2014-01-20 238 views
1

我想了解python作用域规则。要做到这一点,我尝试同一模块访问私人模块变量从类

bar = "bar" 
_bar = "underscore" 
__bar = "double underscore" 

def foo(): 
    print bar 
    print _bar 
    print globals()["__bar"] 
    print __bar 

class Foo: 
    def __init__(self): 
     print bar 
     print _bar 
     print globals()["__bar"] 
     print __bar #NameError: global name '_Foo__bar' is not defined 

foo() 
Foo() 

它失败NameError在访问从类“非常私人”的变量。我无法在规范中找到任何有关这方面的信息。那么,为什么它失败了,这种行为在哪里描述?

+0

你可以发布完整的输出吗?还是完整的异常消息? –

+0

是的,删除是因为 - 我惊讶地发现 - 即使使用独立名称__bar也会发生这种情况。您从文档发布的报价并没有明确说明。 –

+0

@DanielRoseman:*当在类定义中文本出现的标识符*和*这种转换独立于使用标识符的语法上下文*这包括任何在类体中任何地方都是标识符的标识符,包括方法定义。无论它是属性,全局还是本地都无所谓。 –

回答

3

在一个类定义中,所有名称为的起始都带有双下划线;重写为包括类名作为前缀。

这是一个功能,支持在类中标记名称为'private',并防止它被子类覆盖。看到identifiers documentation

私人名称重整:当该文本方式发生在类定义的标识符具有两个开始或多个下划线字符,并在两个或多个下划线并没有结束,它被认为是一个专用名称那个班。在为其生成代码之前,专用名称会转换为更长的形式。该转换将在名称前插入类名,并删除前导下划线和插入的单个下划线。例如,名为Ham的类中出现的标识符__spam将转换为_Ham__spam。这种转换独立于使用标识符的语法上下文。如果转换的名称非常长(超过255个字符),则可能会发生实现定义的截断。如果类名只包含下划线,则不进行转换。

最好不要在模块全局变量上使用双下划线前缀;没有必要这样做,单个下划线就足以说明该值是模块内部的。

如果您遇到这样的值,请创建一个没有损坏的别名,或使用globals()[name]

+0

那么如何才能从课堂内部获得双重得分常数? 'globals()['__ bar']'看起来有点怪异。 –

+1

@PauloBu:或者使用'sys.modules [__ name __] .__ bar' ...最好不要使用双下划线名称作为全局变量,真的。 –

+0

是的,这是我的想法:) –