2011-11-30 11 views
9

Właśnie zauważyłem, że można to zrobić w Pythonie:Czy metody bezklasowe w Pythonie są przydatne do czegokolwiek?

def f(self): 
    print self.name 

class A: 
    z=f 
    name="A" 

class B: 
    z=f 
    name = "B" 

...

print a.z() 

>>> A 

Innymi słowy, f() zachowuje się jak metody, które nie są zdefiniowane w każdej klasie, ale może być dołączony do jeden. I oczywiście spowoduje błąd runtime, jeśli oczekuje metod lub pól na obiekcie, do którego jest przyłączony, a które nie istnieją.

Moje pytanie: czy to przydatne? Czy służy to celowi? Czy są sytuacje, w których rozwiązuje problem? Może to sposób definiowania interfejsów?

Odpowiedz

6

Tak, to jest przydatne i ma służyć cel, ale jest również dość rzadkie, aby to zrobić. Jeśli uważasz, że musisz poprawiać klasy po ich zdefiniowaniu, zawsze powinieneś przestać i zastanowić się, czy to naprawdę najlepszy sposób.

Jedną z sytuacji jest łatanie małp.Zrobiłem to w dużym systemie Plone, gdzie niektóre metody wymagały drobnych poprawek, ale nie było prostego sposobu na normalne obejście tego zachowania. W tej sytuacji, w której masz złożoną bibliotekę, możesz łatwo wprowadzić nowe lub zmodyfikowane zachowanie bez konieczności zmiany oryginalnej biblioteki.

Inną sytuacją, która przychodzi na myśl, jest to, że potrzebujesz wielu metod, które mogą być generowane automatycznie. na przykład testy oparte na danych.

def createTest(testcase, somedata, index): 
    def test(self): 
     "Do something with somedata and assert a result" 
    test_name = "test_%d" % index 
    setattr(testcase, test_name, test) 

for index, somedata in enumerate(somebigtable): 
    createTest(MyTestCase, somedata, index) 

gdy MyTestCase jest unittest.TestCase można mieć jeden test, który przechodzi przez wszystkie dane, ale zatrzymuje się na pierwszym niepowodzeniu, a ty nie masz, aby spróbować dowiedzieć się, które zawiodły linia danych. Poprzez dynamiczne tworzenie metod wszystkie testy są uruchamiane osobno, a nazwa testu mówi, która z nich się nie powiodła (oryginał powyższego kodu rzeczywiście zbudował bardziej znaczącą nazwę, zawierającą niektóre dane, a także indeks).

Nie można tego zrobić wewnątrz ciała klasy, ponieważ nie ma możliwości odwołania się do samej klasy lub jej słownika przed ukończeniem definicji. Możesz jednak zrobić coś podobnego za pomocą metaklasy, która pozwala modyfikować dyktando klasy przed stworzeniem samej klasy, a czasami jest to czystszy sposób robienia tego samego.

Inną rzeczą, na którą należy zwrócić uwagę, są sytuacje, w których to nie zadziała. Niektóre metody specjalne __xxx__ nie mogą zostać nadpisane po utworzeniu klasy: oryginalna definicja jest zapisywana wewnętrznie w innym miejscu niż klasa __dict__, więc wszelkie zmiany wprowadzone później mogą zostać zignorowane. Również w przypadku pracy z metaclasses czasami dodatkowe funkcje nie otrzymają żadnego traktowania, które metaclass nadaje atrybutom jako części definicji klasy.

+0

Interesujące! Wskazuje to również, że inną wartością może być przeniesienie definicji metod, które nie są kluczowe dla klasy w innym miejscu. Oczywiście w szczególnych sytuacjach. –

2

Ciekawostki:

  1. Funkcja w Pythonie jest to typ:

    type(f) # prints <type: function> 
    
  2. Więc funkcja jest wymagalne instancji, dzięki czemu może być podłączony w dowolnym miejscu.

  3. Może być używany do wykonywania funkcji przenośnych i emulowania funkcji plug and play.

  4. To może być naprawdę przydatny podczas rozwoju - na wypróbowanie różnych logiki (podłączając różne funkcje)

  5. ten zapewnia abstrakcji nad logiką, ponieważ możemy zastąpić metody klasy z funkcji importowanych.

Chociaż, wątpię, w jaki sposób użyjesz go do emulacji interfejsów!

3

Ponieważ obiekty funkcji mają metodę __get __ (...), to nie jest deskryptor danych.

Podczas definiowania metody w klasie A, to po prostu obiekt funkcji w .__ dict__:

In [78]: class A(object): 
    ....:  def f1(self): 
    ....:   pass 
    ....: 

In [79]: A.__dict__["f1"] 
Out[79]: <function f1 at 0x0D39A070> 

ale kiedy masz tę funkcję od instancji lub klasę atrybutu Ci związany metodę lub sposób niezwiązany .

In [80]: A.f1 
Out[80]: <unbound method A.f1> 

In [81]: A().f1 
Out[81]: <bound method A.f1 of <__main__.A object at 0x0D2F1CD0>> 

Tak działa metoda. Tak, można dodać metodę później:

In [82]: A.f2 = lambda self: id(self) 

In [83]: A().f2() 
Out[83]: 221189392 

więc kod jest prawie taka sama, jak:

class A: 
    def z(self): 
     print self.name 
    name="A" 

Proszę zapoznać się szczegółowo z http://docs.python.org/howto/descriptor.html

+0

Tak, ale czy ten idiom jest przydatny do czegokolwiek? –

Powiązane problemy