目的是在列表中提供一些字符串作为类的属性。该类不仅应具有属性,还应具有各自的 getter 和 setter 方法。在继承自该类的其他一些类中,需要覆盖其中一些 setter 。
为此,我提出了以下建议。在字符串列表的循环中使用 setattr,创建一个属性和相应的方法。关于第一部分,代码按预期工作。
但是,我无法覆盖继承类中的 setter 。
class Base():
attributes = ["attr{}".format(i) for i in range(100)]
def __init__(self):
_get = lambda a: lambda : getattr(self, a)
_set = lambda a: lambda v: setattr(self, a, v)
for attr in self.attributes:
setattr(self, attr, None)
setattr(self, "get_"+attr, _get(attr))
setattr(self, "set_"+attr, _set(attr))
class Child(Base):
def __init__(self):
super().__init__()
#setattr(self, "set_attr4", set_attr4)
# Here I want to override one of the setters to perform typechecking
def set_attr4(self, v):
print("This being printed would probably solve the problem.")
if type(v) == bool:
super().set_attr4(v)
else:
raise ValueError("attr4 must be a boolean")
if __name__ == "__main__":
b = Base()
b.attr2 = 5
print(b.get_attr2())
b.set_attr3(55)
print(b.get_attr3())
c = Child()
c.set_attr4("SomeString")
print(c.get_attr4())
这里的输出是
5
555
SomeString
然而,预期的输出将是
5
555
This being printed would probably solve the problem.
ValueError("attr4 must be a boolean")
所以 set_attr4 方法永远不会被调用;我猜这是预料之中的,因为 __init__ 在读入类结构之后被调用。但是我不知道如何重写这些方法。我尝试添加 setattr(self, "set_attr4", set_attr4)(上面代码中的注释行)但无济于事。
或者更一般地说,propery 通常用于创建 getter 和 setter。但我不认为我理解如何在 getter 和 setter 是动态创建的并且需要被 child 覆盖的情况下应用它。
有什么解决办法吗?
由于评论而更新:有人指出,在 python 中使用 getters/setters 可能不是一个好的风格,而且通常可能不需要它们。虽然这绝对是要记住的事情,但这个问题的背景是我正在扩展一个旧的现有代码,它始终使用 getters/setters。因此,我不希望更改样式并让用户(这个项目总共只有大约 20 个用户,但仍然......)突然改变他们访问 API 中属性的方式。
然而,任何 future 的读者可能会认为 getter/setter 方法至少是有问题的。
请您参考如下方法:
元类来拯救!
class Meta(type):
def __init__(cls, name, bases, dct):
for attr in cls.attributes:
if not hasattr(cls, attr):
setattr(cls, attr, None)
setattr(cls, f'get_{attr}', cls._get(attr))
setattr(cls, f'set_{attr}', cls._set(attr))
class Base(metaclass=Meta):
attributes = ["attr{}".format(i) for i in range(100)]
_get = lambda a: lambda self: getattr(self, a)
_set = lambda a: lambda self, v: setattr(self, a, v)
# the rest of your code goes here
这是不言自明的:创建 attributes、_get、_set 类变量(这样您就可以在没有类实例化的情况下访问它们),然后让元类为您设置一切。
