【发布时间】:2014-12-19 22:00:34
【问题描述】:
在描述符中,__get__ 和 __set__ 的第二个参数绑定到调用对象实例(__get__ 的第三个参数绑定到调用所有者类对象):
class Desc():
def __get__(self,instance,owner):
print("I was called by",str(instance),"and am owned by",str(owner))
return self
class Test():
desc = Desc()
t = Test()
t.desc
我将如何创建一个装饰器来将另一个描述符方法(__get__、__set__ 或 __delete__ 除外)的第二个参数绑定到实例对象?
示例(只是一个示例;不是我真正想要做的事情):
class Length(object):
'''Descriptor used to manage a basic unit system for length'''
conversion = {'inches':1,'centimeters':2.54,'feet':1/12,'meters':2.54/100}
def __set__(self,instance,length):
'''length argument is a tuple of (magnitude,unit)'''
instance.__value = length[0]
instance.__units = length[1]
def __get__(self,instance,owner):
return self
@MagicalDecoratorOfTruth
def get_in(self, instance, unit): #second argument is bound to instance object
'''Returns the value converted to the requested units'''
return instance.__value * (self.conversion[units] / self.conversion[instance.__units])
class Circle(object):
diameter = Length()
def __init__(self,diameter,units):
Circle.diameter.__set__((diameter,units))
c = Circle(12,'inches')
assert c.diameter.get_in('feet') == 1
c.diameter = (1,'meters')
assert c.diameter.get_in('centimeters') == 100
我考虑尝试的一种方法是用装饰器包装get_in 方法。使用 @classmethod 装饰器可以完成类似的操作,其中类方法的第一个参数绑定到类对象而不是类实例对象:
class Test():
@classmethod
def myclassmethod(klass):
pass
t = Test()
t.myclassmethod()
但是,我不确定如何将其应用于上述情况。
避免整个问题的一种方法是将实例对象显式传递给描述符方法:
c = Circle(12,'inches')
assert c.diameter.get_in(c,'feet') == 1
c.diameter = (1,'meters')
assert c.diameter.get_in(c,'centimeters') == 100
但是,这似乎违反了 D.R.Y.,而且很难启动。
【问题讨论】:
-
你的问题是?
-
我认为有很多混乱正在发生。如果您使用
__get__只是像这样返回self,您将如何实际访问instance.__value或instance.__units中的数据?通常,对于描述符,您希望将其设置为使用x.d = foo、x.d或del x.d三种语法模式。 -
您可以在实际的
Circle类中使用__set__看到这个问题,这不起作用。相反,您想将其更改为self.diameter = (diameter,units),因为self指的是Circle实例,它将自动传递到__set__的Length。 (尝试手动传递它实际上会导致错误,与魔法装饰器问题无关)。 -
例如,当您的代码的用户写
Circle.diameter的那一刻,然后繁荣,这是一个值。它不应该是帮助处理值的类对象(即它应该不是Length的实例)。因此,如果您考虑编写some_circle.diameter.get_in('feet'),您应该能够在心理上自动将其替换为(12, 'inches').get_in('feet'),您可以清楚地看到这是没有意义的。 -
描述符方法的绑定行为由
calling类的元类提供(type,如果你在 Py 2.* 中继承自object)。如果您想要不同的行为(包括其他方法的特殊绑定),您将需要实现自己的自定义元类(无疑是子类化type,但仍然有点令人担忧)并将其应用于需要它的calling classes(直接或通过继承)。除非您正在开发一个非常雄心勃勃的全新框架,否则不推荐...
标签: python