转自:BBS 水木清华站 -- 文章阅读 [讨论区: Python] 原文地址
发信人: ann77 (ann), 信区: Python
标 题: 原创:总结Python 中的类和对象
发信站: BBS 水木清华站 (Sun Nov 9 15:11:26 2003)
花了一下午,终于写完了。
其中有很多我自己的看法,有错误或者不准确之处,
欢迎和大家讨论。
本文中 new style class 部分参考了 <<Python In Nut Shell>>
正文如下:
除了内置的 integer , float 等简单类型之外,一切都是 object 。
例如: module, function, package, list, tuple, dict,
注: Python 2.2 以后的版本中 list, tuple, dict 才可以叫做 object ,因为 new sty
le class 。
什么是 name space :
name space 是 name 和 object 之间的映射关系。
每一个 name 唯一的和一个 object 绑定。
一个 object 可以有多个 name 。
如果没有 name 和 object 绑定,那么 object 就会消失了。
name space 是一个动态的数据结构, dictionary 。
objname = object 会创建一个 name 。
什么 aliase :
如果两个 name 指向同一个 object ,那么这两个 name 互为 aliase 。
什么是 name :
name 是一个字符串,指向一个 object 。
什么是 object :
object 是一个独立的 name space 。 object 的 name space 用 dictionary 表示。
obj.__dict__ 表示一个 object 的 name space 。
其中
obj.__dict__.keys() 表示所有 name 的 list ,
obj.__dict__[name] 表示 name 所指的 object 。
name 分为两种,一种是 unqualified name ,一种是 qualified name 。
带有 attribute 的 name 就是 qualified name , 如 obj.attr 。
其中前面的部分是 object name ,后面部分是 object 的 attribute 。
不带有 attribute 的 name 就是 qualified name , 如 obj 。
什么是 scope :
是所有可见的 unqualified name 的组成的 name space 。
他是一个静态定义,动态使用的概念。不同运行时刻,有不同的 unqualified name
是可见的。
什么是 module :
module 是一个独立的 name space 。其中包含很多定义好的 name 和 object 。
这些 object 通常是 class object , function object 。
什么是 package :
module 是一个独立的 name space 。其中包含很多定义好的 name 和 object 。
这些 object 通常是 module object 。
什么是 function :
function 是一个用 def 语句创建的可调用对象。
什么是 nest function:
nest function 指在 function 内部定义的 function 对象。
outer funciton 是指定义 function 的 function 。
inter function 是指被定义的 function 。
outer function 和 inner function 没有本质的区别,是平等的关系,
outer function 的 local name space 在 inner function 中是不可见的。
inner function 是 outer function 内部的创建的一个 object ,
指向 inner function 的 name 存在于 outer function 的 local name space 。
outer function 可以通过返回值等机制,把 inner function 暴露给调用者。
什么是 class object:
class 是一个object ,也叫做 class object 。
用于生成 object 。
什么是 object instance :
由 class object 生成的 object 就是这个 class object 的 class instance 。
class object 和 class instance 的区别和联系:
他们都是 objecct ,从所有 object 共有的特性来说,他们是一样的。
class instance 是由 class object 创建的。如果clsInstance 是 clsObject 的一
个
class instance ,那么 clsInstance.__class__ 和 clsObject 是同一个 object 。
在搜索一个 clsInstance 的 attribute 的时候,若在 clsInstance 的 name space
中找不到,
就会搜索 clsInstance.__class__ 的 name space 。
什么是 attribute :
attribute 是 qualified name 中的 ``.'' 后面的 name 。
attribute 是按照以下规则搜索而得到的第一个 name 。
1. 搜索 object 的 name space
2. 如果 object 是一个 class instance ,搜索 object 所属的 class object 的
name space 。
3. 如果 object 是一个 class object ,深度优先搜索 object 所有祖先的 name s
pace 。
4. 如果 object 有 __getattr__ 函数,调用这个函数,使用返回结果。
按照下列伪代码描述的算法
def search_name(obj,name):
#1. 搜索 object 的 name space
if name in obj.__dict__:
return obj.__dict__[name]
else:
try:
# 2. 如果 object 是一个 class instance ,
# 搜索 object 所属的 class object 的 name space 。
return search_class(obj.__class__,name)
except AttributeError:
if obj.has_attr(__getattr__):
#4.如果 object 有 __getattr__ 函数,调用这个函数,使用返回
结果
return obj.__getattr__(name)
else:
raise AttributeException, "%s not found"%name
def search_class(clsobj)
# 3.如果 object 是一个 class object ,深度优先搜索
# object 所有祖先的 name space 。
if len(clsobj.__bases) == 0:
if clsobj.has_attr(__getattr__):
return clsobj.__getattr__(self
raise AttributeError, "%s not found"%name
for base in clsobj.__bases__:
return search_name(base,name)
什么是 property :
class object 和 class instance 中的纪录数据的 attribute 。
什么是 methord
class object 或者 class instance 中的 function attribute 。
methord 分为 bound methord 和 unbound methord 。
在搜索一个 object 的 attribute 的时候,如果 attribute 是一个 function object ,
那么就要有特殊的处理,
把这个 function object 变成为 bound methord 或者 unbound methord 。
bound methord 和 unbound methord 的区别,
bound methord 和一个 class instance 绑定。
unbound methord 不和一个 class instance 绑定。
bound methord 会自动把 class instance 作为第一个参数,所以调用的时候要少传
递一个参数。
unbound methord 则不会,调用的时候,不能少传递一个参数。
例如:
class A:
def h():
pass
a=A()
那么:
a.h 是 bound methord 。
A.h 是 unbound methord 。
我们大多数情况使用 bound methord ,较少情况使用 unbound methord 。 使用 unbou
nd methord 的典型情况就是,
调用父类的 unbound methord 。
bound methord 和 unbound methord 的相同点:
他们的第一个参数都是一个 class instance ,这个 class instance 和 methord 同
属于
同一个 class object 。
他们都是 class object 的 name space 中的 name ,
一般不是 class instance 的 name space 中的 name ,除非明显的在
class instance 的 name space 中创建一个同名的 name 。
bound methord ,unbound methord 和普通function object 的比较。
这里所说的普通 function 是指在 class 语句控制范围之外定义的 function obje
ct 。
相同点:
他们都是 function object ,本质上一样的。 methord 相对于普通 function
来说,
在处理 class instance 和 class object 的时候,并没有什么不一样的特权。
不同点:
如果 methord 所属的 class object 是 AObj ,那么
methord 的第一个参数必须是 AObj 的 class instance
或者 AObj 的子孙的 class instance 。
普通的 function object 没有这个限制。
什么是 new style class :
new style class 是 Python 2.2 新提出的功能。 因此原来的 class object ,叫做
classic class 。
如果一个 class object 的祖先是 ``object'' , 那么这个 class object 就是 ne
w style class 。
``object'' 是一个 class object 的名字。
也就是说,如果一个 class object 直接继承或者间接继承 ``object'' ,那么就是
new style class 。
直接继承的 new style class 例如 : class newClass(object)
间接继承的例子如 : class newClass(dict) 。
其它的如 list, dict, tuple, file, 都是 ``object'' 的子类。
new style class 具有classic class 的所有特性。
new style class 和 classic class 的不同之处:
1. 增加了两个新的 methord 机制。
a. static methord
例子:
class AClass(object):
def astatic( ): print 'a static method'
astatic = staticmethod(astatic)
anInstance = AClass( )
AClass.astatic( ) # prints: a static method
anInstance.astatic( ) # prints: a static method
说明:
static methord 和普通 function 没有区别。
b. class methord
例子:
class ABase(object):
def aclassmet(cls): print 'a class method for', cls._ _name_ _
aclassmet = classmethod(aclassmet)
class ADeriv(ABase): pass
bInstance = ABase( )
dInstance = ADeriv( )
ABase.aclassmet( ) # prints: a class method for ABase
bInstance.aclassmet( ) # prints: a class method for ABase
ADeriv.aclassmet( ) # prints: a class method for ADeriv
dInstance.aclassmet( ) # prints: a class method for ADeriv
说明:
class methord 和 bound methord 类似。 bound methord 是自动把
class instance 作为第一个参数。 class methord 是自动把 class object 作
为第一个
参数。
无论是 clsInstance.class_methord 的形式,还是 clsObject.class_methord
的形式。
效果一样。
2. 增加了新的特殊函数。
a. __new__
__init__ 是初始化函数,不是构造函数。在调用 __init__ 函数的时候,对象已
经创建好了。
新增的 __new__ 函数,是真正的构造函数。
clsInstance = clsObject(...)
等价于
clsInstance = clsObject.__new__(clsObject,...)
注意到, __new__ 的第一个参数不是一个 class instance ,而是一个 class
object 。他默认就是一个
一个 class methord , 不用使用
__new__ = staticmethod(__new__)
来特别声明他是一个 class methord 。
object.__new__ 的默认动作时创建一个对象,然后调用 __init__ ,返回一个
class instance 。
重载 __new__ 的时候,会常常调用父类(如 object, list, tuple, dict, file
等)的 __new__ 函数,
然后,再作其他你要干的事情。
一个典型的例子就是返回一个已经存在的对象,实现 Singleton 的 design pat
tern 。
例子:
class Singleton(object):
_singletons = { }
def _ _new_ _(cls, *args, **kwds):
if not cls._singletons.has_key(cls):
cls._singletons[cls] = object._ _new_ _(cls)
return cls._singletons[cls]
这个例子中, Singleton 的每一个子孙类,只能有一个对象,也就是说,
如果 clsobj1, clsobj2, ..., clsobjn , 都是Singleton 的子孙。
那么 clsobj1 的所有 class instance 都是同一个 object ,
clsobj2 的所有 class instance 都是同一个 object , ... ,
clsobjn 的所有 class instance 都是同一个 object 。
不同子孙, 如 clsobj1, 和 clsobj2 的 class instance 不是同一个 object
。
b. __getattribute__
__getattr__ 这个特殊函数在 attribute 的搜索算法中,是最后一关。
而 __getattribute__ 是第一关,也就是他会拦截所有 attribute 的引用请求。
3. new style class 的 class instance 的特性。
a. property
attrib = property(fget=None, fset=None, fdel=None, doc=None)
可以为一个 new style class instance 增加一个 attribute ,叫做 attr ,
fget 是读 property 的时候,调用的 bound methord 。不接收参数。 None 表示 p
roperty 不可读。
fset 是写 property 的时候,调用的 bound methord 。接收一个参数,表示写入什
么。 None 表示 property 不可写。
fset 是删除 property 的时候,也就是调用 del obj.attr 语句的时候,
调用的 bound methord 。不接收参数。None 表示 property 不可删。
doc 表示 doc string 。
例子:
class Circle (object):
def _ _init_ _(self,radius):
self.radius = radius
def getArea(self):
return self.radius * self.radius * math.pi
def setArea(self,value):
self.radius = math.sqrt((value/math.pi))
area = property(getArea,setArea,doc='area of the circle ')
这个例子中, 如果 c 是一个 Circle 的一个 class intance 。
那么
print c.area # 调用 c.getArea
c.area = 100 # 调用 c.setArea(100)
print c.area.__doc__ # 打印 area of the circle 。
b. __slots__
__slots__ 是一个 sequence (一般是 tuple ),其中每一个元素是一个 string
。
这是一个提高效率的方法。因为 object 的 name space 是一个 dictionary ,
是动态的申请和释放内存的,这样效率很低。
有了 __slots__ 之后,object 的 name space 就是一个固定内存的大小,
同时, object 也不有 __dict__ 来表示 name space 了。
object 新建的 attribute 的名字必须是 __slots__ 中的名字。
定义 __slots__ 不等于定义 attributes , 还要创建之后才能用。
例子:
>>> class OptimizedRectangle(object):
... __slots__= 'width','heigth'
...
>>> r = OptimizedRectangle()
>>> r.width # 定义 __slots__ 不等于定义 attribute
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: width
>>> r.width,r.heigth=1,2
>>> print r.width,r.heigth
1 2
>>> r.high = 100
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'OptimizedRectangle' object has no attribute 'high'
这个例子中,创建 high 是不允许的。
__slots__ 效率高的机制,是以牺牲动态创建 attribute 的特性为代价的。
只有在内存中同时大量存在这样的 class instance 的时候,
大量是指几百万这样的数量级,而不是几千个这样的数量级,而且每一个 instan
ce 要节省
几十个字节,这样提高效率效果明显。 否则就没有必要了。
c. new style class 中的 Per-instance methords
一个 class object 的一个 class instance
可以 绑定一个 attribute 到任意一个 function object 。
例如:
>>> class AClass:
... pass
...
>>> a = AClass()
>>> fakeGetItem=lambda idx:idx
>>> a.__getitem__=fakeGetItem
>>> a[100]
100
这个例子中, a 可以把特殊函数 __getitem__ ,绑定到任意一个函数上,
但是这时,a.__getitem__ 不是一个 bound methord ,而是一个普通函数,也就是说,他
不能自动
把 class instance 作为第一个参数。
new style class 和 classic class 在处理因为操作符重载而调用特殊函数的时候,
处理有所不同。
new style class 是先在class instance 所属的 class object 的 name space 中搜
索特殊函数,而不会在
class instance 的 name space 搜索 。
classic class 还是按照原来的搜索算法,没有什么特殊的处理,就像上一个例子。
例如:
>>> class NewStyleClass(object):
... pass
...
>>> a = NewStyleClass()
>>> a.__getitem__=fakeGetItem
>>> a[100]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unindexable object
>>> a.__getitem__(100)
100
可以看到,操作符重载的时候,new style class 仅仅会在 class object 中搜索特
殊函数。
但是,如果不是因为操作符重载,而直接调用 __getitem__ ,还是和其他 attribut
e 的搜索算法一致的。
d. new style class 的多重继承的限制
list, dict, file 等对象称为内置对象。他们继承与所有 new style class 的基类
``object'',
在多重继承中,最多只能同时继承一个内置对象和一个 ``object'' 。
e. new style class 和 classic class 的 methord 的搜索顺序不同。
classic 按照 attribute 的搜索算法,搜索一个 methord 。例如:
class D:
pass
class B(D):
pass
class C(D):
pass
class A(B,C):
pass
按照搜索算法,classic class 的搜索顺序是 A, B, D, C, D 。
class D(object):
pass
class B(D):
pass
class C(D):
pass
class A(B,C):
pass
new style class 的搜索顺序是 A,B,C,D,object 。也就是广度优先搜索。
f. new style class 和 classic class 调用父类的方法不同。
classic class 中调用父类的方法,一般使用 unbound methord 。例如:
class A:
def met(self):
print 'A.met'
class B(A):
def met(self):
print 'B.met'
A.met(self)
class C(A):
def met(self):
print 'C.met'
A.met(self)
class D(B,C):
def met(self):
print 'D.met'
B.met(self)
x=D()
x.met()
在这个例子中,B.met(self), C.met(self) 就是 unbound methord 的用法。
但是问题是,这样 A.met 就会被调用两次。
运行结果是 :
D.met
B.met
A.met
C.met
A.met
new style class 解决的办法就是,使用 super 。
super(clsobj,obj) 会返回一个特殊的 clsobj 的父类。
当我们用 super(clsobj,obj).somemethord(...) 搜索 somemethord 的时候,
搜索顺序和上面讲的搜索顺序是一样的。
例如:
class A(object):
def met(self):
print 'A.met'
class B(A):
def met(self):
print 'B.met'
super(B,self).met( )
class C(A):
def met(self):
print 'C.met'
super(C,self).met( )
class D(B,C):
def met(self):
print 'D.met'
super(D,self).met( )
x=D()
x.met()
运行结果是:
D.met
B.met
C.met
A.met
在这个例子中, super(D,self).met() 的搜索 met 的顺序是 B,C,A 。
这样,就没有这个问题了。建议以后的 new style class 都用这种办法调用
父类的methord 。
--
※ 来源:·BBS 水木清华站 http://smth.org·[FROM: 210.12.42.5]