linux 页描述符,Python描述符(descriptor)解密

在元类中使用带标签的描述符

由于描述符的标签名和赋给它的变量名相同,所以有人使用元类来自动处理这个簿记(bookkeeping)任务。

class Descriptor(object):

def __init__(self):

#notice we aren't setting the label here

self.label = None

def __get__(self, instance, owner):

print '__get__. Label = %s' % self.label

return instance.__dict__.get(self.label, None)

def __set__(self, instance, value):

print '__set__'

instance.__dict__[self.label] = value

class DescriptorOwner(type):

def __new__(cls, name, bases, attrs):

# find all descriptors, auto-set their labels

for n, v in attrs.items():

if isinstance(v, Descriptor):

v.label = n

return super(DescriptorOwner, cls).__new__(cls, name, bases, attrs)

class Foo(object):

__metaclass__ = DescriptorOwner

x = Descriptor()

f = Foo()

f.x = 10

print f.x

__set__

__get__. Label = x

10

我不会去解释有关元类的细节——参考文献中David Beazley已经在他的文章中解释的很清楚了。 需要指出的是元类自动的为描述符添加标签,并且和赋给描述符的变量名字相匹配。

尽管这样解决了描述符的标签和变量名不一致的问题,但是却引入了复杂的元类。虽然我很怀疑,但是你可以自行判断这么做是否值得。

访问描述符的方法

描述符仅仅是类,也许你想要为它们增加一些方法。举个例子,描述符是一个用来回调property的很好的手段。比如我们想要一个类的某个部分的状态发生变化时就立刻通知我们。下面的大部分代码是用来做这个的:

class CallbackProperty(object):

"""A property that will alert observers when upon updates"""

def __init__(self, default=None):

self.data = WeakKeyDictionary()

self.default = default

self.callbacks = WeakKeyDictionary()

def __get__(self, instance, owner):

return self.data.get(instance, self.default)

def __set__(self, instance, value):

for callback in self.callbacks.get(instance, []):

# alert callback function of new value

callback(value)

self.data[instance] = value

def add_callback(self, instance, callback):

"""Add a new function to call everytime the descriptor updates"""

#but how do we get here?!?!

if instance not in self.callbacks:

self.callbacks[instance] = []

self.callbacks[instance].append(callback)

class BankAccount(object):

balance = CallbackProperty(0)

def low_balance_warning(value):

if value < 100:

print "You are poor"

ba = BankAccount()

# will not work -- try it

#ba.balance.add_callback(ba, low_balance_warning)

这是一个很有吸引力的模式——我们可以自定义回调函数用来响应一个类中的状态变化,而且完全无需修改这个类的代码。这样做可真是替人分忧解难呀。现在,我们所要做的就是调用ba.balance.add_callback(ba, low_balance_warning),以使得每次balance变化时low_balance_warning都会被调用。

但是我们是如何做到的呢?当我们试图访问它们时,描述符总是会调用__get__。就好像add_callback方法是无法触及的一样!其实关键在于利用了一种特殊的情况,即,当从类的层次访问时,__get__方法的第一个参数是None。

class CallbackProperty(object):

"""A property that will alert observers when upon updates"""

def __init__(self, default=None):

self.data = WeakKeyDictionary()

self.default = default

self.callbacks = WeakKeyDictionary()

def __get__(self, instance, owner):

if instance is None:

return self

return self.data.get(instance, self.default)

def __set__(self, instance, value):

for callback in self.callbacks.get(instance, []):

# alert callback function of new value

callback(value)

self.data[instance] = value

def add_callback(self, instance, callback):

"""Add a new function to call everytime the descriptor within instance updates"""

if instance not in self.callbacks:

self.callbacks[instance] = []

self.callbacks[instance].append(callback)

class BankAccount(object):

balance = CallbackProperty(0)

def low_balance_warning(value):

if value < 100:

print "You are now poor"

ba = BankAccount()

BankAccount.balance.add_callback(ba, low_balance_warning)

ba.balance = 5000

print "Balance is %s" % ba.balance

ba.balance = 99

print "Balance is %s" % ba.balance

Balance is 5000

You are now poor

Balance is 99

结语

希望你现在对描述符是什么和它们的适用场景有了一个认识。前进吧骚年!

参考文献

0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值