理解built-in objects
Python中一切皆对象:字符是对象,列表是对象,内建类型也是对象;用户定义的类型是对象,object是对象,type也是对象。
|
|
| 编号 | 对象 | type<*> | class | bases | isinstance(*,object) | isinstance(*,type) |
|---|---|---|---|---|---|---|
| [1] | object | 〈type ‘type’〉 | 〈type ‘type’〉 | () | 真 | 真 |
| [2] | type | 〈type ‘type’〉 | 〈type ‘type’〉 | 〈type ‘type’〉 | 真 | 真 |
| [3] | a | 〈type ‘instance’〉 | main.A | () | 真 | 假 |
| [4] | b | 〈class ‘main.B’> | 〈class ‘main.B’> | 〈type ‘type’〉 | 真 | 假 |
| [5] | c | 〈class ‘main.C’> | 〈class ‘main.C’> | 〈type ‘type’〉 | 真 | 真 |
| [6] | d | 〈class ‘main.D’> | 〈class ‘main.D’> | 〈type ‘type’〉 | 真 | 假 |
新式类能够基于内建类型构建新的用户类型,支持property和描述符特性等。作为新式类的祖先,Object类中还定义了一些特殊方法,如:new(), init(), delattr(), getattribute(),setattr(), hash(), _repr(),str__()等
类的内部机制
init()不是构造方法
init()方法是在类的对象创建好之后进行变量的初始化。new()方法才会真正创建实例,是类的构造方法
- object.new(els [,args…]):其中els代表类, args 为参数列表
- object.init(self [,args…])::其中self代表实例对象, args为参数列表
- new()方法是静态方法,而init()为实例方法。
- new()方法返回类的对象,当返回类的对象时将会自动调用方法进行初始化,如果没有对象返回,则init()方法不会被调用。方法不需要显式返回,默认为None,否则会在运行时拋出TypeError。
- 当需要控制实例创建的时候可使用new()方法,而控制实例初始化的时候使用init()方法。
- 一般情况下不需要覆盖new()方法,但当子类继承自不可变类型,如str、int、 imicode或者tuple的时候,往往需要覆盖该方法。
- 当需要覆盖new()和init()方法的时候这两个方法的参数必须保持一致,如果不一致将导致异常
特殊情况下需要覆盖new()方法
(1)当类继承(如str、int、unicode、tuple或者forzenset等)不可变类型且默认的new()方法不能满足需求的时候
|
|
(2)用来实现工厂模式或者单例模式或者进行元类编程
|
|
理解名字查找机制
|
|
Python中变量的作用域
- 局部作用域:一般来说函数的每次调用都会创建一个新的本地作用域,拥有新的命名 空间。默认情况下函数内部任意的赋值操作(包括=语句、import语句、def语句、参数传递等)所定义的变量名,如果没用global语句,则都为局部变量。
- 全局作用域:定义在Python模块文件中的变量名拥有全局作用域,全局仅限单个文件,其他文件中想使用这些变量名必须先导人文件对应的模块
- 嵌套作用域:需要注意的是global语句仅针对全局变量,在嵌套作用域的情况下,如果想在嵌套的函数内修改外层函数中定义的变量,即使使用global进行申明也不能达到目的,其结果最终是在嵌套的函数所在的命名空间中创建了一个新的变量。
- 内置作用域:它是通过一个标准库中名builtin的模块来实现的123456789101112def ex2 ():var = 'a'def inner ():global varvar = 'b'print 'inside inner, var is ', varinner ()print 'inside outer function, var is ', var# 上述程序的输出如下:inside inner, var is binside outer function, var is a
Python的名字査找机制:
- 在最内层的范围内査找,一般而言,就是函数内部,即在locals()里面査找
- 在模块内査找,即在global()里面查找
- 在外层査找,即在内置模块中査找,也就是在builtin中査找
global声明其为全局变量
|
|
Python3引入的nonlocal关键字解决这方面的问题
|
|
self参数
Python语言本身的动态性决定了使用self能够带来一定便利。由于self在函数调用中是隐式传递的,因此当直接调用全局函数len()时传入的是point对象,而当在类中调用该方法时,传入的是类所对应的对象,使用self可以在调用的时候决定应该传入哪一个对象。
|
|
Python属于一级对象语言,如果m是类A的一个方法,有好几种方式都可以引用该方法
|
|
理解MRO与多继承
|
|
古典类中,MRO搜索采用简单的自左至右的深度优先方法,即按照多继承申明的顺序形成继承树结构,自顶向下采用深度优先的搜索顺序,当找到所需要的属性或者方法的时候就停止搜索。当调用d.getvalue()的时候,其搜索顺序为D->B,所以调用的是B类中对应的方法。而d.show()的搜索顺序为D->B->A,因此最后调用的是A类中对应的方法。
新式类采用C3 MRO搜索方法
- (1)C1,C2…CN表示类C1到CN的序列,其中序列头部元素(head)=Cl,序列尾部 (tail)定义为=C2..CN;
- (2)C继承的基类自左向右分别表示为Bl,B2…BN;
- (3)L[C]表示C的线性继承关系,其中L[object]=object
算法具体过程如下L[C(B1 …BN)1 = C + merge(L[B1]…L[BN], B1 …BN)
merge方法的计算规则如下:在L[B1]…L[BN],B1…BN中,取L[B1]的head,如果该元素不在L[B2]…L[BN], B1 …BN的尾部序列中,则添加该元素到C的线性继承序列中,同时将该元素从所有列表中删除该元素,否则取L[B2]的head。继续相同的判断,直到整个列表为空或者没有办法找到任何符合要求的头元素(此时 将引发一个异常)12345678910L(0)=0;L(A)=AO;L(B)=B+merge(L(A))=B+merge(AO)=B+A+merge(0,0)=B,A,0L(C)=C+merge(L(A))=C+merge(AO)=C+A+merge(0,0)=C,A,0L(D)=D+merge(L[B], L[C], BC)=D+merge(BAO,CAO,BC)=D+B+merge(AO,CAO,C) # (下一个计算取AO的头A,但A包含在CAO的尾部,因此不满足条件.跳到下一个元素CAO继续计算)=D+B+C+merge(AO,AO)=D+B+C+A+O=DBCAO
当D的实例d调用getvalue()和show()方法时按照D>B>C>A>O的顺序进行搜索,在第一个找该方法的位置停止搜素并调用该类对应的方法,因此getvalue() 会在B的类中找到对应的方法,而show会在C()类中找到对应的方法。
MRO的搜索顺序我们也可以在新式类中通过查看mro属性得到证实