使用在每个实例级别定义的属性而不是每个类

时间:2009-10-27 16:47:04

标签: python properties python-2.6

我想要实现的是这样的:

class object:
    def __init__(self):
        WidthVariable(self)

        print self.width
        #Imagine I did this 60frames/1second later
        print self.width

#output:
>>0
>>25

我想要发生什么(如上所述):当WidthVariable - 创建一个类时,它会将变量width添加到对象实例。此变量的作用类似于普通属性,但在此特定情况下,它是只读的(仅设置fget变量)。此外,fget调用WidthVariable中定义的函数,该函数决定返回width

但是,我不知道该怎么做!我尝试使用普通属性,但我发现它们只适用于类而不是每个实例 - 请注意我使用的代码应尽可能与上面的代码相似(即只有__init__ WidthVariable内的代码应该设置width变量,而不是其他地方)。此外,self.width无法正常运行,因为我不像self.width()那样称呼它,我想要self.width(因为它与我设计的其余部分保持一致)。

为了澄清,完整的代码将是这样的:

class MyObject:
    def __init__(self)
        WidthVariable(self)
        print self.width

class WidthVariable:
    def __init__(self, object)
        object.width = property(self.get_width)

    def get_width(self):
        value = #do_stuff
        return value #The Value

#output:
>>25 #Whatever the Value was

4 个答案:

答案 0 :(得分:4)

因为正如@Jonathan所说,描述符(包括属性)是每个类而不是每个实例,获得不同的每个实例描述符的唯一方法是让每个实例个性化它自己的类。就元编程而言,这是非常浅薄和容易的; - )......:

class Individualistic(object_or_whatever_bases):
  def __init__(self, whatever_args):
    self.__class__ = type('GottaBeMe', (self.__class__, object), {})
    # keep rocking...!-)

我还明确地添加了object,因为它需要(在Python 2.*中,并且你确实说这是你正在使用的!!!)以使类成为新类型。永远不再使用遗留类,它们在属性方面表现不正确以及其他许多方面(并且为了向后兼容性,它们不能 - 在Python 3中,遗留类最终被消灭所以每个类都是新类型没有要求明确继承自对象!)。

现在,放在self.__class__.__dict__中的任何描述符只会影响这一个实例,而不会影响其他实例。有一些开销(每个GottaBeMe类,因此每个实例都有自己的__dict__等),但没什么可怕的。

现在,满足原始请求所需的只是改变:

class WidthVariable:
    def __init__(self, object)
        object.width = property(self.get_width)

(同时明智地重命名object arg以避免践踏内置,并使该类成为新式,因为你应该总是将每个类型改为新式;-),以:

class WidthVariable(object):
    def __init__(self, obj)
        obj.__class__.width = property(self.get_width)

正如你所看到的,没有什么太黑的魔法了! - )

答案 1 :(得分:0)

我不明白你构建你的例子的方式,也不明白你对“正常属性”的意思,只是在“课堂上”工作。以下是创建只读属性的方法:

class Foo(object):
    # create read-only property "rop"
    rop = property(lambda self: self._x)

    def __init__(self):
        self._x = 0

    def tick(self):
        self._x += 1    

f = Foo()
print f.rop # prints 0
f.tick()
f.tick()
print f.rop # prints 2
f.rop = 4 # this will raise AtributeError

答案 2 :(得分:0)

不是很清楚你想要什么?但我假设您希望为每个实例定制obj.width 这是一种使用普通属性的简单方法,每个实例回调返回的width属性返回值

class MyClass(object):
    def __init__(self, callback):
        self.callback = callback

    def get_width(self):
        return self.callback()

    width = property(get_width)

def w1(): return 0
def w2(): return 25

o1 = MyClass(w1)
o2 = MyClass(w2)

print o1.width
print o2.width

如果无法传递回调,我们可以将其分配给WidthVariable,它根据实例返回宽度

class MyClass(object):
    def __init__(self):
        self.callback = WidthVariable(self)

    def get_width(self):
        return self.callback()

    width = property(get_width)

class WidthVariable(object):
    def __init__(self, obj):
        self.obj = obj

    def __call__(self):
        return hash(self.obj)

o1 = MyClass()
o2 = MyClass()

print o1.width
print o2.width

答案 3 :(得分:0)

我相信我现在明白你的问题了,我也相信你是out of luck

  

对于新式类,隐式   特殊方法的调用是   只保证正常工作   在对象的类型上定义,而不是在   对象的实例字典。

描述符(用于实现属性)必须出现在类的 __dict__中,并且不能出现在实例的 __dict__中。换句话说,Python不是Ruby!

我高兴地等待着一位虔诚的Python元程序员的纠正,但我认为我是对的。