在 Python 方法中设置属性

rub*_*bik 5 python methods properties class

我想在类方法内设置一个只读属性。
我已经尝试过这个:

class Foo(object):
    def __init__(self, v):
        self._set('_v', v)

    def _set(self, attr, v):
        setattr(self, attr, v)
        setattr(Foo, attr[1:], property(lambda self: getattr(self, attr)))
Run Code Online (Sandbox Code Playgroud)

但这太可怕了。还有别的办法吗?我需要做的是设置属性:

class Foo(object):
    def __init__(self, v):
        self._v = v

    @ property
    def v(self):
        return self._v    

>>> f = Foo(42)
>>> f.v
42
>>> f.v = 41
AttributeError: can't set attribute ## This is what I want: a read-only attribute
Run Code Online (Sandbox Code Playgroud)

但我需要在方法内完成它。还有别的办法吗?

谢谢你,
鲁比克

PS我已经检查过这篇文章,但它没有解决我的问题: Using Python property() inside a method

编辑:我不能使用property,因为我想将它设置在方法中。property我只能从外部使用:

class Foo(object):
    def __init__(self, v):
        self._v = v
    @ property
    def v(self):
        return self._v
    ## ...OR
    def getv(self):
        return self._v
    v = property(getv)
Run Code Online (Sandbox Code Playgroud)

我不能这样做,因为我不知道属性名称,并且必须动态设置它。像这样的东西:

class Foo(object):
    def __init__(self, v):
        self._set_property_from_inside('v', v)
>>> f = Foo(42)
>>> f.v
42
Run Code Online (Sandbox Code Playgroud)

Lau*_*low 1

我已经想到了一个更干净的解决方案来实现纯只读属性,如果这就是您想要的。它是 tangentstorm 给出的解决方案的一个变体,但完全不需要方法__getattr__

class Foo(object):
    def __init__(self):
        self.readonly = set()

    def set_readonly(self, attr, value):
        setattr(self, attr, value)
        self.readonly.add(attr)

    def __setattr__(self, attr, value):
        if hasattr(self, "readonly") and attr in self.readonly:
            raise AttributeError("Read only attribute: %s" % (attr,))
        object.__setattr__(self, attr, value)
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:

>>> f = Foo()
>>> f.x = 5
>>> f.set_readonly("y", 9)
>>> f.x, f.y
(5, 9)
>>> f.x = 7
>>> f.y = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "ro.py", line 13, in __setattr__
    raise AttributeError("Read only attribute: %s" % (name,))
AttributeError: Read only attribute: y
Run Code Online (Sandbox Code Playgroud)

将只读属性再次读写很容易:

    def unset_readonly(self, attr):
        self.readonly.remove(attr)
Run Code Online (Sandbox Code Playgroud)

在我第一次尝试编写这个想法时,我使用self.__readonly而不是self.readonly,但这会导致实际设置属性时出现问题__readonly,因为我需要取消“私有”属性来检查它的存在(hasattr(self, "_Foo__readonly")),并且这感到气馁。