Python 通过子类化'type'类实现类描述符

Python 通过子类化'type'类实现类描述符,python,class,properties,class-attributes,descriptor,Python,Class,Properties,Class Attributes,Descriptor,我想要一些数据描述符作为类的一部分。这意味着我希望类属性实际上是属性,其访问由类方法处理 Python似乎不直接支持这一点,但它可以通过子类化type类来实现。因此,将属性添加到类型的子类将导致其实例具有该属性的描述符。它的实例是类。因此,类描述符 这样做明智吗?有什么我应该注意的地方吗?这就是你所说的“类属性实际上是属性,其访问由类方法处理”的意思吗 您可以使用decorator属性使访问者看起来是实际的数据成员。然后,您可以使用x.setterdecorator为该属性创建一个setter

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

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

这样做明智吗?有什么我应该注意的地方吗?

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

您可以使用decorator
属性
使访问者看起来是实际的数据成员。然后,您可以使用
x.setter
decorator为该属性创建一个setter

请确保从
对象继承,否则这将不起作用

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
当对类进行访问时,描述符通常会返回描述符对象本身。这就是
属性
所做的;如果访问类上的属性对象,则会返回属性对象(因为这是
\uuuu get\uuuu
方法选择执行的操作)。但这是一个惯例;你不必那样做

因此,如果您只需要在类上有一个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',)
(“你好,我的朋友”,)
如果您想要一个完整的数据描述符,或者想要使用内置的属性对象,那么您是对的,您可以使用一个元类并将它放在那里(意识到这个属性在类的实例中是完全不可见的;在类的实例上执行属性查找时不会检查元类)


这样做明智吗?我不这么认为。我不会做您在生产代码中随意描述的事情;如果我有一个非常有说服力的理由去做的话,我只会考虑这个问题。元类功能非常强大,但并非所有程序员都能很好地理解它们,而且更难推理,因此元类的使用使代码更难维护。我认为这种设计会受到python社区的普遍反对。

这个线程可能会有所帮助:事实上,它几乎是重复的,除了我明确询问了子类化
类型
,而它只是在该问题的一个答案中建议的。不,我希望能够使用
Foo.x
调用
x(cls)
。非常好的响应,谢谢。当你说元类时,你是指我所描述的,即子类化
类型
?这个术语似乎模棱两可,因为它不同于使用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。有没有办法区分这两个概念?或者子类化
类型
是如此少以至于几乎没有必要吗?据我所知,子类化
类型
只有当您将其用作
元类时才真正有用。类与其元类之间的关系完全类似于对象实例与其类之间的关系。一个班级中的一个班级。当您打印MyClass时,会产生一个隐式的
str(MyClass)
(我们打印的文本),实际被调用以生成该文本的方法是
type.\uuu str\uuuu
(或者自定义元类上的
\uu str\uuuu
方法)。元类定制通常在类构造期间进行,但也可以用其他方式进行定制。好了,我现在明白了。实际上,我调用元类时使用了一个3参数调用
type
来创建类。我只是不明白
\uuuuuuuuuuuuuuuuuu
做什么。我想我被文档中关于其影响发生在类构造中的断言弄糊涂了。但是类声明本身也是如此:)再次感谢。
('hello from', <class '__main__.Foo'>)
('hello from', <class '__main__.Foo'>)