##基础知识:## Python Class 对象或类型经过内置成员 dict 来存储成员信息。
还能够经过重载 getattr 和 setattr 来拦截对成员的访问,须要注意的是 getattr 只有在访问不存在的成员时才会被调用。
若是类型继承自 object,咱们可使用 getattribute 来拦截全部(包括不存在的成员)的获取操做html
dict 返回类的属性字典, 会调用__getattrbute__
若是有一个类A;
a = A()
a.dict 和 A.__dict__会有所不一样, a__dict__中没有方法,而 A.dict 有方法。
因此可见 类方法是类的属性被全部对像共享。python
python的对象能够动态加属性,例如 a.ss=3, 这时a.__dict__就会有ss的key, 而A.__dict__ 不会有这个key,从而引伸出类属性和对象属性(这里不作过多解释)。
这里要问一个问题了:
对象的__dict__中没有方法, 那对象是怎么调用方法的呢?
在这里就引伸出Descriptor个东西:git
class RevealAccess(object): def __init__(self, initval=None, name='var'): self.val = initval self.name = name def __get__(self, obj, objtype): print 'Retrieving', self.name return self.val def __set__(self, obj, val): print 'Updating' , self.name self.val = val
在类中定义__get__和__set__方法的,成为descriptor
它是用来作什么的呢。。。。。
再写一个类:github
class MyClass(object): x = RevealAccess(10, 'var "x"') def __init__(self): self.y = 5 def test(self): print 'hello world!' test = RevealAccess(test, 'var "x"') if __name__ == "__main__": m = MyClass() print m.y # 输出 # 5 print m.x # 输出 # Retrieving var "x" # 10 print m.test # 输出 # Retrieving var "x" # <function test at 0x02CBE870>
哈哈, 结果看出来了吧;当对像调用x(属性),test(方法)的时候都调用了__get__方法。 这个RevealAccess的对象就是一个descriptor。访问属性m.x就是调用__get__方法,设置属性值就是调用__set__方法。还能够有一个__delete__方法,在del m.x时被调用。函数
下一个问题:
print MyClass.dict["test"] # 输出: <function test at 0x02C9E8F0> print m.test # 输出: <bound method MyClass.test of <main.MyClass object at 0x02C9DB70>> 这是什么状况, 这俩明显不是一个东西, 什么状况。
这说明test方法在类中仅仅是一个function, 他跟对象仍是不要紧。 print MyClass.dict["test"].get(m, Myclass) # 输出: <bound method MyClass.test of <main.MyClass object at 0x02CDDB90>> 这回是一个东西了,其实,类的成员函数就是一个descriptor,在实例化对象m的时候,作了m.test = MyClass.dict["test"].get(m, Myclass) 这么一件事,这回通了。哈哈。post
有了这个基础: 理解一下staticmethod和classmethod这两个decorator,staticmethod就是像RevealAccess同样忽略第一个参数,直接返回参数。classmethod就是手动赛一个对像进去: def get(self, obj, klass=None): if klass is None: klass = type(obj) def newfunc(*args): return self.f(klass, *args) return newfunccode
dict 妙用
<!-- lang: python --> class Person: def init(self,_obj): self.name = _obj['name'] self.age = _obj['age'] self.energy = _obj['energy'] .............. class Person: def init(self, _obj): self.dict.update(_obj) 这样就减小了不少代码量
delattr: 当使用 p = Person(); del p.name 会调用htm
主要参考http://hbprotoss.github.io/posts/python-descriptor.html http://blog.jobbole.com/21351/对象