Czytałem o tym, jak wykonywać klasy Pythona mniej dynamiczne, szczególnie nie pozwalając użytkownikom dynamicznie tworzyć nowe atrybuty. Czytałem, że Przeciążenie __setattr__ jest dobrym sposobem Aby zrobić to i __slots__ nie jest sposobem na przejście. Jeden Post na tej ostatniej nici sugeruje, że __slots__ może złamać trawienie. (Czy ktoś może to potwierdzić?)

Jednak właśnie czytałem whatsnew for Python 2.2, a Atrakcyjny dostęp Sekcja faktycznie sugeruje przy użyciu __slots__ dla samego celu ograniczania tworzenia atrybutu, nie tylko do optymalizacji, jak inni sugerowali. Jeśli chodzi o historię Pythona, czy ktoś wiedział, jaki był pierwotny zamiar __slots__? Czy ogranicza formację zmienną funkcję lub błąd, który ma być nadużywany? Jak ludzie widzieli __slots__ używane w praktyce? Czy wielu ludzi widziało __setattr__ przeciążony, aby ograniczyć tworzenie atrybutu? Który jest najlepszy? Jeśli jesteś bardziej zaznajomiony z jedną metodą lub drugą metodą, możesz opublikować plusy i wady metody, którą znasz. Ponadto, jeśli masz inny sposób rozwiązania problemu, podziel się! (I spróbuj nie tylko powtórzyć wady __slots__, które zostały wyrażone w Inne wątki. )

Edytuj: Miałem nadzieję uniknąć dyskusji na temat "dlaczego?", Ale pierwsza odpowiedź wskazuje, że pojawi się, więc podam to tutaj. W danym projekcie, używamy tych klas przechowywać "Informacje o konfiguracji", umożliwiając użytkownikowi ustawianie atrybutów na obiektach z parametrami (użytkownikami), a następnie przekazać obiekty do innej części programu. Obiekty robią więcej niż tylko przechowywać parametry, więc słownik nie działa. Mamy już przypadkowo wpisujemy nieprawidłową nazwę atrybutów, a kończą tworzenie nowego atrybutu, a nie ustawianie jednego z atrybutów, których oczekuje program. Dotyczy to niewykrytych, więc użytkownik uważa, że ustawiają parametr, ale nie widzi oczekiwanego wyniku. To jest mylące dla użytkownika i trudno dostrzec. Ograniczając kreację atrybutową, wyjątek zostanie rzucony, a nie przejść przez cicho.

Edytuj 2, RE LICLING: Te obiekty będą czymś, co będziemy chcieli przechowywać w przyszłości, a miażdżenie wydaje się dobrym sposobem na to. Jeśli __slots__ jest wyraźnie najlepszym rozwiązaniem, prawdopodobnie moglibyśmy znaleźć inny sposób na ich przechowywanie, ale marynowanie zdecydowanie będzie miała wartość i powinna być uwzględniona.

Edytuj 3: Powinienem także wspomnieć, że konserwacja pamięci nie jest problemem. Bardzo niewielu z tych obiektów zostanie utworzonych, więc każda zapisana pamięć będzie znikoma (jak 10 m od kilobajtów na maszynie 3-12 GB).

1
hunse 5 grudzień 2013, 21:12

2 odpowiedzi

Najlepsza odpowiedź

Moja sugestia dla każdego przypadku użycia jest użycie __setattr__ i wydać OSTRZEŻENIE , gdy nazwa atrybutu nie jest rozpoznawana za pomocą Pythona ostrzeżenia moduł.

1
kindall 5 grudzień 2013, 17:31

Dlaczego próbujesz ograniczyć deweloperów z tego? Czy istnieje jakiś powód techniczny oprócz "Nie chcę, żeby zrobili to" dla niego? Jeśli nie, nie rób tego.

W każdym razie przy użyciu pamięci __slots__ (No {x1}}), więc lepiej to zrobić. Nie będziesz mógł go użyć, jeśli niektóre z twojego kodu potrzebuje obiektu, aby mieć __dict__.

Jeśli jest dobry powód, aby go ograniczyć (ponownie, jesteś pewien, że jest jeden?) lub Musisz zapisać tę małą pamięć, przejdź do __slots__.


Po przeczytaniu wyjaśnień możesz użyć __setattr__, ewentualnie połączony z __slots__ (Musisz i tak przechowywać atrybut i tak i tak możesz, dzięki czemu można go użyć, aby zapisać pamięć). W ten sposób można wyświetlić bardziej pomocne informacje, takie jak atrybut podobny . Możliwe wdrożenie może wyglądać tak:

class Test(object):
    __slots__ = ('foo', 'bar', 'moo', 'meow', 'foobar')

    def __setattr__(self, name, value):
        try:
            object.__setattr__(self, name, value)
        except AttributeError:
            alts = sorted(self.__slots__, key=lambda x: levenshtein(name, x))
            msg = "object has no attribute '{}', did you mean '{}'?"
            raise AttributeError(msg.format(name, alts[0]))

Testowałem go {{X0}. A>. W przypadku nie jest więc inteligentne Użytkownicy możesz sprawić, że błąd będzie jeszcze bardziej wyrazisty i obejmować wszystkie bliskie mecze zamiast pierwszego.

Możesz jeszcze bardziej poprawić kod, tworząc klasę miksin zawierającą metodę __setattr__. W ten sposób możesz zachować kod z twoich klas rzeczywistych, a także mieć niestandardowy __setattr__, jeśli to konieczne (wystarczy użyć super(...).__setattr__(...) w miksie zamiast object.__setattr__)

4
ThiefMaster 5 grudzień 2013, 17:39