【问题标题】:'exec' not working with private method Python'exec' 不使用私有方法 Python
【发布时间】:2017-05-29 00:02:48
【问题描述】:

我知道你们中的大多数人都留下来不应该使用 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'

有人知道为什么会有这种差异吗?

【问题讨论】:

  • 请注意,__ 名称是 class 私有的。这与其他语言的隐私模型不同。

标签: python class exec private


【解决方案1】:

__name 名称是类私有;此类名称在编译时以另一个下划线和类名作为前缀。目的是防止名称与子类中使用的名称发生意外冲突。这些名称​​不对外部呼叫者保密。

引用Reserved classes of identifiers section

__*
类私有名称。此类别中的名称在类定义的上下文中使用时,会被重写以使用重整形式,以帮助避免基类和派生类的“私有”属性之间的名称冲突。

还有Identifiers (Names) section:

私有名称修改:当以文本形式出现在类定义中的标识符以两个或多个下划线字符开头并且不以两个或多个下划线结尾时,它被视为该类的私有名称.在为私有名称生成代码之前,私有名称会转换为更长的形式。转换插入类名,删除前导下划线并在名称前面插入一个下划线。例如,出现在名为Ham 的类中的标识符__spam 将转换为_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__))

现在,除非您确实计划在第三方代码中广泛地对您的类进行子类化,而不必担心与内部实现细节发生意外冲突,否则您根本不应该使用双下划线名称。改用单下划线名称。

【讨论】:

    【解决方案2】:

    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()
    

    我将打印答案放在那里以检测它是否有效,并且确实有效!

    【讨论】:

      猜你喜欢
      • 2018-02-27
      • 2018-04-25
      • 2013-06-16
      • 2011-12-08
      • 1970-01-01
      • 1970-01-01
      • 2010-09-09
      • 1970-01-01
      相关资源
      最近更新 更多