2013-04-22 12 views
5

Po pierwsze, istnieje klasa A z dwóch zmiennych klasowych i dwóch zmiennych instancji:Jaka jest różnica między zmiennymi klasowymi różnych typów?

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 

Widzimy, że obie klasy zmienna i instancja zmiennej typu int działa dobrze:

In [3]: a = A() 

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

Jednak sytuacja zmieniły się, jeśli sprawdzimy zmienne typu funkcji:

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) 

Wiem, że python przetłumaczył a.cfun(1,2) do A.cfun(a,1,2), a następnie błąd został zgłoszony.

Moje pytanie jest: Ponieważ zarówno cvar, jak i cfun są zmiennymi klasy, dlaczego Python traktować je w różny sposób?

+0

'ifun' jest podpisem pola obiektu' a', nie jest to metoda obiekt/klasa. Aby powiązać go z obiektem, użyj 'a.ifun = types.MethodType (fun, a)' – kalgasnik

+1

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

Odpowiedz

3

Właściwie, to funkcja przypisana do członka klasy pozostaje funkcja:

def x():pass 

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

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

To konwertowane w locie do obiektu metody można odzyskać z instancji:

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 -definiowane metody ":

Zdefiniowane przez użytkownika obiekty metod mogą zostać utworzone podczas pobierania atrybutów bute klasy (być może poprzez instancję tej klasy), jeśli ten atrybut jest obiektem zdefiniowanym przez użytkownika, niezwiązanym obiektem metody zdefiniowanym przez użytkownika lub obiektem klasy ... Zwróć uwagę, że transformacja z obiektu funkcji do() niezwiązany lub związany) obiekt metody dzieje się za każdym razem, gdy atrybut jest pobierany z klasy lub instancji.

Ta konwersja dotyczy tylko funkcji przypisanych do klasy, a nie do instancji. Zauważ, że zostało to zmienione w Pythonie 3, gdzie Class.fun zwraca normalną funkcję, a nie "niezwiązaną metodę".

Co do pytania, dlaczego jest to potrzebne, obiekt metody jest zasadniczo zamknięciem, które zawiera funkcję wraz z kontekstem wykonawczym ("self"). Wyobraź sobie, że masz obiekt i użyj jego metody jako callbacka gdzieś. W wielu innych językach trzeba przekazać zarówno wskaźniki obiektu i metody, jak i ręcznie utworzyć zamknięcie. Na przykład, w javascript:

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

Python udaje, że dla nas za kulisami:

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

Z drugiej strony, czasami jest to praktyczne, aby mieć „gołe” funkcje lub „obcych” metod w klasy:

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

Powyższa konwencja (klasa vars => metod przykład vars => funkcje) stanowi dogodny sposób na oba.

Nie trzeba dodawać, tak jak wszystko inne w Pythonie, można zmienić to zachowanie, tj. Napisać klasę, która nie konwertuje swoich funkcji na metody i zwraca je w niezmienionej formie.

+0

Tak, Python czy domyślnie traktuje się typ wywoływalny i niemożliwy w różny sposób w zmiennej Klasy i zmiennej instancji? – Eastsun

+0

@Eastsun: tak, to jest domyślne zachowanie. – georg

+0

Dzięki za pomoc! – Eastsun