2013-04-22 5 views
5

Erstens gibt es Klasse A mit zwei Klassenvariablen und zwei Instanzvariablen:Was ist der Unterschied zwischen Klassenvariablen verschiedener Typen?

In [1]: def fun(x, y): return x + y 

In [2]: class A: 
    ...:  cvar = 1 
    ...:  cfun = fun 
    ...:  def __init__(self): 
    ...:   self.ivar = 100 
    ...:   self.ifun = fun 

Wir können sehen, dass beide Klassenvariablen und Instanzvariable von Typ int funktioniert:

In [3]: a = A() 

In [4]: a.ivar, a.cvar 
Out[4]: (100, 1) 

jedoch Dinge geändert haben, wenn wir die Funktion Typ Variablen überprüfen:

In [5]: a.ifun, a.cfun 
Out[5]: 
(<function __main__.fun>, 
<bound method A.fun of <__main__.A instance at 0x25f90e0>>) 

In [6]: a.ifun(1,2) 
Out[6]: 3 

In [7]: a.cfun(1,2) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
/home/future/<ipython-input-7-39aa8db2389e> in <module>() 
----> 1 a.cfun(1,2) 

TypeError: fun() takes exactly 2 arguments (3 given) 

ich gewusst, dass pythonübersetztbis A.cfun(a,1,2) und dann Fehler ausgelöst.

Meine Frage ist: Da sowohl cvar und cfun Klasse variabel sind, warum Python sie Unterschied Art und Weise behandeln?

+0

'ifun' ist aufrufbares Feld des Objekts' a', es ist keine Objekt/Klassenmethode. Um es an ein Objekt zu binden, benutze 'a.ifun = types.MethodType (fun, a)' – kalgasnik

+1

http://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object – kalgasnik

Antwort

3

Eigentlich eine Funktion einer Klasse Mitglied zugewiesen bleibt Funktion:

def x():pass 

class A: 
    f = x 
    e = None 
    g = None 

print(A.__dict__['f']) 
# <function x at 0x10e0a6e60> 

Es on the fly auf ein Verfahren Objekt umgewandelt wird, wenn Sie es von einer Instanz abrufen:

print(A().f) 
# <bound method A.x of <__main__.A instance at 0x1101ddea8>> 

http://docs.python.org/2/reference/datamodel.html#the-standard-type-hierarchy „User "definierte Methoden":

Benutzerdefinierte Methodenobjekte können beim Abrufen eines Attributs erstellt werden bute einer Klasse (möglicherweise über eine Instanz dieser Klasse), wenn dieses Attribut ein benutzerdefiniertes Funktionsobjekt, ein ungebundenes benutzerdefiniertes Methodenobjekt oder ein Klassenmethodenobjekt ist ... Beachten Sie, dass die Transformation vom Funktionsobjekt in (ungebunden oder gebunden) Das Methodenobjekt wird jedes Mal ausgeführt, wenn das Attribut von der Klasse oder Instanz abgerufen wird.

Diese Konvertierung tritt nur bei Funktionen auf, die einer Klasse und nicht einer Instanz zugewiesen sind. Beachten Sie, dass dies in Python 3 geändert wurde, wobei Class.fun eine normale Funktion und keine "ungebundene Methode" zurückgibt.

In Bezug auf Ihre Frage, warum dies erforderlich ist, ist ein Methodenobjekt im Wesentlichen eine Closure, die eine Funktion zusammen mit ihrem Ausführungskontext ("self") enthält. Stellen Sie sich vor, Sie haben ein Objekt und verwenden seine Methode als Callback. In vielen anderen Sprachen müssen Sie sowohl Objekt- als auch Methodenzeiger übergeben oder manuell eine Schließung erstellen. Zum Beispiel in javascript:

myListener = new Listener() 
    something.onSomeEvent = myListener.listen // won't work! 
    something.onSomeEvent = function() { myListener.listen() } // works 

Python verwaltet das für uns hinter den Kulissen:

myListener = Listener() 
    something.onSomeEvent = myListener.listen // works 

Auf der anderen Seite, manchmal ist es praktisch „nackte“ Funktionen oder „fremde“ Methoden in einem haben Klasse:

def __init__(..., dir, ..): 
     self.strip = str.lstrip if dir == 'ltr' else str.rstrip 
     ... 
    def foo(self, arg): 
     self.strip(arg) 

Die obige Konvention (Klasse vars => Methoden, zB vars => Funktionen) bietet eine bequeme Möglichkeit, beides zu haben.

Unnötig hinzuzufügen, wie alles andere in Python, ist es möglich, dieses Verhalten zu ändern, d. H. Eine Klasse zu schreiben, die ihre Funktionen nicht in Methoden konvertiert und sie so zurückgibt wie sie ist.

+0

Also, Python Behandle aufrufbare und nicht aufrufbare Typen in unterschiedlicher Weise in Klassenvariablen und Instanzvariablen standardmäßig? – Eastsun

+0

@Eastsun: Ja, das ist das Standardverhalten. – georg

+0

Danke für Ihre Hilfe! – Eastsun

Verwandte Themen