在工厂方法中通过setattr
设置属性时,我无法设置实例的正确属性。
给出以下代码,其中data
是一个简单的dict,包含例如{ "age": "64", ...}
def factory(data):
obj = MyClass()
for k, v in data.items():
setattr(obj, k, v)
return obj
class MyClass(object):
def __init__(self):
self._age = None
# more...
@property
def age(self):
return self._age
@age.setter
def age(self, value):
some_validation(value)
self._age = value
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
def __getitem__(self, item):
return self.__dict__.get(item, None)
def __getattr__(self, item):
self.__dict__[item] = None
return None
def __str__(self):
return json.dumps(self, default=lambda o: o.__dict__)
c = factory(data)
print(c)
打印创建的对象时,我总是得到以下输出:
{"_age": "64", ...}
但我需要
{"age": "64", ...}
为什么setattr
方法会指定前导下划线?
答案 0 :(得分:2)
你想要实现的一些事情变得混乱,比如想要为可读表示打印__dict__
,而是使用属性的私有属性。让我们从头开始,看看我们如何正确地实现你的课程。
您正在尝试实现一个类,可以将这些属性作为键和属性进行访问。这很好,可以用更简洁的方式完成。
class MyClass:
...
def __getitem__(self, item):
return self.__getattribute__(item)
def __setitem__(self, key, value):
return self.__setattr__(key, value)
当属性不存在时,您还希望返回None
。 __getattr__
涵盖了这一点,当属性不存在时,就会完全调用它。
def __getattr__(self, _):
return None
然后,您想要使用property
为某些属性添加一些验证。这确实是正确的方法。
@property
def age(self):
return self._age
@age.setter
def age(self, value):
# some validation here
self._age = value
最后,您希望能够为您的实例提供一个很好的字符串表示形式。我们必须要小心,因为我们必须添加一些我们不想打印的私有属性。
我们要做的是实施方法keys
以允许转换为dict
。此方法仅返回非私有属性或方法的键。
def keys(self):
return [k for k in dir(self) if not k.startswith('_') and not callable(self[k])]
def __str__(self):
return json.dumps(dict(self))
这是正确的。
obj = MyClass()
obj.age = 3
print(obj)
# prints: {"age": 3}