class object 和 instance object 中的属性字典
由于前一段时间一直用c#做项目,以前用python时积累的很多认识都忘了。
现在一边回忆,一边深入。
(一)-------------------------------------
下面是一段试验代码:
>>> class a:
... def b(self):
... self.c='dfd'
...
>>> d=a()
>>> dir(d)
['__doc__', '__module__', 'b']
>>> d.b()
>>> dir(a)
['__doc__', '__module__', 'b']
>>> dir(d) #*******************
['__doc__', '__module__', 'b','c']
>>> d.__dict__ #*******************
{'c': 'dfd'}
>>> a.__dict__
{'__module__': '__main__', 'b': , '__doc__': None}
>>>
由此可见:
class object和instance object的__dict__中保存的都是local symbol table,而dir(object)则是上溯式的
Python Library Reference中2.1节Built-in Functions对此有详细描述。
对对象的访问, 除了要像dir这样回溯,还要调用__getattr__
(http://blog.donews.com/limodou/archive/2004/10/16/134808.aspx):
当访问一个对象的会根据不同的情况作不同的处理,是比较复杂的。一般象instanceObj.b这样的形式,python可能会先查找instanceObj.__dict__中是否存在,如果不存在会在类的__dict__中去查找,再没找到可能会去按这种方法去父类中进行查找。实在是找不到,会调用__getattr__,如果不存在则返回一个异常。那么__getattr__只有当找不到某个属性的时候才会被调用。因此,你可能会想实现一种机制,当访问一个不存的属性时,自动提供一个缺省值
(二)------------------------------------------
接下来的部分说说函数对象Function Object和方法对象Method Object的属性字典
接着上面的输入:
>>> dir(d.b)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'im_class', 'im_func', 'im_self']
>>> def dd():
... pass
...
>>> dir(dd)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__', '__module__',
'__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults',
'func_dict', 'func_doc', 'func_globals', 'func_name']
>>> dir(d.b.im_func)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__', '__module__',
'__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults',
'func_dict', 'func_doc', 'func_globals', 'func_name']
>>>
函数对象有个'__module__'属性,方法对象加入了'im_class', 'im_func', 'im_self',其中im_func才是真正的可执行的对象。
The implementation adds two special read-only attributes to class instance methods: m.im_self is the object on which the method operates, and m.im_func is the function implementing the method. Calling m(arg-1, arg-2, ..., arg-n) is completely equivalent to calling m.im_func(m.im_self, arg-1, arg-2, ..., arg-n).
Class instance methods are either bound or unbound, referring to whether the method was accessed through an instance or a class, respectively. When a method is unbound, its im_self attribute will be None and if called, an explicit self object must be passed as the first argument. In this case, self must be an instance of the unbound method's class (or a subclass of that class), otherwise a TypeError is raised.
Mix-in技术,它实现了基类的动态增加。这样 我们就可以在运行时,根据选择可以动态地增加基类,从而实现不同的目的。现在 还有一个问题,就是,在基类与派生类中都有同名的函数,要如何处理呢?
在Python中,如果派生类中有与基类同名的函数,那么调用函数时,会调用派生类的函数,而不是基类的函数,可以测试一下:
>>> class foobase:
def a(self):
print "hello"
>>> class foo(foobase):
def a(self):
print "foo"
>>> c=foo()
>>> c.a()
foo
可以看出,执行的是foo类的函数。这样在使用Mix-in技术时,如果原来
的类中存在与Mix类中同名的函数,那么Mix类中的函数不会运行,如果
想对其进行替换怎么办呢?方法就是使用getattr()和setattr()函数。当然
还是最简单的,更复杂更通用的以后再讨论。
定义两个类:
>>> class foobase:
def a(self):
print "hello"
>>> class foo:
def a(self):
print "foo"
>>> f=getattr(foobase, "a")
>>> setattr(foo, "a", f.im_func) #f.im_func会得到真正的函数对象
>>> c=foo()
>>> c.a()