Подтвердить что ты не робот

Двойное подчеркивание для метода Python * аргумент *

Я знаю, что означает двойное подчеркивание для атрибутов/методов класса Python, но означает ли это что-то для аргумента метода?

Похоже, вы не можете передать аргумент, начинающийся с двойного подчеркивания методам. Это запутанно, потому что вы можете сделать это для обычных функций.

Рассмотрим этот script:

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)

Запуск этого script дает:

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)
4b9b3361

Ответ 1

Мелодия имени применяется ко всем идентификаторам с ведущими двойными символами подчеркивания независимо от того, где они происходят (от второго до последнего предложения в этом разделе):

Это преобразование не зависит от синтаксического контекста, в котором используется идентификатор.

Это проще реализовать, определить и более согласованно. Это может показаться глупым, но всякое изъявление названия - уродливый маленький взлом ИМХО; и вы не собираетесь использовать такие имена для чего-либо, кроме атрибутов/методов, в любом случае.

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}), ключи которого тоже не будут искажены. Но, честно говоря, я бы назвал это уродливым угловым делом в уже уродливом частном случае и продолжил. Это не важно, потому что вы все равно не должны использовать такие идентификаторы.

Ответ 2

Он преобразуется в _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')

Ответ 3

Double Underscore или Name Mangling в контексте класса является частным идентификатором. В вашем примере попробуйте dir (Spam.egg), и вы увидите, что параметр __a теперь _Spam__egg.

Теперь вы можете использовать:

Spam().egg(_Spam__a=1)