我知道大多数人留下来的 exec 不应该被使用,但我有一些问题。
这是最小的例子,有效:
class A:
def __init__(self):
exec('self.a = self.funct()')
def funct(self):
return 1
def ret(self):
return self.a
> obj = A()
> obj.ret()
1
但是,当我这样做时:
class A:
def __init__(self):
exec('self.a = self.__funct()')
def __funct(self):
return 1
def ret(self):
return self.a
> obj = A()
AttributeError: 'A' has no attribute '__funct'
有人知道为什么会有这种差异吗?
答案 0 :(得分:3)
__name
名称 class private ;这些名称在编译时以另一个下划线和类名称作为前缀。目的是保护名称免受与子类中使用的名称的意外冲突。这些名称不意味着对外部呼叫者是私有的。
引用Reserved classes of identifiers section:
__*
类私有名称。当在类定义的上下文中使用时,此类别中的名称将被重写以使用损坏的表单来帮助避免基类和派生类的“私有”属性之间的名称冲突。
私有名称修改:当在类定义中以文本方式出现的标识符以两个或多个下划线字符开头且不以两个或多个下划线结尾时,它被视为该类的私有名称。在为其生成代码之前,将私有名称转换为更长的形式。转换将在名称前面插入类名,删除前导下划线并插入单个下划线。例如,名为
__spam
的类中出现的标识符Ham
将转换为_Ham__spam
。此转换独立于使用标识符的语法上下文。
在您的情况下,exec()
推迟编译,有效地编译隔离。类上下文消失了,因此不会发生错位。
因此,您需要手动应用自动前缀:
exec('self.a = self._A__funct()')
如果您使用的是Python 3,则可以使用__class__
闭包normally available for the super()
function来访问为当前方法定义的类名:
exec('self.a = self._{0.__name__}__funct()'.format(__class__))
现在,除非你真的计划在第三方代码中广泛地继承类,而不必担心与内部实现细节的意外冲突,否则你不应该使用双下划线名称。坚持使用单下划线名称。
答案 1 :(得分:0)
Python私有方法是"伪装"在与代码中指定的标识符不同的标识符下,您可以像_classname__privateAttribute一样访问它们。
将此内容公布为具体:
class A:
def __init__(self):
exec('self.a = self._A__funct()')
def __funct(self):
print("Hello")
def ret(self):
return self.a
obj = A()
我把打印答案放在那里以检测它是否有效,它确实有效!