2012-09-20 9 views
12

Ich weiß, was Doppel-Unterstrich für Python-Klasse Attribute/Methoden bedeutet, aber bedeutet es etwas für Methode Argument?Doppelter Unterstrich für Python-Methode * Argument *

Es sieht so aus, als ob Sie kein Argument übergeben können, das mit einem doppelten Unterstrich zu Methoden beginnt. Es ist verwirrend, weil Sie das für normale Funktionen tun können.

Betrachten Sie dieses Skript:

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) 

dieses Skript Ausbeuten Laufen:

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' 

ich diese 2.7.2 mit Python überprüft.


Einige andere Beispiele

Dies funktioniert:

def egg(self, __a): 
    return __a 


class Spam(object): 

    egg = egg 

Spam().egg(__a=1) 

Dies gilt nicht:

class Spam(object): 

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

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

Spam().egg(1) 

Antwort

12

Namen Mangeln mit führenden doppelten Unterstrichen für alle Kennungen gilt, regardless of where they occur (zweite bis letzter Satz in diesem Abschnitt):

Diese Umwandlung ist unabhängig vom syntaktischen Kontext, in dem der Bezeichner verwendet wird.

Dies ist einfacher zu implementieren und zu definieren und konsistenter. Es mag dumm erscheinen, aber der ganze Name Mangling Deal ist ein hässlicher kleiner Hack IMHO; und es wird nicht erwartet, dass Sie solche Namen für irgendetwas außer Attribute/Methoden verwenden.

Spam().egg(_Spam__a=1), sowie Spam().egg(1), funktioniert. Aber auch wenn Sie es schaffen können, haben führende Unterstriche (beliebig viele) keinen Platz in Parameternamen. Oder in jeder lokalen Variablen (Ausnahme: _).

Bearbeiten: Sie scheinen einen Eckfall gefunden zu haben, den niemand jemals in Betracht gezogen hat. Die Dokumentation ist hier ungenau oder die Implementierung ist fehlerhaft. Es scheint, dass Schlüsselwortargumentnamen nicht fehlerhaft sind. Schauen Sie sich die Bytecode (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 

Dies wurzelt in der Tatsache sein, dass Keyword-Argumente äquivalent sind ein dict vorbei (in diesem Fall {'__a': 1}), deren Schlüssel nicht entweder verstümmelt werden. Aber ehrlich gesagt, würde ich es in einem ohnehin hässlichen Sonderfall nur als hässlichen Eckfall bezeichnen und weitermachen. Es ist nicht wichtig, weil Sie solche Identifikatoren sowieso nicht verwenden sollten.

+0

Wenn es passiert „unabhängig davon, wo sie auftreten“, erwarte ich das letzte Beispiel (die, die ich hinzugefügt) arbeitet. Ich denke, ich weiß, warum es nicht so ist; es sollte im "Class Namespace" oder so ähnlich sein (ich weiß nicht, was das richtige Wort dafür ist), oder? – tkf

+0

Das würde ich auch erwarten und bin ziemlich überrascht. Ich denke, es ist ein Fehler in der Dokumentation oder der Implementierung. Ich bearbeite gerade, um meine Ergebnisse hinzuzufügen. – delnan

+0

Ich stimme zu, dass es kein eleganter Parameter ist, aber bedenken Sie, wenn Sie etwas wie 'self .__ dict __. Update (kwds)' in der Funktion haben, aber das Verhalten der Funktion steuern wollen. Der einzige gültige Argumentname, den ich mir vorstellen kann, um das Verhalten zu steuern, ist der mit einem doppelten Unterstrich. – tkf

3

Es zu _Spam__a umgewandelt wird:

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') 
1

Doppel Unterstrichen oder Name Mangling in einem Klassenkontext ist eine private Kennung. In Ihrem Beispiel versuchen Sie dir (Spam.egg) und Sie werden sehen, dass der Parameter __a jetzt _Spam__egg ist.

Sie können nun:

Spam().egg(_Spam__a=1)