开发者

python read-only class properties

Is there a way to make r开发者_StackOverflow中文版ead-only class properties in Python? Ex. in Unity3d you can do this:

transform.position = Vector3.zero

Vector3.zero returns an instance of the Vector3 class where x, y, and z are 0. This is basically the same as:

transform.position = Vector3(0, 0, 0)

I've tried doing something like this:

class Vector3(object):
    zero = Vector3(0, 0, 0)
    ...

But I get an undefined variable error because the class hasn't been defined yet. So how do you make read-only class properties that don't require an instance of the class?


The most obvious way might be to alter the class object after the fact:

class Vector3(object):
    # ...
Vector3.zero = Vector3(0, 0, 0)

The main problem with this is that there's then only one zero object, and if it's mutable you can cause accidental damage all over the place. It may be easier (and feel less hacky) to use a dynamic descriptor that creates a zero vector every time it's accessed (this is done by creating a ClassProperty class):

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)

I consider none of these really "pythonic", though. Consider the other mathematical types in Python: ints, floats, and complex numbers. None of these have a "zero" class attribute, or a zero constructor, instead they return zero when called with no arguments. So perhaps it might be best to do like so:

class Vector3(object):
    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z 

This is less like Unity3D and more like Python, if you know what I mean.


Use a metaclass

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)


Use a descriptor:

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__)

Should do what you want:

>>> 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}


What you're imagining is possible, but not necessary in this case. Just wait until after your class is defined to assign the attribute

class Vector3(object):
    ...
Vector3.zero = Vector3(0, 0, 0)

or make it a module level constant.


There is a good chance you want simply to use a shape (3,) numpy array instead of writing this class, for any practical purposes.


That's a really interesting question, the workaround I would go with is to do a classmethod as a "getter" for the zero object:

class Vector3(object):
    __zero = None
    def __init__(self, x,y,z):
        self.x = x
        self.y = y
        self.z = z

    @classmethod
    def zero(cls):
        if not cls.__zero:
            cls.__zero = Vector3(0,0,0) 
        return cls.__zero

myzerovec = Vector3.zero()


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

class Vector3(object):
    _zero = None

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

    @ClassProperty
    @classmethod
    def zero(cls):
        if cls._zero is None:
            cls._zero = cls(0,0,0) 
        return cls._zero

Shamelessly stolen from here


As for the read-only part, this is a good resource.

template = property(lambda self: self.__template)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜