13

我知道双下划线对 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)
4

3 回答 3

13

名称修改适用于所有带有前导双下划线的标识符,无论它们出现在哪里(该部分中倒数第二句):

此转换与使用标识符的语法上下文无关。

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

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}),其键也不会被破坏。但老实说,我只是在一个已经很丑的特殊情况下称它为一个丑陋的角落案例,然后继续前进。这并不重要,因为无论如何您都不应该使用这样的标识符。

于 2012-09-20T17:43:59.490 回答
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')
于 2012-09-20T17:44:23.510 回答
1

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

您现在可以使用:

Spam().egg(_Spam__a=1)
于 2012-09-20T17:51:56.187 回答