Python方法*参数*的双下划线

时间:2012-09-20 17:38:19

标签: python

我知道双重下划线对Python类属性/方法意味着什么,但它是否意味着方法参数?

看起来你不能将以双下划线开头的参数传递给方法。这很令人困惑,因为你可以为正常的功能做到这一点。

考虑这个脚本:

def egg(__a=None):
    return __a

print "egg(1) =",
print egg(1)
print


class Spam(object):

    def egg(self, __a=None):
        return __a

print "Spam().egg(__a=1) =",
print Spam().egg(__a=1)

运行此脚本会产生:

egg(1) = 1

Spam().egg(__a=1) =
Traceback (most recent call last):
  File "/....py", line 15, in <module>
    print Spam().egg(__a=1)
TypeError: egg() got an unexpected keyword argument '__a'

我用Python 2.7.2检查了这个。


其他一些例子

这有效:

def egg(self, __a):
    return __a


class Spam(object):

    egg = egg

Spam().egg(__a=1)

这不是:

class Spam(object):

    def _egg(self, __a=None):
        return __a

    def egg(self, a):
        return self._egg(__a=a)

Spam().egg(1)

3 个答案:

答案 0 :(得分:13)

名称修改适用于具有前导双下划线的所有标识符regardless of where they occur(该部分中倒数第二句):

  

此转换独立于使用标识符的语法上下文。

这更容易实现和定义,并且更加一致。这可能看起来很愚蠢,但整个名字的整理交易是一个丑陋的小黑客恕我直言;并且除了属性/方法之外,你不应该使用这样的名字。

Spam().egg(_Spam__a=1)以及Spam().egg(1)确实有效。但即使你可以使它工作,前导下划线(任意数量)在参数名称中没有位置。或者在任何局部变量(例外:_)中。

编辑:您似乎找到了一个没有人考虑的角落案例。这里的文档不精确,或者实现有缺陷。它出现的关键字参数名称不会被破坏。查看字节码(Python 3.2):

>>> dis.dis(Spam.egg)
  3           0 LOAD_FAST                0 (self)
              3 LOAD_ATTR                0 (_egg)
              6 LOAD_CONST               1 ('__a') # keyword argument not mangled
              9 LOAD_FAST                1 (a)
             12 CALL_FUNCTION          256
             15 RETURN_VALUE
>>> dis.dis(Spam._egg)
  2           0 LOAD_FAST                1 (_Spam__a) # parameter mangled
              3 RETURN_VALUE

这可能源于这样一个事实:关键字参数等同于传递一个dict(在这种情况下为{'__a': 1}),其键也不会被破坏。但老实说,我只是把它称为一个丑陋的角落案件,在一个已经很丑陋的特殊情况下继续前进。这并不重要,因为你不应该使用这样的标识符。

答案 1 :(得分:3)

它会转换为_Spam__a

In [20]: class Spam(object):
   ....:     
   ....:         def egg(self, __a=None):
   ....:             return __a
   ....: 

In [21]: Spam.egg.__func__.__code__.co_varnames
Out[21]: ('self', '_Spam__a')

答案 2 :(得分:1)

类上下文中的双下划线或Name Mangling是私有标识符。在您的示例中尝试dir(Spam.egg),您将看到参数__a现在是_Spam__egg

您现在可以使用:

Spam().egg(_Spam__a=1)