我想在类方法中设置只读属性 我已经尝试过了:
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)))
但它太可怕了。还有另外一种方法吗?我需要做的是设置属性:
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
但我需要在方法中完成。还有另外一种方法吗?
谢谢你,
魔方
P.S。我已经查过这篇文章,但它没有解决我的问题: 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)
我不能这样做,因为我不知道属性名称,我必须动态设置它。像这样:
class Foo(object):
def __init__(self, v):
self._set_property_from_inside('v', v)
>>> f = Foo(42)
>>> f.v
42
答案 0 :(得分:3)
我认为你正在寻找python descriptors。
class MyDescriptor(object):
def __init__(self, protected_attr_name):
self.attr = protected_attr_name
def __get__(self, obj, objtype):
return getattr(obj, self.attr)
def __set__(self, obj, value):
#setattr(obj, self.attr, value)
raise AttributeError("Can't set attribute")
class Foo(object):
def __init__(self, k, v):
setattr(self.__class__, k, MyDescriptor("_" + k))
setattr(self, "_" + k, v)
f = Foo("v", 42)
print f.v # Prints 42
try:
f.v = 32
except AttributeError:
pass
print f.v # Prints 42
您可以在__get__
和__set__
方法中执行任何操作来控制访问权限。如果你在__get__
中调用obj.get_v,在__set__
中调用obj.set_v,这非常接近于属性的实际实现,正如您在上面的链接中所看到的那样。
修改:已修复。我应该更好地阅读那个页面。引用:
对于对象,机制位于
object.__getattribute__
,将b.x
转换为type(b).__dict__['x'].__get__(b, type(b))
因此,如果您将描述符放在实例的__dict__
中,那么当您将该属性设置为新值时,它们就会被覆盖。
答案 1 :(得分:2)
class Foo(object):
def __getattr__(self, name):
return getattr(self, "_" + name)
def __setattr__(self, name, value):
if name.startswith('_'):
self.__dict__[name] = value
else:
raise ValueError("%s is read only" % name)
然后:
>>> f = Foo()
>>> f.x = 5
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 8, in __setattr__
ValueError: x is read only
>>> f._x = 5
>>> f.x
5
答案 2 :(得分:1)
property()正是这里的解决方案。为什么不能解决你的问题呢? 覆盖setter的getter方法可以让你完全控制你想要的东西:完全控制属性。
请查看
等官方文档http://docs.python.org/library/functions.html#property
为了理解整个故事。
答案 3 :(得分: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)
它的工作原理如下:
>>> 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
再次对只读属性进行读写很容易:
def unset_readonly(self, attr):
self.readonly.remove(attr)
在我第一次尝试撰写此提示时,我使用的是self.__readonly
而不是self.readonly
,但这导致了实际设置__readonly
属性的问题,因为我需要这样做un-munge“private”属性来检查它的存在(hasattr(self, "_Foo__readonly")
),这是不鼓励的。