W Pythonie 3.4+, dlaczego powinienem używać namestuple zamiast SimpleNamespace, gdy nie używam dict, wydają się bardzo podobne

11

W pewnym momencie możesz natrafić na funkcje z wieloma argumentami. Czasami sensowne jest łączenie niektórych argumentów w superargumenty. Często robiłem to z dyktando, ale teraz szukam lepszych sposobów na zrobienie tego.

Chciałbym włączyć ...

def do_something(ax, ay, az, bu, bv, c):
    # Do something

... w ...

def do_something(a, b, c):
    # Do something

... gdzie ai bzawierają ich podwariacje.

Jednym ze sposobów na to jest:

A = namedtuple('A', 'x, y, z')
a = A(ax, ay, az)
B = namedtuple('B', 'u, v')
b = B(bu, bv)

Wydaje się to jednak prostsze:

a = SimpleNamespace(x=ax, y=ay, z=az)
b = SimpleNamespace(u=bu, v=bv)

Jaka jest wada? Fakt, że ai bnie są dobrze napisane? To nie są obiekty A i B?

(Przy okazji, nie przejmuj się nazwami zmiennych. Zwykle nie używam jako krótkich nazw zmiennych).

André Christoffer Andersen
źródło
1
Nie ma żadnych wad, są to po prostu różne rzeczy. Na początek, imiona są niemodyfikowalne, a przestrzenie nazw są zmienne. Czy zmienne są lepsze czy gorsze niż niewymowne? To zależy od tego, czego potrzebujesz lub chcesz, w wielu przypadkach to po prostu nie ma znaczenia. Twoja funkcja prawdopodobnie działałaby z dowolnym obiektem z wymaganymi atrybutami, jak zbudować to zależy od obiektu wywołującego.
Przestań krzywdzić Monikę
@ Gooy Dziękuję. „Wada” była niezdarnym sposobem na powiedzenie tego. Nie chciałem sugerować, że jedno jest z natury lepsze od drugiego. Chciałem tylko za i przeciw. Dzięki jeszcze raz.
André Christoffer Andersen
1
czy czwarta linia nie powinna wyglądać jak „b = B (bu, bv)”?
Alen Siljak,
@AlenSiljak Tak, powinno. Naprawię to teraz.
André Christoffer Andersen

Odpowiedzi:

21

SimpleNamespacejest po prostu ładną fasadą na górze słownika. Pozwala używać właściwości zamiast kluczy indeksu. Jest to miłe, ponieważ jest bardzo elastyczne i łatwe w obsłudze.

Minusem tej elastyczności jest to, że nie zapewnia żadnej struktury. Nic nie stoi na przeszkodzie, aby ktoś zadzwonił SimpleNamespace(x=ax, y=ay)(i del a.zw pewnym momencie później). Jeśli to wystąpienie zostanie przekazane do funkcji, wyjątek występuje podczas próby uzyskania dostępu do pola.

Natomiast namedtuplepozwala utworzyć typ strukturalny. Typ będzie miał nazwę i będzie wiedział, jakie pola powinien mieć. Nie będziesz w stanie utworzyć instancji bez każdego z tych pól i nie będzie można ich później usunąć. Ponadto instancja jest niezmienna, więc będziesz wiedział, że wartość w a.xbędzie zawsze taka sama.

To Ty decydujesz, czy potrzebujesz elastyczności, która SimpleNamespaceCi daje, czy wolisz mieć strukturę i gwarancje namedtuple.

unholysampler
źródło
2

Bardzo podoba mi się odpowiedź na temat strukturyzowanej kontra nie, dlatego poniżej podam konkretny przykład.

SimpleNamespacezaakceptuje klucze zaczynające się od _. Jeśli szukasz szybkiego i łatwego sposobu na przekształcenie, powiedzmy JSON, którego nie kontrolujesz w obiekty o nazwach pól, jest to bardzo przydatne:

d = {"_id": 2342122, "text": "hi there!"} # Elasticsearch gives this id!
e = SimpleNamespace(**d) # works
Name = namedtuple("Name", sorted(d)) # ValueError so we can't do Name(**d)

Zauważ powyżej, że widać, że namedtupledaje nam to cały dodatkowy obiekt, który SimpleNamespacenigdy nie będzie. Każda z nich SimpleNamespacejest naprawdę „wyjątkowym płatkiem śniegu”, podczas gdy namedtupleistnieje bez tworzenia konkretnych wartości. Gdziekolwiek potrzebujesz abstrakcji, które uogólniają na konkretne wartości, prawdopodobnie powinieneś je preferować.

Alex Moore-Niemi
źródło
1

Podsumowanie SimpleNamespace

Pozwala na inicjalizację atrybutów podczas konstruowania obiektu:

sn = SimpleNamespace(a=1, b=2)

Zapewnia czytelność

repr(): eval(repr(sn)) == sn

Zastępuje domyślne porównanie. Zamiast porównywać według id(), porównuje wartości atrybutów.

Vlad Bezden
źródło