Czy wszystkie klasy Pythona powinny rozszerzać obiekt?

129

Stwierdziłem, że oba poniższe działania:

class Foo():
    def a(self):
        print "hello"

class Foo(object):
    def a(self):
        print "hello"

Czy wszystkie klasy Pythona powinny rozszerzać obiekt? Czy są jakieś potencjalne problemy z nierozciąganiem obiektu?

Kara
źródło
2
Czy jest różnica między class Foo():i class Foo:? Jak zauważyłem, oba działają w Pythonie 3.
Wolf
Odpowiedź jest dobra w tym pytaniu: stackoverflow.com/questions/4015417/ ...
nngeek

Odpowiedzi:

117

W Pythonie 2 nie dziedziczenie z objectspowoduje powstanie klasy w starym stylu, co między innymi powoduje typeuzyskanie różnych wyników:

>>> class Foo: pass
... 
>>> type(Foo())
<type 'instance'>

vs.

>>> class Bar(object): pass
... 
>>> type(Bar())
<class '__main__.Bar'>

Również zasady wielokrotnego dziedziczenia są różne w sposób, którego nawet nie będę próbował tutaj streszczać. Cała dobra dokumentacja dotycząca MI, którą widziałem, opisuje klasy w nowym stylu.

Wreszcie, w Pythonie 3 zniknęły klasy starego typu, a dziedziczenie z objectstało się niejawne. Dlatego zawsze preferuj nowe klasy, chyba że potrzebujesz wstecznej kompatybilności ze starym oprogramowaniem.

Fred Foo
źródło
68

W Pythonie 3 klasy rozszerzają się objectniejawnie, niezależnie od tego, czy mówisz to sam, czy nie.

W Pythonie 2 istnieją klasy w starym i nowym stylu . Aby zasygnalizować, że klasa jest w nowym stylu, musisz jawnie dziedziczyć zobject . Jeśli nie, używana jest implementacja w starym stylu.

Zwykle chcesz klasy w nowym stylu. Dziedzicz z objectjawnie. Należy zauważyć, że dotyczy to również kodu Python 3, który ma być zgodny z Pythonem 2.

Slezica
źródło
Tak, różnica, którą wskazał Free Foo , zniknęła, przy okazji: czy puste nawiasy są opcjonalne?
Wolf
4
Jest dużo kodu Pythona 3, który używa foo (obiekt) :. Czy to tylko konwencja?
RFV5,
2
@RFVenter Może to być kod, który powinien działać zarówno w Pythonie 2, jak i 3, w takim przypadku musisz jawnie
podklasować
@blubberdiblub Tak podejrzewałem, ALE nasz projekt działa wyłącznie na pythonie 3.5 virtualenv. Myślę, że kod musiał zostać skopiowany z projektu Python 2.
RFV5s
@RFVenter tak, to może być inne wyjaśnienie. Oczywiście, jeśli jest to tylko Python 3.x, można pozbyć się odniesień do obiektów.
blubberdiblub
17

W Pythonie 3 możesz stworzyć klasę na trzy różne sposoby i wewnętrznie wszystkie są równe (zobacz przykłady). Nie ma znaczenia, w jaki sposób utworzysz klasę, wszystkie klasy w Pythonie 3 dziedziczą po specjalnej klasie zwanej object . Klasa obiektu jest podstawową klasę w Pythonie i zapewnia wiele funkcji, takich jak metody podwójnego podkreślenia deskryptorów, super sposób (metoda), nieruchomości () etc.

Przykład 1.

class MyClass:
 pass

Przykład 2.

class MyClass():
 pass

Przykład 3.

class MyClass(object):
  pass
N Randhawa
źródło
1
To nie do końca prawda ... stackoverflow.com/questions/1238606/…
Philip Adler
Nie jestem pewien, czy cię śledzę. I tak, prawdopodobnie nie dotyczy większości ludzi, dopóki nie jest to istotne.
Philip Adler
@PhilipAdler Powszechnie przyjmuje się, objectże odwołuje się do wbudowanego object. Jeśli musimy wziąć pod uwagę, że jakikolwiek wbudowany identyfikator CPythona może zostać zastąpiony, z trudem moglibyśmy powiedzieć coś o modelu danych. Czy można poważnie argumentować, że strnie zawsze akceptuje się ciąg znaków jako argument, ponieważ można go przypisać builtins.str = None?
Nuno André
Ciągle widzę to twierdzenie, że jest to „szeroko zakładane” i akceptuję, że jest to założenie, które zakłada każda obecna implementacja (nie jest to wymóg języka), nie było z mojego doświadczenia, że ​​większość programistów Pythona spotkali się, zakładali to, wiedzieli o tym, a nawet rozważali. Niezależnie od tego, co twierdzenie, że powszechnie przyjmuje się, nawet jeśli to prawda, nie podważa moje twierdzenie, że równoważność nie jest ściśle prawdziwe.
Philip Adler,
1

Tak, wszystkie klasy Pythona powinny rozszerzać (a raczej podklasę, tutaj jest Python). Chociaż zwykle nie wystąpią żadne poważne problemy, w niektórych przypadkach (jak w przypadku wielu drzew dziedziczenia) będzie to ważne. Zapewnia to również lepszą zgodność z Pythonem 3.

pydsigner
źródło
1
dokładnie, technicznie rzecz biorąc, jeśli tego nie zrobisz, otrzymasz klasyczną klasę, ale nie ma to żadnych zalet, a i tak nie jest obsługiwana przez Pythona 3
max k.
Jestem ciekawy, dlaczego poprawia kompatybilność z pythonem3. O ile mi wiadomo, python3 automatycznie rozszerzy obiekt, nawet jeśli go nie określisz, prawda?
Paul Lo,
2
@PaulLo Dobrze, ale jeśli jawnie odziedziczysz po obiekcie, uzyskasz to samo (w nowym stylu) zachowanie zarówno w Pythonie 2, jak i Pythonie 3. Nie jest to kwestia zmiany sposobu działania Pythona 3, jest to kwestia użycia forward -kompatybilność w Pythonie 2.
pydsigner
Ta sugestia nie wygląda zbyt elegancko, ale jeśli zajmiesz się Python2 i Python3, wydaje się skuteczna. Ale jak istotne jest to w praktyce?
Wolf
@Wolf To zależy od tego, co robisz. Jeśli masz złożone drzewa dziedziczenia, ma to duże znaczenie. Jeśli chcesz, aby Twoja klasa była deskryptorem, musisz użyć nowego stylu. Możesz skorzystać z linków ze stackoverflow.com/questions/54867/ ... jeśli chcesz uzyskać więcej szczegółowych informacji.
pydsigner
1

Zgodnie z innymi odpowiedziami, dziedziczenie Pythona 3 po obiekcie jest niejawne. Ale nie mówią, co należy robić i czym jest konwencja.

Wszystkie przykłady dokumentacji Pythona 3 używają następującego stylu, który jest konwencją, więc sugeruję, abyś postępował zgodnie z tym dla każdego przyszłego kodu w Pythonie 3.

class Foo:
    pass

Źródło: https://docs.python.org/3/tutorial/classes.html#class-objects

Przykładowy cytat:

Obiekty klas obsługują dwa rodzaje operacji: odwołania do atrybutów i tworzenie instancji.

Odniesienia do atrybutów używają standardowej składni używanej dla wszystkich odniesień do atrybutów w Pythonie: obj.name. Prawidłowe nazwy atrybutów to wszystkie nazwy, które znajdowały się w przestrzeni nazw klasy podczas tworzenia obiektu klasy. Tak więc, jeśli definicja klasy wyglądałaby tak:

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

Inny cytat:

Ogólnie rzecz biorąc, zmienne instancji są unikalne dla danych dla każdej instancji, a zmienne klas dotyczą atrybutów i metod wspólnych dla wszystkich instancji klasy:

class Dog:

    kind = 'canine'         # class variable shared by all instances

    def __init__(self, name):
        self.name = name    # instance variable unique to each instance
jmoz
źródło
0

w pythonie3 nie ma różnicy, ale w pythonie2 nie rozszerzanie objectdaje klasę w starym stylu; chciałbyś użyć klasy w nowym stylu zamiast klas w starym stylu.

thkang
źródło
2
Ta odpowiedź jest rozsądna, ale inni odpowiadający dotarli tam szybciej i / lub bardziej szczegółowo; ta odpowiedź nie dodaje żadnej wartości do strony w obecnej postaci.
Mark Amery,