python函数和类的一些研究
通过实验梳理 Python 函数与类中的绑定、相等判断、方法查找、可调用性和名称改写。
bound与unbound
通常认为实例方法是bound的,而类方法是unbound的,这种说法也没错,只是对于不同类型变量来说,结果是不同的
class A(object): """test class""" _instance = None
def __private(self): pass
def _protect(self): pass
def fs(self): pass
@staticmethod def sm(): pass
@classmethod def fc(cls): pass测试一下, 结果显示的都是bound method
>>> a = A()>>> a.fs<bound method A.fs of <__main__.A object at 0x101fa3250>>>>> a.fc<bound method type.fc of <class '__main__.A'>>直接从类访问,结果fs这个实例方法显示的是unbound。可以知道bound的意义并不是始终不变的,对于不同的对象来说意义并不一样。
>>> A.fs<unbound method A.fs>>>> A.fc<bound method type.fc of <class '__main__.A'>>python里面类方法和实例方法可以等价变换
a.fs()# equalsA.fs(a)从描述器的角度看
>>> A.__dict__['fs'].__get__(None, A)<unbound method A.fs>
>>> A.__dict__['fs'].__get__(a, A)<bound method A.fs of <__main__.A object at 0x101fa3250>>
>>> A.__dict__['fc'].__get__(None, A)<bound method type.fc of <class '__main__.A'>>不过实例a调用静态方法会出错(TypeError),因为实例对方法的调用提供了self参数,但sm是没有参数的。但是这提供了另一种思路)比如在python的多进程编程中,进程跑的函数如果是实例函数的会因为无法序列化而失败,但如果是staticmethod就没有问题,静态函数的本质其实也就是普通函数。
所以可以这样
class B(object): @staticmethod def run(inst): inst.foo()
def foo(self): print 'foo'
b = B()B.run(b)在2.x中区分实例函数和类函数可以用im_self
>>> A.fs.im_selfNone>>> A.fc.im_self<class '__main__.A'>至于通过实例引用方法时的im_self的值,大家自己可以探索下
获取类中所有定义的方法
- 使用
dir函数
>>> dir(A)['_A__private', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_instance', '_protect', 'fc', 'fs', 'sm']2 使用inspect.getmembers
这个除了函数名的字符串以外,连对象的type也得到了,结果更加详细
>>> inspect.getmembers(A)[('_A__private', <unbound method A.__private>), ('__class__', type), ('__delattr__', <slot wrapper '__delattr__' of 'object' objects>), ('__dict__', <dictproxy {'_A__private': <function __main__.__private>, '__dict__': <attribute '__dict__' of 'A' objects>, '__doc__': 'test class', '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '_instance': None, '_protect': <function __main__._protect>, 'fc': <classmethod at 0x1022a50f8>, 'fs': <function __main__.fs>, 'sm': <staticmethod at 0x1022a5088>}>), ('__doc__', 'test class'), ('__format__', <method '__format__' of 'object' objects>), ('__getattribute__', <slot wrapper '__getattribute__' of 'object' objects>), ('__hash__', <slot wrapper '__hash__' of 'object' objects>), ('__init__', <slot wrapper '__init__' of 'object' objects>), ('__module__', '__main__'), ('__new__', <function __new__>), ('__reduce__', <method '__reduce__' of 'object' objects>), ('__reduce_ex__', <method '__reduce_ex__' of 'object' objects>), ('__repr__', <slot wrapper '__repr__' of 'object' objects>), ('__setattr__', <slot wrapper '__setattr__' of 'object' objects>), ('__sizeof__', <method '__sizeof__' of 'object' objects>), ('__str__', <slot wrapper '__str__' of 'object' objects>), ('__subclasshook__', <function __subclasshook__>), ('__weakref__', <attribute '__weakref__' of 'A' objects>), ('_instance', None), ('_protect', <unbound method A._protect>), ('fc', <bound method type.fc of <class '__main__.A'>>), ('fs', <unbound method A.fs>), ('sm', <function __main__.sm>)]判断某个属性是否可调用
a = A()callable(getattr(a, 'testattr', None))获得一个对象中所有可调用的方法
[method for method in dir(object) if callable(getattr(object, method))]隐藏属性
重写__dict__或者__dir__
class C(object): __dict__ = {}
def __dir__(self): return ['cherry']注意,这里的__dict__不是类的,是实例的,类的__dict__是不可写的,不信可以试试
__dir__很奇怪,如果dir函数用在C的实例上,确实会返回['cherry'],但dir(C)还是能得到类中所有属性,有点掩耳盗铃的感觉,待继续研究