3

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()
# equals
A.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_self
None
>>> A.fc.im_self
<class '__main__.A'>

至于通过实例引用方法时的im_self的值,大家自己可以探索下

获取类中所有定义的方法

  1. 使用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)还是能得到类中所有属性,有点掩耳盗铃的感觉,待继续研究


quietin
761 声望44 粉丝

兴趣在程序语言, 高性能, 分布式等方面