python只读类属性

top*_*her 7 python properties

有没有办法在Python中创建只读类属性?防爆.在Unity3d中你可以这样做:

transform.position = Vector3.zero
Run Code Online (Sandbox Code Playgroud)

Vector3.zero返回Vector3类的一个实例,其中x,y和z为0.这基本上与:

transform.position = Vector3(0, 0, 0)
Run Code Online (Sandbox Code Playgroud)

我尝试过这样的事情:

class Vector3(object):
    zero = Vector3(0, 0, 0)
    ...
Run Code Online (Sandbox Code Playgroud)

但是我得到一个未定义的变量错误,因为该类尚未定义.那么如何创建不需要类实例的只读类属性?

Dev*_*rre 10

最明显的方法可能是在事后改变类对象:

class Vector3(object):
    # ...
Vector3.zero = Vector3(0, 0, 0)
Run Code Online (Sandbox Code Playgroud)

这个问题的主要问题是只有一个零对象,如果它是可变的,你可能会在整个地方造成意外伤害.使用每次访问时创建零向量的动态描述符可能更容易(并且感觉不那么hacky)(这通过创建ClassProperty类来完成):

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class Vector3(object):
    @ClassProperty
    @classmethod
    def zero(cls):
        return cls(0, 0, 0)
Run Code Online (Sandbox Code Playgroud)

不过,我认为这些都不是"pythonic".考虑Python中的其他数学类型:整数,浮点数和复数.这些都没有"零"类属性或零构造函数,而是在没有参数的情况下调用时返回零.所以也许最好这样做:

class Vector3(object):
    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z 
Run Code Online (Sandbox Code Playgroud)

如果你知道我的意思,那就不像Unity3D,更像是Python.

  • @topher,你对只读的坚持是错误的.这个*名义上是只读的,另外我可以很容易地用元类解决方案来改变它.*在Python中,尝试在语言级别强制执行"只读"等操作是浪费精力.* (2认同)

Ery*_*Sun 9

使用元类

class MetaVector3(type):

    @property
    def zero(cls):
        return cls(0,0,0)

class Vector3(object):
    __metaclass__ = MetaVector3

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

>>> v = Vector3.zero
>>> v.x, v.y, v.z
(0, 0, 0)
Run Code Online (Sandbox Code Playgroud)

  • 元类不能被多重继承或组合,所以如果你想要另一个元类,或者另一个超类,你就是SOL.我一般都避开它们. (4认同)

cne*_*son 6

使用描述符:

class Zero(object):
    def __get__(self, instance, owner):
        return owner(0, 0, 0)

    def __set__(self, instance, value):
        #could raise an exception here or somethiing
        #this gets called if the user attempts to overwrite the property
        pass  

class Vector3(object):
    zero = Zero()

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __repr__(self):
        return str(self.__dict__)
Run Code Online (Sandbox Code Playgroud)

应该做你想做的事:

>>> v = Vector3(1, 2, 3)
>>> v
{'y': 2, 'x': 1, 'z': 3}
>>> v.zero
{'y': 0, 'x': 0, 'z': 0}
>>> v.zero = 'foo'
>>> v.zero
{'y': 0, 'x': 0, 'z': 0}
Run Code Online (Sandbox Code Playgroud)