【发布时间】:2011-12-08 14:16:36
【问题描述】:
我刚刚遇到了一种情况,在使用 setattr 或 exec 时,伪-私有类成员名称不会被破坏。
In [1]: class T:
...: def __init__(self, **kwargs):
...: self.__x = 1
...: for k, v in kwargs.items():
...: setattr(self, "__%s" % k, v)
...:
In [2]: T(y=2).__dict__
Out[2]: {'_T__x': 1, '__y': 2}
我也试过exec("self.__%s = %s" % (k, v)),结果相同:
In [1]: class T:
...: def __init__(self, **kwargs):
...: self.__x = 1
...: for k, v in kwargs.items():
...: exec("self.__%s = %s" % (k, v))
...:
In [2]: T(z=3).__dict__
Out[2]: {'_T__x': 1, '__z': 3}
执行self.__dict__["_%s__%s" % (self.__class__.__name__, k)] = v 可以,但__dict__ 是只读属性。
是否有另一种方法可以动态创建这些 psuedo-private 类成员(无需在名称修改中进行硬编码)?
更好地表达我的问题:
当遇到设置的双下划线 (self.__x) 属性时,python 会“在幕后”做什么?是否有用于进行修饰的魔术函数?
【问题讨论】:
-
这有点不寻常,因为您允许构造函数分配任意私有变量。如果构造函数可以给这些变量任何值,为什么还要将它们设为私有呢?您可以使用具有默认值的命名关键字参数来分配这些吗?
-
@MichaelAaronSafyan 这就是我最初所做的,但后来我想扩展 T 以获取任何 kwarg,并考虑在 init 但不允许 S 访问这些成员中的任何一个(因为 S 在调用 T.__init__(self, **kwargs) S 之前可以看到 kwargs 可能会破坏东西)。
-
此时,我仍在编写代码,所以我想看看这是否可行,如果不可行,我可能会改用
def __init__(self, x=1, y=2):之类的东西。 -
来自文档:“请注意,传递给 exec、eval() 或 execfile() 的代码不会将调用类的类名视为当前类;这类似于global 语句,其效果同样仅限于字节编译在一起的代码。同样的限制适用于 getattr()、setattr() 和 delattr(),以及直接引用 dict 时。”这说明了为什么
exec和setattr不起作用......虽然我不知道解决方案。 -
错位名称在函数的代码对象中硬编码。我尝试使用
compile,但它保留了未损坏的名称。
标签: python attributes private-members name-mangling