在 Python 方法中设置属性

发布于 2024-10-18 08:15:07 字数 1332 浏览 1 评论 0原文

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

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

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

谢谢你,
鲁比克

​我已经检查过这篇文章,但它并没有解决我的问题: 在方法内使用 Python property()

编辑:我无法使用 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

I want to set a read-only attribute inside a class method.
I have already tried this:

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

but it is horrible. Is there another way? What I need to do is setting the property:

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

but I need to do it inside a method. Is there another way?

Thank you,
rubik

P.S. I have already checked this post, but it does not solve my problem:
Using Python property() inside a method

EDIT: I cannot use property, because I want to set it inside a method. I can use property only from outside:

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)

And I can't do that because I don't know the property name and I have to set it dynamically. Something like this:

class Foo(object):
    def __init__(self, v):
        self._set_property_from_inside('v', v)
>>> f = Foo(42)
>>> f.v
42

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

弥繁 2024-10-25 08:15:07

我认为您正在寻找 python 描述符

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__ 中,它将 bx 转换为 type(b).__dict__['x'].__get__(b,类型(b))

因此,如果您将描述符放入实例的 __dict__ 中,那么当您将该属性设置为新值时,它们就会被覆盖。

I think you're looking for 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

Here you can do whatever you want to control access in the __get__ and __set__ methods. If you call obj.get_v in __get__ and obj.set_v in __set__, this is very close to the actual implementation of a property, as you can see in the above link.

Edit: Fixed. I should have read that page better myself. Quoting:

For objects, the machinery is in object.__getattribute__ which transforms b.x into type(b).__dict__['x'].__get__(b, type(b))

So if you put descriptors in the __dict__ of the instance, they'll simply get overwritten when you set that attribute to a new value.

孤檠 2024-10-25 08:15:07
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
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)

Then:

>>> 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
始于初秋 2024-10-25 08:15:07

我已经想到了一个更干净的解决方案来实现纯只读属性,如果这就是您想要的。它是 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 属性时出现问题,因为我需要取消修改“private”属性来检查其是否存在 (hasattr(self, " _Foo__readonly")),这是不鼓励的。

I've thought of what I think is a cleaner solution for implementing a pure read-only attribute, if that's all you want. It's a variant of the solution tangentstorm gave, but dispenses with the need for a __getattr__ method altogether.

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)

It works like this:

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

Making a read-only attribute read-write again is easy:

    def unset_readonly(self, attr):
        self.readonly.remove(attr)

In my first attempt at writing this idea I used self.__readonly instead of self.readonly, but that leads to a problem with actually setting the __readonly attribute, since I'd need to do un-munge the "private" attribute to check for its presence (hasattr(self, "_Foo__readonly")), and this is discouraged.

property() 正是这里的解决方案。为什么不应该解决你的问题?
重写 setter 和 getter 方法可以让您准确地实现您想要和需要的功能:对属性的完全控制。

请查看官方文档,例如

http://docs.python.org/library/functions.html #property

以便了解整个故事。

property() is exactly the solution here. Why shouldn't is solve your problem?
Overriding the setter an getter method allows you exactly what you want and need: full control over the property.

Please check with official documentation like

http://docs.python.org/library/functions.html#property

in order to understand the whole story.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文