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

发布于 2024-08-08 21:49:41 字数 1113 浏览 4 评论 0原文

我想要实现的目标是这样的:

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

What I am trying to achieve is something like this:

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

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

#output:
>>0
>>25

What I want happening (as above): When WidthVariable - a class - is created it adds the variable width to the object instance. This variable acts like a normal property, but in this particular case it is read-only (only the fget variable is set). Additionally, the fget calls a function defined in WidthVariable which decides what width to return.

However, I have no idea how to do this! I tried it using normal properties but I found that they only work on classes and not per instance - please note that the code I use should be similar as possible to the above (i.e. only code within the __init__ of WidthVariable should set the width variable, nowhere else). Also, self.width cannot be function, because I do not what to call it like self.width(), I want self.width (because it keeps with the rest of the design I have).

To clarify, the complete code would be something like this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

翻身的咸鱼 2024-08-15 21:49:41

正如@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 new-style;-), to:

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

没有什么太黑魔法的,如你所见!-)

Since, as @Jonathan says, descriptors (including properties) are per-class, not per-instance, the only way to get different per-instance descriptors is to have each instance individualize its own class. That's pretty shallow and easy as far as metaprogramming goes;-)...:

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

I'm also adding object explicitly because it's needed (in Python 2.*, and you do say that's what you're using!!!) to make classes new-type. Never use legacy classes any more, they don't behave correctly with respect to properties and much else besides (and for backwards compatibility they can't -- in Python 3, legacy classes have finally been annihilated so EVERY class is new-style without the requirement to explicitly inherit from object any more!).

Now, any descriptor that's placed in self.__class__.__dict__ will only affect this one instance, none other. There's a bit of overhead (each GottaBeMe class and therefore each instance has its own __dict__, etc), but nothing too terrible.

Now, all that's needed to satisfy the original request is to change:

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

(also renaming the object arg sensibly to avoid trampling on a built-in, and making the class new-style because you should ALWAYS make EVERY class new-style;-), to:

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

Nothing too black-magicky, as you can see!-)

执手闯天涯 2024-08-15 21:49:41

我相信我现在明白你的问题,而且我也相信你是 运气不好

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

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

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

I believe I now understand your question, and I also believe you're out of luck.

For new-style classes, implicit
invocations of special methods are
only guaranteed to work correctly if
defined on an object’s type, not in
the object’s instance dictionary.

Descriptors (which are used to implement properties) must appear in the class's __dict__, and cannot appear in the instance's __dict__. In other words, Python is not Ruby!

I happily await correction from a godly Python metaprogrammer, but I think I'm right.

多孤肩上扛 2024-08-15 21:49:41

我不明白你构建示例的方式,也不明白你所说的“普通属性”仅适用于“类”的含义。以下是创建只读属性的方法:

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

I don't understand the way you've constructed your example, nor do I understand what you mean about "normal properties" only working "on classes". Here's how you create a read-only property:

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
睫毛上残留的泪 2024-08-15 21:49:41

不太清楚你想要什么?但我假设您希望为每个实例自定义 obj.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

Not very clear what you want? but I assume you want obj.width to be customized for each instance
Here is a easy way by using plain properties, width property returns value returned by a per instance callback

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

If callback can not be passed we can assign it to WidthVariable which returns width based on instance

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文