通过子类化“type”类来实现类描述符

发布于 2024-09-10 13:01:50 字数 200 浏览 8 评论 0原文

我想要一些数据描述符作为类的一部分。这意味着我希望类属性实际上是属性,其访问由类方法处理。

看来Python并不直接支持这一点,但是可以通过子类化type类来实现。因此,向 type 的子类添加属性将导致其实例具有该属性的描述符。它的实例是类。因此,类描述符。

这是可取的吗?有什么我应该注意的问题吗?

I'd like to have some data descriptors as part of a class. Meaning that I'd like class attributes to actually be properties, whose access is handled by class methods.

It seems that Python doesn't directly support this, but that it can be implemented by subclassing the type class. So adding a property to a subclass of type will cause its instances to have descriptors for that property. Its instances are classes. Thus, class descriptors.

Is this advisable? Are there any gotchas I should watch out for?

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

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

发布评论

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

评论(2

小女人ら 2024-09-17 13:01:50

按照约定(通常),当在类上访问描述符时,返回描述符对象本身。这就是property的作用;如果您访问类上的属性对象,则会返回该属性对象(因为这是它的 __get__ 方法选择执行的操作)。但这是惯例。你不必那样做。

因此,如果您只需要在类上有一个 getter 描述符,并且您不介意尝试设置会覆盖该描述符,则可以在不进行元类编程的情况下执行类似的操作:

def classproperty_getter_only(f):
    class NonDataDescriptor(object):
        def __get__(self, instance, icls):
            return f(icls)
    return NonDataDescriptor()

class Foo(object):

    @classproperty_getter_only
    def flup(cls):
        return 'hello from', cls

print Foo.flup
print Foo().flup

如果

('hello from', <class '__main__.Foo'>)
('hello from', <class '__main__.Foo'>)

您想要一个完整的数据描述符,或者想要使用内置的属性对象,那么您是对的,您可以使用元类并将其放在那里(意识到该属性对于您的类的实例是完全不可见的;在类的实例上进行属性查找时不会检查元类)。

可取吗?我不这么认为。我不会在生产代码中做你随意描述的事情;只有当我有一个非常令人信服的理由时,我才会考虑这样做(而且我无法立即想到这种情况)。元类非常强大,但并非所有程序员都能很好地理解它们,并且有些难以推理,因此它们的使用使您的代码更难以维护。我认为这种设计会受到整个 Python 社区的反对。

It is convention (usually), for a descriptor, when accessed on a class, to return the descriptor object itself. This is what property does; if you access a property object on a class, you get the property object back (because that's what it's __get__ method chooses to do). But that's a convention; you don't have to do it that way.

So, if you only need to have a getter descriptor on your class, and you don't mind that a an attempt to set will overwrite the descriptor, you can do something like this with no metaclass programming:

def classproperty_getter_only(f):
    class NonDataDescriptor(object):
        def __get__(self, instance, icls):
            return f(icls)
    return NonDataDescriptor()

class Foo(object):

    @classproperty_getter_only
    def flup(cls):
        return 'hello from', cls

print Foo.flup
print Foo().flup

for

('hello from', <class '__main__.Foo'>)
('hello from', <class '__main__.Foo'>)

If you want a full fledged data descriptor, or want to use the built-in property object, then you're right you can use a metaclass and put it there (realizing that this attribute will be totally invisible from instances of your class; metaclasses are not examined when doing attribute lookup on an instance of a class).

Is it advisable? I don't think so. I wouldn't do what you're describing casually in production code; I would only consider it if I had a very compelling reason to do so (and I can't think of such a scenario off the top of my head). Metaclasses are very powerful, but they aren't well understood by all programmers, and are somewhat harder to reason about, so their use makes your code harder to maintain. I think this sort of design would be frowned upon by the python community at large.

过期以后 2024-09-17 13:01:50

这就是“类属性实际上是属性,其访问由类方法处理”的意思吗?

您可以使用装饰器 property 使访问器看起来像是实际的数据成员。然后,您可以使用 x.setter 装饰器为该属性创建 setter。

确保从 object 继承,否则这将不起作用。

class Foo(object):
    def __init__(self):
            self._hiddenx = 3
    @property
    def x(self):
            return self._hiddenx + 10
    @x.setter
    def x(self, value):
            self._hiddenx = value

p = Foo()

p.x #13

p.x = 4
p.x #14

Is this what you mean by "class attributes to actually be properties, whose access is handled by class methods"?

You can use a decorator property to make an accessor appear to be an actual data member. Then, you can use the x.setter decorator to make a setter for that attribute.

Be sure to inherit from object, or this won't work.

class Foo(object):
    def __init__(self):
            self._hiddenx = 3
    @property
    def x(self):
            return self._hiddenx + 10
    @x.setter
    def x(self, value):
            self._hiddenx = value

p = Foo()

p.x #13

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