2

我想要实现的是这样的:

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__of 中的代码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

4 回答 4

6

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

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

我还object明确添加,因为需要它(在 Python2.*中,并且您确实说这就是您正在使用的!!!)使类成为新类型。永远不要再使用遗留类,它们在属性和其他许多方面的行为不正确(并且为了向后兼容性,它们不能——在 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)

如您所见,没有什么太黑魔法了!-)

于 2009-10-27T20:09:38.117 回答
1

我相信我现在明白了你的问题,我也相信你不走运

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

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

我很高兴地等待来自虔诚的 Python 元程序员的纠正,但我认为我是对的。

于 2009-10-27T18:47:27.547 回答
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
于 2009-10-27T17:19:15.057 回答
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
于 2009-10-27T17:24:15.093 回答