我希望能够动态检查和设置实例属性值。该用例用于类似点的类,在该类中,我想要一个自定义的“ set_value”方法,该方法检查客户端尝试设置的值,然后确定从那里开始做什么。
我的目标是拥有一种方法,该方法允许一次设置实例的值(x,y),然后禁止将来对这些变量进行赋值...有效地使它们“不变”。 我知道,从技术上讲,这并不是使它们一成不变,我依靠的是绅士的同意,不要做任何有趣的事情,也不要弄乱它。
我正在尝试弄乱 setattr 方法,但无济于事,因为那样一来,该init将无法首先运行。
我的课显示如下:
class Node:
"""Represents the nodes as points with a position x, y."""
def __init__(self, x=0, y=0, x_state=0, y_state=0):
"""Create a new node at x, y"""
self.x = x
self.y = y
if self.x != 0:
self.x_state = 1
else:
self.x_state = x_state
if self.y != 0:
self.y_state = 1
else:
self.y_state = y_state
# some other dunder methods here
def set_value(self, attr, value):
if self.[attr]_state == 0:
self.[attr] = value
self.[attr]_state = 1
else:
raise NotImplementedError
该方法检查适当的“状态”变量,然后如果“状态”为0,则将x或y变量分配给用户给定的值,然后将“状态”的值赋予1,从而呈现出未来值分配没用。
我对动态引用属性感到困惑。
这可能吗?
在此先感谢您的帮助!
答案 0 :(得分:0)
听起来像您想要一个namedtuple(或将其子类化)。没有更具体的说明,尚不清楚不使用它的原因是什么。
In [7]: from collections import namedtuple
point = namedtuple("Point", ["x", "y"])
In [8]: point
Out[8]: __main__.Point
In [9]: point(1, 2)
Out[9]: Point(x=1, y=2)
In [10]: p = point(1, 2)
In [11]: p.x = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-11-4e1ffb2a7978> in <module>()
----> 1 p.x = 1
AttributeError: can't set attribute
在这方面,Tuples非常棒,因为它们是高效的,并且是获得不变性的“ pythonic”方式。
如果您使用的是最新版本的Python(3.7+),则可以执行以下操作:
In [1]: from dataclasses import dataclass
...:
In [2]: @dataclass(frozen=True)
...: class Point():
...: x: int
...: y: int
...:
...:
In [3]: point = Point(x=1, y=2)
In [4]: point
Out[4]: Point(x=1, y=2)
In [5]: point.x = 1
---------------------------------------------------------------------------
FrozenInstanceError Traceback (most recent call last)
<ipython-input-5-7f9ef2714879> in <module>()
----> 1 point.x = 1
<string> in __setattr__(self, name, value)
FrozenInstanceError: cannot assign to field 'x'
这里最酷的部分是可以轻松添加一些功能来扩展Point
。
setattr
确实是用于您的案例的相当困难的方法。这是一个有趣的实现,但是不推荐使用此代码(hacky,可能还有一些边缘情况):
class Node():
def __init__(self, x, y):
self.x = x
self.y = y
self.frozen = True
def __setattr__(self, key, value):
if getattr(self, "frozen", False):
raise ValueError("Cannot change value")
self.__dict__[key] = value