实用函数 开发调试之必备
id() 返回对象的唯一身份标识
type() 返回对象的类型
dir() 显示对象的属性(没有参数显示全局变量)
环境安装 PIP 全称是Python Package Index,Python的包管理器,可以理解为ubuntu下的apt-get
1 sudo apt-get install python-pip
安装python的mongodb扩展
virtualenv 一个创建隔离的Python环境的工具
使用apt-get
1 sudo apt-get install python-virtualenv
或者使用pip
1 sudo pip install virtualenv
建立虚拟环境
启动虚拟环境
1 2 cd MyEnv source ./bin/activate
在虚拟环境中安装python包
退出虚拟环境
标准类型的分类
数据类型
存储模型
更新模型
访问模型
数字
标量
不可更改
直接访问
字符串
标量
不可更改
顺序访问
列表
容器
可更改
顺序访问
元组
容器
不可更改
顺序访问
字典
容器
可更改
映射访问
这里标准类型被分为三类,这里我们需要重点记一下更新模型 (不管是在接下来的例子还是以后的编程中,还要打交道)
更新模型中的可更改 和不可更改 分别代表着对象创建成功后,它的值可不可以进行更新。
数字和字符串之所以是不可更改,是因为事实上是创建一个新的对象取代一个旧的对象。
1 2 3 4 5 6 7 8 9 10 11 12 >>> x = 'abc' >>> id(x)140024151271304 >>> x = 'def' >>> id(x)140024115106120 >>> y = 1 >>> id(y)34961336 >>> y += 1 >>> id(y)34961312
再来看一下列表:
1 2 3 4 5 6 >>> aList = [1 , 2 , 3 , 4 ]>>> id(aList)140024094989344 >>> aList[1 ] = 5 >>> id(aList)140024094989344
序列 序列包括字符串、列表和元组。它们的成员是有序排列的,并且有着相同的访问模式——可以通过下标访问到它的一个(下标偏移量)或多个(切片)。
当然,它们有着通用的操作符:
成员关系操作符(in, not in)
连接操作符(+)
重复操作符(*)
切片操作符([], [:], [::])
还有相同的BIF(enumerate、len、max、min、reversed、sorted、sum、zip等)
当然,除了这些公共的BIF,他们还有着自己私有的BIF,可以通过dir()来查看,如:
1 2 >>> dir(list)['__add__' , '__class__' , '__contains__' , '__delattr__' , '__delitem__' , '__delslice__' , '__doc__' , '__eq__' , '__format__' , '__ge__' , '__getattribute__' , '__getitem__' , '__getslice__' , '__gt__' , '__hash__' , '__iadd__' , '__imul__' , '__init__' , '__iter__' , '__le__' , '__len__' , '__lt__' , '__mul__' , '__ne__' , '__new__' , '__reduce__' , '__reduce_ex__' , '__repr__' , '__reversed__' , '__rmul__' , '__setattr__' , '__setitem__' , '__setslice__' , '__sizeof__' , '__str__' , '__subclasshook__' , 'append' , 'count' , 'extend' , 'index' , 'insert' , 'pop' , 'remove' , 'reverse' , 'sort' ]
具体的使用可以查看手册或API,这里就不一一列举了。
字符串不变性 对于字符串为什么会是不可更改 ,一个切片的例子可能比id()讲的更加的清晰明白:
1 2 3 4 5 6 7 8 >>> s = 'abc' >>> s[2 ] = 'd' Traceback (most recent call last): File "<stdin>" , line 1 , in <module> TypeError: 'str' object does not support item assignment >>> s = s[0 ]+'d' +s[2 ]>>> s'adc'
从本例中可以看到如果想修改字符串的值,就要用一点点hacker,否则就会报出TypeError的异常。
单元素元组的初始化 元组的分界符是圆括号,而圆括号却不仅仅属于元组(也用于分组)。所以单元素的初始化看起来有那么一点点hacker(需要第一个元素后添加一个逗号)。
1 2 3 4 >>> type(('xyz' ))<type 'str' > >>> type(('xyz' ,))<type 'tuple' >
元组的”可变性” 1 2 3 4 5 6 >>> t = (['xyz' , 123 ], 23 , -103 ,4 )>>> t(['xyz' , 123 ], 23 , -103 , 4 ) >>> t[0 ][1 ] = 'abc' >>> t(['xyz' , 'abc' ], 23 , -103 , 4 )
按前面的分类来讲,元组属于不可变类型,这里为何又可以改变了呢?——其实这里改变不是元组,而是列表。
深拷贝与浅拷贝 映射类型(字典) 创建一个“默认”字典 1 2 3 4 5 6 >>> ddict = {}.fromkeys(('x' , 'y' ), -1 )>>> ddict{'y' : -1 , 'x' : -1 } >>> edict = {}.fromkeys(('foo' , 'bar' ))>>> edict{'foo' : None , 'bar' : None }
键必须是可哈希的 这里又要说到更新模型 了:所有不可变的类型都是可哈希的(元组中不能有可变类型对象——参见”元组的可变性”)
集合 类型
可变集合(set)
不可变集合(frozenset)
异常 try-except-else-finally 代码格式一览(大而全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 try : try_suite except Exception1: suite_for_Exception1 except (Exception2, Exception3, Exception4): suite_for_Exception2_3_and_4 except Exception5, Argument5: suite_for_Exception5_plus_argument except (Exception6, Exception7), Argument67: suite_for_Exception6_and_7_plus_argument except : suite_for_all_other_exceptions else : no_exceptions_detected_suite finally : always_execute_suite
异常的继承结构 \- BaseException
|- KeyboardInterrupt
|- SystemExit
|- Exception
|- (all other current built-in exceptions)
上下文管理 其他
触发异常(raise)
断言(assert)
异常与sys模块(sys.exc_info() )
sys.exc_info()返回一个元组,包含以下三类信息:
exc_type:异常类
exc_value: 异常类的实例
exc_traceback: 跟踪记录对象
1 2 3 4 5 6 7 8 >>> try :... float('abc' )... except :... import sys... exc_tuple = sys.exc_info()... >>> print exc_tuple(<type 'exceptions.ValueError' >, ValueError('could not convert string to float: abc' ,), <traceback object at 0x7f59e9c08200 >)
函数 参数组 1 func(*tuple_grp_nonkw_args, **dict_grp_kw_args)
其中tuple_grp_nonkw_args是以元组形式体现的非关键字参数组,dict_grp_kw_args是装有关键字参数的字典
Python所允许的函数调用的完整语法:
1 func(position_args, keyword_args, *tuple_grp_nonkw_args, **dict_grp_kw_args)
关键字参数 关键字参数的一个特性是:调用都可通过函数调用中的参数名字来区分参数,允许参数缺失及不按顺序
1 2 3 >>> def net_conn (host, port) :... pass >>> net_conn(port='8080' , host='localhost' )
###可变长度的参数
非关键字可变长参数(元组) 1 2 3 4 5 6 7 8 9 10 11 >>> def tupleVarArgs (arg1, arg2='defaultB' , *theRest) :... print 'formal arg1 : ' , arg1... print 'formal arg2 : ' , arg2... for eachXtrArg in theRest:... print 'another arg:' , eachXtrArg... >>> tupleVarArgs('abc' , 123 , 'xyz' , 456.789 )formal arg1 : abc formal arg2 : 123 another arg: xyz another arg: 456.789
关键字变量参数(字典)
为了区分关键字参数和非关键字非正式参数,使用了双星号
1 2 3 4 5 6 7 8 9 10 11 12 >>> def dictVarArgs (arg1, arg2='defaultB' , **theRest) :... print 'formal arg1:' , arg1... print 'formal arg2:' , arg2... for eachXtrArg in theRest.keys():... print 'Xtra arg %s : %s' % (eachXtrArg, str(theRest[eachXtrArg]))... >>> dictVarArgs('one' , d = 10 , e = 'zoo' , men = ('freud' , 'gaudi' ))formal arg1: one formal arg2: defaultB Xtra arg men : ('freud' , 'gaudi' ) Xtra arg e : zoo Xtra arg d : 10
调用带有可变长参数对象函数
1 2 3 4 5 6 7 8 9 >>> def newfoo (arg1, arg2, *nkw, **kw) :... print 'arg1 is : ' , arg1... print 'arg2 is : ' , arg2... for eachNKW in nkw:... print ' non-keyword arg : ' , eachNKW... for eachKW in kw.keys():... print ' keyword arg %s : %s' %(eachKW, kw[eachKW])... >>>
1 2 3 4 5 6 7 >>> newfoo(2 , 4 , *(6 ,8 ), **{'foo' :10 , 'bar' :12 })arg1 is : 2 arg2 is : 4 non-keyword arg : 6 non-keyword arg : 8 keyword arg foo : 10 keyword arg bar : 12
1 2 3 4 5 6 7 8 9 10 11 12 >>> aTuple = (6 ,7 ,8 )>>> aDict = {'z' :9 }>>> newfoo(1 , 2 , 3 , x=4 , y=5 , *aTuple, **aDict)arg1 is : 1 arg2 is : 2 non-keyword arg : 3 non-keyword arg : 6 non-keyword arg : 7 non-keyword arg : 8 keyword arg y : 5 keyword arg x : 4 keyword arg z : 9
列表解析与生成器表达式
1 sum([x ** 2 for x in range(6 )])
生成器表达式
是列表解析的扩展
延迟计算
生成器允许你返回一个值,然后“暂停”代码的执行,稍后恢复
1 sum( x ** 2 for x in range(6 ))
面向对象编程 类属性VS实例属性 定义类和属性 1 2 3 4 >>> class C (object) :... version = 1.2 ... x = {2003 : 'poe2' } ...
改变不可变对象
1 2 3 4 5 >>> c = C()>>> C.version1.2 >>> c.version1.2
1 2 3 4 5 >>> C.version += 0.1 >>> c.version1.3 >>> C.version1.3
1 2 3 4 5 >>> c.version += 0.1 >>> c.version1.4 >>> C.version1.3
改变可变对象
1 2 3 >>> foo = C()>>> foo.x{2003 : 'poe2' }
1 2 3 4 5 >>> foo.x[2004 ] = 'valid path' >>> foo.x{2003 : 'poe2' , 2004 : 'valid path' } >>> C.x{2003 : 'poe2' , 2004 : 'valid path' }
绑定方法VS非绑定方法
self参数代表实例对象本身,当用实例调方法时,由解释器传递给方法
1 2 3 class EmpAddrBookEntry (AddrBookEntry) : def __init__ (self, nm, ph, em) : AddrBookEntry.__init__(self, nm, ph)
多重继承采用MRO算法来决定调用的方法,如下例中调用gc.foo()执行的是P1的foo方法,这时如果我想执行P2的foo方法怎么办呢?这时就需要用典型的非绑定方式去调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class P1 (object) : def foo (self) : print 'called P1-foo()' class P2 (object) : def foo (self) : print 'called P2-foo()' class C1 (P1, P2) : pass class C2 (P1, P2) : def bar (self) : print 'called C2-bar()' class GC (C1, C2) : pass gc = GC() gc.foo() gc.bar() P2.foo(gc)
静态方法和类方法 装饰器
1 2 3 @decomark(deco_args) def foo () : pass
装饰器可以如函数调用一样“堆叠”起来
1 2 3 4 5 6 @g @f def foo () : pass
staticmethod()和classmethod()内建函数
1 2 3 4 5 >>> class TestClassMethod :... def foo (cls) :... print 'test class method' ... ... foo = classmethod(foo)
1 2 3 4 5 6 7 8 9 class TestStaticMethod : @staticmethod def foo () : pass class TestClassMethod : @classmethod def foo (cls) : pass
通常的方法需要一个实例(self)作为第一个参数。而对于类方法而言,需要类而不是实例作为第一个参数,它是由解释器传给方法。类不需要特别的命名,类似self,不过很多人使用cls作为变量名称
私有化
双下划线实现私有性的原理是把属性加上类名形成新的“混淆”结果以防止和祖先类或子孙类中的同名冲突
1 2 3 4 5 6 7 8 9 10 >>> class NumStr (object) :... __num = 10 ... >>> NumStr.__dict__dict_proxy({'__dict__' : <attribute '__dict__' of 'NumStr' objects>, '__weakref__' : <attribute '__weakref__' of 'NumStr' objects>, '__module__' : '__main__' , '_NumStr__num' : 10 , '__doc__' : None }) >>> NumStr()._NumStr__num10 >>> c = NumStr()>>> c._NumStr__num10
__dict__ 与 __slots__ 类属性
字典位于实例的“心脏”。dict属性跟踪所有实例属性。 字典会占据大量内存,如果有一个属性少的类,但有很多实例。为了内存上的考虑,可使用slots代替dict
1 2 3 4 5 6 7 8 9 >>> class SlottedClass (object) :... __slots__ = {'foo' , 'bar' }... >>> c = SlottedClass()>>> c.foo = 42 >>> c.xxx = '133' Traceback (most recent call last): File "<stdin>" , line 1 , in <module> AttributeError: 'SlottedClass' object has no attribute 'xxx'
类的实例
Python给类提供了__call__的特别方法,该方法允许程序员创建可调用的对象实例。(默认__call__()没有实现 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 >>> class C (object) :... pass ... >>> c = C()>>> c<__main__.C object at 0x7f0642abfb10 > >>> callable(c)False >>> c()Traceback (most recent call last): File "<stdin>" , line 1 , in <module> TypeError: 'C' object is not callable >>> >>> class D (object) :... def __call__ (self, *args) :... print "I'm callable! args:\n" , args... >>> d = D()>>> d<__main__.D object at 0x7f0642abfbd0 > >>> callable(d)True >>> d()I'm callable! args: () >>> d(1, 2, 3) I' m callable! args:(1 , 2 , 3 )