2012-08-04 12 views
5

Czy istnieją dobre (nadaje się do stosowania w rzeczywistych projektach) sposobów lub zmniejszenie boilerplate w takie rzeczyJak uniknąć bojownika podczas używania super (...) w Pythonie 2.6+?

class B(A): 
    def qqq(self): # 1 unwanted token "self" 
     super(B, self).qqq() # 7 unwanted tokens plus 2 duplications ("B", "qqq") 
     do_something() 

chcę wyglądać mniej więcej tak:

class B(A): 
    def qqq: 
     super 
     do_something() 

lub (bardziej realistycznie)

class B(A): 
    @autosuper_before 
    def qqq(self): 
     do_something() 

Czy jest to możliwe w Pythonie 2.6+ bez jawnych hacków?

@link super() in Python 2.x without args

+4

Nie ma sensu walczyć z parametrem 'self'. Jawność jest lepsza niż domniemana, specjalne przypadki nie są na tyle szczególne, aby złamać zasady, yadda yadda yadda. Poza tym, jak często nadpisujesz metodę bez parametrów i nic nie robisz przed wywołaniem następnej implementacji? – delnan

+0

Co masz na myśli przez "jawne hacki"? – BrenBarn

+0

@BrenBarn, "Overt hacks" oznacza tutaj "Kod staje się trochę prostszy za cenę masowego spowolnienia lub brzydkich śladów czy czegoś nieprzyjemnego". –

Odpowiedz

4

tl; dr

Jak powiedział OP "Czy to możliwe, w Pythonie 2.6+ bez jawnych hacki?", Odpowiedź brzmi: nr

Długa wersja:

Możesz zrobić prosty dekorator, który wywoła ne rodzic xt tą metodą. Problem polega na tym, że nie będziesz mieć kontroli nad argumentami, które chcesz przekazać.

Edit: To nie będzie działać dla podklasy już używają autosuper ponieważ będzie ona wybrała niewłaściwą klasę i zrobić nieskończoną pętlę.

def autosuper(fn): 
    def f(self, *args, **kw): 
     cl = super(type(self), self) 
     getattr(cl, fn.__name__)(*args, **kw) 
     return fn(self, *args, **kw) 
    return f 

Jak można to zrobić? Python 3.x ma funkcję super, która nie przyjmuje żadnych argumentów!

unfortunally, Python 3.x na super jest klasa i w tym samym czasie kluczowe, bo tylko obecność jego nazwa zmieni bieżący środowiska odsłonić zmienną o nazwie __class__ że jest prawo klasa, której potrzebujesz użyć!

Jeśli zaznaczysz ramkę wewnątrz funkcji zadeklarowanej w klasie, nie ma zmiennej __class__, a atrybut co_freevars atrybutu ramki f_code jest pusty. Gdy napiszesz nazwę super (nie musisz tego wywoływać), ciąg znaków __class__ pojawi się w co_freevars, co oznacza, że ​​pochodzi z innego zamknięcia. Ponadto, jeśli spróbujesz uzyskać dostęp do zmiennej __class__ bez użycia super, użyje ona LOAD_DEFER kodu bajtowego z tego samego powodu zamiast LOAD_GLOBAL, podobnie jak normalne dla każdej niezdefiniowanej nazwy.

To jest tak szalone, że nie można po prostu wykonać hyper = super i wywołać tej nowej zmiennej hyper bez argumentów (to dokładnie ten sam obiekt co super).

Ponieważ nie może konkurować z tym dużo czarnej magii wewnątrz interpreter Pythona, a ponieważ autosuper dekorator nie jest zadeklarowana wewnątrz klasy (tak to może nie uzyskać dostępu do __class__ zmienną nawet jeśli to było możliwe w Pythonie 2.x), nie będę starał się napisać nowego dekoratora i pozostawi tę odpowiedź tutaj jako ostrzeżenie dla innych ludzi, którzy chcą to zrobić.

Prawdopodobnie można zrobić kilka hackerów, aby znaleźć odpowiednią klasę do wykorzystania, ale nie będę kopał aż tak daleko. Rzeczy do wzięcia pod uwagę:

  • Po nałożeniu dekoratora klasa jeszcze nie istnieje, więc należy to zrobić, gdy wywoływana funkcja zostanie wywołana.
  • Funkcja, która ma być dekorowana, nie jest jeszcze wersją unbound method (która została usunięta mimo to z Py3k), więc nie można sprawdzić atrybutu im_class.
  • Rama wydaje się nie posiadać żadnych informacji klasy wykorzystywane do wytwarzania tego połączenia (o ile oczywiście zmienna __class__ istnieją i to jest możliwe, aby uzyskać odwołanie do niego)
  • This answer dostarczone przez OP jest również dość zepsuty, ponieważ ma wiele złych założeń i ma problemy z dekorowanymi funkcjami.
+0

(Po prostu zapominam o dodawaniu "siebie" raz za razem. (Zapominając o zmianie argumentów lub "super" w wielu metodach, gdy zmieniam nazwę klasy lub nazwę metody). –

+0

Czy to działa dość szybko? Wygląda trochę jak refleksja Javy, która mówi się, że jest wolna.Czy "odbicie" można przenieść z "f" (aby utrzymać lekkość) na "autosuper" i pozwolić "f" na wywołanie już przygotowanej rzeczy? (Właściwie to chcę coś takiego jak makra Lispa, które dodadzą automatycznie "super (...)" linię) –

+0

@Vi Java Reflection używa podobnej składni, ale bardzo różni się od dekoratorów, po prostu doda jedno dodatkowe wywołanie funkcji. BTW, zmieniłem kod używaj ± cy funkcji 'super' zamiast pisać własne – JBernardo

Powiązane problemy