2013-03-03 25 views
19

Chciałbym zbudować metodę wewnątrz klasy z domyślnymi argumentami wartości zaczerpniętymi z tej klasy. Ogólnie filtruję niektóre dane. Wewnątrz mojej klasy mam metodę, w której normalnie przekazuję wektor danych. Czasami nie mam wektora i biorę symulowane dane. Za każdym razem, gdy nie przekazuję konkretnego wektora, domyślnie chciałbym pobrać symulowane dane. Pomyślałem, że powinna to być łatwa konstrukcja, w której w mojej metodzie definicji mówię: a=self.vector. Ale z jakiegoś powodu mam błąd NameError: name 'self' is not defined. Uproszczona konstrukcja jest:przypisywanie zmiennej klasy jako wartości domyślnej do argumentu metody klasy

class baseClass(object): # This class takes an initial data or simulation 
    def __init__(self): 
     self.x = 1 
     self.y = 2 

class extendedClass(baseClass): # This class does some filtering 
    def __init__(self): 
     baseClass.__init__(self) 
     self.z = 5 
    def doSomething(self, a=self.z): 
     self.z = 3 
     self.b = a 

if __name__ == '__main__': 
    a = extendedClass() 
    print a.__dict__ 
    a.doSomething() 
    print a.__dict__ 

Wyjście Spodziewałem powinno być:

{'y': 2, 'x': 1, 'z': 5} 
{'y': 2, 'x': 1, 'z': 3, 'b': 5} 

Próbowałem domyślne przypisanie jako def doSomething(self, a=z): oczywiście nie działa zawsze. O ile rozumiem self.z jest widoczny w tym zakresie i nie powinno być problemu z jego domyślną wartością. Nie wiem, dlaczego mam ten błąd i jak to zrobić. Jest to prawdopodobnie łatwe pytanie, ale staram się to rozgryźć lub znaleźć rozwiązanie bez żadnego braku na jakiś czas. Znalazłem similar pytań tylko dla innych języków.

Odpowiedz

25

Twoje zrozumienie jest złe. self sam jest parametrem tej definicji funkcji, więc nie ma możliwości, aby mógł być w tym punkcie. Jest tylko w zasięgu samej funkcji.

Odpowiedź jest po prostu domyślne argumentu do None, a następnie sprawdzić, że wewnątrz metody:

def doSomething(self, a=None): 
    if a is None: 
     a = self.z 
    self.z = 3 
    self.b = a 
+0

Jeśli argument nie może przyjąć wartości falsy, powinieneś po prostu napisać 'if a: a = self.z' lub nawet' a = a lub self.z'. – danijar

+0

Myślę, że masz na myśli 'if not a: a = self.z' – BBischof

+0

Czy jest to standardowy wzorzec pytonowy, tj. Mający właściwość klasy z wartością domyślną, która jest używana jako fallback z opcjonalnej właściwości metody? Czy lepiej zmienić konstruktor 'extendedClass' __init__ tak, aby zawierał opcjonalną własność' z = None', a jeśli 'None' ustawi ją jako domyślną w metodzie, a nie jako parametr metody? Mogę tylko myśleć, że posiadanie zakodowanej klasy własności jest użyteczne, jeśli tak naprawdę jest stałą i wymaganą przez więcej niż jedną metodę, w przeciwnym razie dlaczego nie wystarczy ograniczyć 'z' do zakresu metody, może bez klasy lub obiektu własność w ogóle? – Davos

6

Oto demontaż kodu dla prostego przykładowego modułu. Obiekt kodu jest kontenerem tylko do odczytu dla kodu bajtowego, stałych i nazw, których używa, oraz metadanych dotyczących liczby zmiennych lokalnych, wymaganego rozmiaru stosu itp. Należy zauważyć, że wszystkie obiekty kodu są kompilowane jako stałe. Są one tworzone w czasie kompilacji. Ale obiekty są tworzone w czasie wykonywania (na przykład, gdy moduł jest importowany).

Aby klasę, BUILD_CLASS przyjmuje nazwę 'A', podstawy tuple(object,) i dict który zawiera atrybuty przestrzeni nazw klasy. To jest jak ręczne tworzenie instancji typu przez wywołanie type(name, bases, dict). Aby utworzyć dict, funkcja jest tworzona z obiektu kodu A i wywoływana. Na koniec obiekt klasy jest przechowywany w przestrzeni nazw modułu poprzez STORE_NAME.

W obiekcie kodu A, self.z jest ładowany na stos jako argument do MAKE_FUNCTION. Kod bajtowy op LOAD_NAME wyszuka self w bieżących locals (tj. Definiowana przestrzeń nazw klasy), globale modułu i wbudowane. To oczywiście nie powiedzie się, jeśli self nie jest zdefiniowany w zasięgu globalnym lub wbudowanym; wyraźnie nie jest zdefiniowany w zakresie lokalnym.

Jeśli jednak się to uda, funkcja zostanie utworzona z (self.z,) jako jej atrybut __defaults__, a następnie zapisana pod lokalną nazwą test.

>>> code = compile(''' 
... class A(object): 
... def test(self, a=self.z): pass 
... ''', '<input>', 'exec') 

>>> dis.dis(code) 
    2   0 LOAD_CONST    0 ('A') 
       3 LOAD_NAME    0 (object) 
       6 BUILD_TUPLE    1 
       9 LOAD_CONST    1 (<code object A ...>) 
      12 MAKE_FUNCTION   0 
      15 CALL_FUNCTION   0 
      18 BUILD_CLASS   
      19 STORE_NAME    1 (A) 
      22 LOAD_CONST    2 (None) 
      25 RETURN_VALUE 

>>> dis.dis(code.co_consts[1]) # code object A 
    2   0 LOAD_NAME    0 (__name__) 
       3 STORE_NAME    1 (__module__) 

    3   6 LOAD_NAME    2 (self) 
       9 LOAD_ATTR    3 (z) 
      12 LOAD_CONST    0 (<code object test ...>) 
      15 MAKE_FUNCTION   1 
      18 STORE_NAME    4 (test) 
      21 LOAD_LOCALS   
      22 RETURN_VALUE  

@uselpa: Twoja wklejarka przykład (przepisany na 2.x):

>>> code = compile(''' 
... default = 1 
... class Cl(object): 
...  def __init__(self, a=default): 
...   print a 
... Cl() 
... default = 2 
... Cl() 
... ''', '<input>', 'exec') 
>>> dis.dis(code) 
    2   0 LOAD_CONST    0 (1) 
       3 STORE_NAME    0 (default) 

    3   6 LOAD_CONST    1 ('Cl') 
       9 LOAD_NAME    1 (object) 
      12 BUILD_TUPLE    1 
      15 LOAD_CONST    2 (<code object Cl ...>) 
      18 MAKE_FUNCTION   0 
      21 CALL_FUNCTION   0 
      24 BUILD_CLASS   
      25 STORE_NAME    2 (Cl) 

    6   28 LOAD_NAME    2 (Cl) 
      31 CALL_FUNCTION   0 
      34 POP_TOP    

    7   35 LOAD_CONST    3 (2) 
      38 STORE_NAME    0 (default) 

    8   41 LOAD_NAME    2 (Cl) 
      44 CALL_FUNCTION   0 
      47 POP_TOP    
      48 LOAD_CONST    4 (None) 
      51 RETURN_VALUE   

Jak widać, klasa obiektu Cl (i funkcja obiektu __init__) jest tworzony tylko i zapisywane do lokalnej nazwy 'Cl' jeden raz. Moduł wykonuje sekwencyjnie w czasie wykonywania, więc ponowne przypisanie nazwy default nie będzie miało wpływu na domyślną wartość w __init__.

Można dynamicznie wystąpienia nowej funkcji przy użyciu wcześniej skompilowany kod i nową wartość domyślną:

>>> default = 1 
>>> class Cl(object): 
...  def __init__(self, a=default): 
...   print a 
... 

>>> from types import FunctionType 
>>> default = 2 
>>> Cl.__init__ = FunctionType(
... Cl.__init__.__code__, globals(), '__init__', (default,), None) 
>>> c = Cl() 
2 

to ponowne wykorzystanie już skompilowany obiekt kodu z __init__.__code__ aby utworzyć funkcję z nowym __defaults__ krotki:

>>> Cl.__init__.__defaults__ 
(2,) 
+1

Utknąłem. Jeśli klasa i metoda są tworzone w czasie tworzenia instancji, dlaczego nie są oczywiście w moim przykładzie na http://pastebin.com/UJfMpnqW? – uselpa

+0

@uselpa: Dodałem twój przykład, aby, mam nadzieję, wyjaśnić różnicę między "czasem kompilacji" i "czasem uruchomienia". Moduł może się kompilować dobrze bez błędów składniowych, ale nadal ma błędy w czasie wykonywania po zaimportowaniu (wykonane). – eryksun

+0

Myślę, że rozumiem. Bardzo dziękuję za cierpliwość! – uselpa

Powiązane problemy