python method-wrapper_python描述符理解

Python中的描述符是一个相对底层的概念

descriptor

Any object which defines the methods get(), set(), or delete(). When a class attribute is a descriptor, its special binding behavior is triggered upon attribute lookup. Normally, using a.b to get, set or delete an attribute looks up the object named b in the class dictionary for a, but if b is a descriptor, the respective descriptor method gets called. Understanding descriptors is a key to a deep understanding of Python because they are the basis for many features including functions, methods, properties, class methods, static methods, and reference to super classes. For more information about descriptors’ methods, see Implementing Descriptors.

描述符

任何实现了__get__(), __set__(), 或者 __delete__()方法的对象就是描述符。一个class的属性是一个描述符的时候,对这个属性的访问会触发特定的绑定行为。一般的我们使用a.b的方式访问,修改和删除属性,它通过查找class的字典来访问属性b,当时如果b是一个描述符,那么get,set和delete相关的描述符方法会被调用。理解描述符是深入理解python的关键,因为描述符是很多特性实现的基础,比如:方法,函数,属性,类方法,静态方法还有对父类方法的引用。详细的说明请看描述符的实现。--CooMark译

在说描述符之前,先看一小段代码:

class Foo(object):

"""docstring for Foo"""

def __init__(self, arg=''):

super(Foo, self).__init__()

self.arg = arg

def foo(self):

print(self)

print('foo:', 123)

print(Foo.foo)

print(Foo().foo)

print(Foo.foo.__get__)

# 输出

#

# >

#

主要想说的是这个__get__,他是一个method-wrapper。每次调用一个方法,其实都是调用这个__get__构造的method对象。我们定义的方法其实都是descriptor,它通过__get__控制了对相应method的访问

def __get__(self, instance, owner)

Foo.foo -- Foo.__dict__['foo'].__get__(None,Foo) # 隐式传递的self是Foo class对象, 一切皆对象,class在模块级别中也有instance

下面三种方式的调用输出的结果是一样的,这个None咋来的呢?,有一点可以确认:self都是class对象实例

# 两种访问方式是一样的

print(Foo.foo.__get__(Foo(), Foo)())

print(Foo.__dict__['foo'].__get__(Foo(), Foo)())

c = Foo()

print(Foo.foo.__get__(c, Foo)())

# <__main__.foo object at>

# foo: 123

# None

# <__main__.foo object at>

# foo: 123

# None

# <__main__.foo object at>

# foo: 123

# None

再说说bound method和unbound method

区分依据就是是否给method绑定了实例对象,也就是调用的时候是否会隐式传递self参数

print(Foo.foo)

# 当时3.0之后不再叫unbound method,因为定义为function更贴切

#

print(Foo().foo)

# >

描述符

我们定义的属性,方法其实都是描述符,只不过我们习以为常,而没有刻意的去了解背后的机制

class Bar(object):

"""docstring for Bar"""

_name = 'Mark Xiao'

def __init__(self, arg=''):

super(Bar, self).__init__()

self.arg = arg

self._name = 'CooMark'

def _get_name(self):

return self._name

def _set_name(self, value):

self._name = value

def _del_name(self):

del self._name

name = property(_get_name, _set_name, _del_name, 'description of property name')

print(Bar.name)

print(Bar().name)

#

# CooMark

描述符协议:

__get__(self, instance, owner) --> return value

__set__(self, instance, value)

__delete__(self, instance)

描述符对象以类型 (owner class) 成员的方式出现,且最少要实现一个协议方法。最常见的描述符有 property、staticmethod、classsmethod。访问描述符类型成员时,解释器会自动调用与行为相对应的协议方法。

实现 get 和 set 方法,称为 data descriptor。

仅有 get 方法的,称为 non-data descriptor。

get 对 owner_class、owner_instance 访问有效。

set、delete 仅对 owner_instance 访问有效。

instance method, class method, static method

实例方法bound到instance

类方法bound到class

静态方法没有绑定,仅仅是个方法

总结

描述符是一种协议,实现了相应的描述符方法便会有相应的描述符行为,property就是一个特定的描述符类型,我们可以自己实现类似的功能

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值