Czy istnieje sposób wygodnego zdefiniowania struktury podobnej do C w Pythonie? Mam dość pisania takich rzeczy jak:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
MyStruct = namedtuple("MyStruct", "field1 field2 field3")
pandas.Series(a=42).a
powinien to zrobić, jeśli jesteś naukowcem danych ...Odpowiedzi:
Użyj nazwanej krotki , która została dodana do modułu kolekcji w standardowej bibliotece w Pythonie 2.6. Możliwe jest również użycie przepisanego krotka Raymonda Hettingera, jeśli chcesz obsługiwać Python 2.4.
Jest to miłe z punktu widzenia twojego podstawowego przykładu, ale obejmuje również kilka przypadków krawędzi, na które możesz natknąć się później. Twój fragment powyżej zostanie zapisany jako:
Nowo utworzonego typu można użyć w następujący sposób:
Możesz także użyć nazwanych argumentów:
źródło
Aktualizacja : Klasy danych
Wraz z wprowadzeniem klas danych w Pythonie 3.7 jesteśmy bardzo blisko.
Poniższy przykład jest podobny do poniższego przykładu NamedTuple , ale wynikowy obiekt można modyfikować i dopuszcza wartości domyślne.
To ładnie gra z nowym modułem pisania na wypadek, gdybyś chciał użyć bardziej szczegółowych adnotacji typu.
Desperacko na to czekałem! Jeśli mnie zapytasz, klasy danych i nowa deklaracja NamedTuple w połączeniu z pisaniem modułem są niebios!
Ulepszona deklaracja NamedTuple
Od wersji Python 3.6 stało się dość proste i piękne (IMHO), o ile można żyć z niezmiennością .
Wprowadzono nowy sposób deklarowania NamedTuples , który umożliwia także dodawanie adnotacji :
źródło
dataclass
Moduł jest nowego w Pythonie 3.7, ale możnapip install dataclasses
. Jest to backport w Pythonie 3.6. pypi.org/project/dataclasses/#description@dataclass
Szczegóły są tutaj: pypi.org/project/dataclasses/#descriptionMożesz użyć krotki do wielu rzeczy, w których użyjesz struktury w C (np. Współrzędne x, y lub kolory RGB).
Do wszystkiego innego możesz użyć słownika lub klasy użyteczności takiej jak ta :
Myślę, że „ostateczna” dyskusja jest tutaj , w opublikowanej wersji Python Cookbook.
źródło
TypeError: this constructor takes no arguments
Być może szukasz Struktur bez konstruktorów:
źródło
class Sample:
nie robią natychmiast nic; ustawiają atrybuty klas. Można do nich zawsze uzyskać dostęp npSample.name
.s1
is2
w czasie wykonywania. O ile nie zabrania się tego inaczej, możesz dodawać lub modyfikowaćname
atrybut w dowolnej instancji dowolnej klasy w dowolnym momencie, niezależnie od tego, czy klasa maname
atrybut. Prawdopodobnie największym problemem funkcjonalnym jest to, że różne instancje tej samej klasy będą zachowywać się inaczej w zależności od tego, czy został ustawionyname
. Jeśli zaktualizujeszSample.name
, wszelkie obiekty bez jawnie ustawionejname
właściwości zwrócą nowyname
.self
słów kluczowych i linii konstruktora, jeśli mnie o to pytasz. Byłbym wdzięczny, gdyby Jose mógł edytować swoją odpowiedź, aby dodać ostrzeżenie o ryzyku przypadkowego dzielenia się wartościami między instancjami.Co powiesz na słownik?
Coś takiego:
Następnie możesz użyć tego do manipulowania wartościami:
A wartości nie muszą być łańcuchami. Mogą być praktycznie dowolnym innym przedmiotem.
źródło
pt3.w = 1 print pt3.w
W języku ze słownikami lepiej jest ich używać, szczególnie w przypadku serializowanych obiektów, ponieważ możesz automatycznie użyć importu json, aby zapisać je i inne biblioteki serializacji, o ile nie masz dziwnych rzeczy w twoim dyktandzie. Dicts to rozwiązanie oddzielające dane i logikę i są lepsze niż struktury dla osób, które nie chcą pisać niestandardowych funkcji serializacji i odserializować i nie chcą używać nieprzenośnych serializatorów takich jak marynata.Możesz uzyskać dostęp do pól klasy za pomocą słownika, ponieważ pola klasy, jej metody i wszystkie jej właściwości są przechowywane wewnętrznie za pomocą dykt (przynajmniej w CPython).
... Co prowadzi nas do twojego drugiego komentarza. Przekonanie, że dyktanda Pythona są „ciężkie”, jest pojęciem skrajnie pythonistycznym. A czytanie takich komentarzy zabija mojego Pythona Zen. To nie jest dobrze.
Widzisz, kiedy deklarujesz klasę, faktycznie tworzysz dość złożone opakowanie wokół słownika - więc, jeśli już, to dodajesz więcej narzutu niż przy użyciu prostego słownika. Koszty ogólne, które, nawiasem mówiąc, są w ogóle bez znaczenia. Jeśli pracujesz nad aplikacjami krytycznymi pod względem wydajności, użyj C lub czegoś takiego.
źródło
self['member']
jest o 3 znaki dłuższy niżself.member
i wszystkie te postacie są względnie nieprzyjazne dla nadgarstka.Możesz podklasować strukturę C dostępną w standardowej bibliotece. Ctypes moduł dostarcza struktura klasowa . Przykład z dokumentów:
źródło
Chciałbym również dodać rozwiązanie wykorzystujące automaty :
Zdecydowanie sprawdź w dokumentacji szczeliny, ale szybkie wyjaśnienie szczelin jest takie, że python tak mówi: „Jeśli możesz zablokować te atrybuty i tylko te atrybuty w klasie, tak że zobowiązujesz się, że nie dodasz żadnych nowych atrybutów, gdy klasa jest tworzony (tak, możesz dodać nowe atrybuty do instancji klasy, patrz przykład poniżej), a następnie zrezygnuję z dużej alokacji pamięci, która pozwala na dodawanie nowych atrybutów do instancji klasy i użyć tylko tego, czego potrzebuję dla tych szczelin atrybutów ".
Przykład dodawania atrybutów do instancji klasy (a więc nie używania gniazd):
Wyjście: 8
Przykład próby dodania atrybutów do instancji klasy, w której zastosowano sloty:
Dane wyjściowe: AttributeError: Obiekt „Point” nie ma atrybutu „z”
Może to skutecznie działać jako struktura i zużywa mniej pamięci niż klasa (tak jak struktury, choć nie badałem dokładnie ile). Zaleca się stosowanie miejsc, jeśli będziesz tworzyć dużą liczbę instancji obiektu i nie musisz dodawać atrybutów. Obiekt punktowy jest tego dobrym przykładem, ponieważ prawdopodobne jest, że można utworzyć wiele punktów w celu opisania zestawu danych.
źródło
Możesz także przekazać parametry inicjujące do zmiennych instancji według pozycji
źródło
Point3dStruct
deklaracji,Point3dStruct(5, 6)
nie będzie działać zgodnie z oczekiwaniami. Dziwne, że nikt nie napisał tego przez wszystkie 6 lat.print
>print()
iattrs[n]
>next(attrs)
(filtr jest teraz własnym iterowalnym obiektem i wymaganext
).Ilekroć potrzebuję „natychmiastowego obiektu danych, który również zachowuje się jak słownik” ( nie myślę o strukturach C!), Myślę o tym uroczym hacku:
Teraz możesz po prostu powiedzieć:
Idealnie przydatny w sytuacjach, gdy potrzebujesz „torby danych, która NIE JEST klasą”, i gdy imienniki są niezrozumiałe ...
źródło
Dostęp do struktury C-Style uzyskuje się w pythonie w następujący sposób.
jeśli chcesz tylko użyć obiektu cstruct
jeśli chcesz stworzyć tablicę obiektów konstrukcyjnych
Uwaga: zamiast nazwy „cstruct” użyj nazwy struktury zamiast var_i, var_f, var_str, proszę zdefiniuj zmienną członka swojej struktury.
źródło
Niektóre odpowiedzi tutaj są bardzo rozbudowane. Najprostszą opcją, którą znalazłem, jest (z: http://norvig.com/python-iaq.html ):
Inicjalizacja:
dodając więcej:
edytuj: Przykro mi, ale nie widziałem jeszcze tego przykładu
źródło
To może być trochę za późno, ale zrobiłem rozwiązanie za pomocą Python Meta-Classes (poniżej również wersja dekoratora).
Kiedy
__init__
jest wywoływany w czasie wykonywania, pobiera każdy z argumentów i ich wartość i przypisuje je jako zmienne instancji do twojej klasy. W ten sposób możesz stworzyć klasę podobną do struktury bez konieczności przypisywania każdej wartości ręcznie.W moim przykładzie nie ma sprawdzania błędów, więc łatwiej jest naśladować.
Tutaj jest w akcji.
I napisali go na reddit i / u / matchu napisali wersję dekorator, który jest czystsze. Zachęcam do korzystania z niego, chyba że chcesz rozszerzyć wersję metaklasy.
źródło
Napisałem dekorator, którego można użyć w dowolnej metodzie, aby uczynić go tak, aby wszystkie przekazane argumenty lub wartości domyślne zostały przypisane do instancji.
Szybka demonstracja. Zauważ, że używam argumentu pozycyjnego
a
, używam domyślnej wartości dlab
i nazwanego argumentuc
. Następnie drukuję wszystkie 3 odwołaniaself
, aby pokazać, że zostały poprawnie przypisane przed wprowadzeniem metody.Pamiętaj, że mój dekorator powinien działać dowolną metodą, nie tylko
__init__
.źródło
Nie widzę tutaj tej odpowiedzi, więc sądzę, że ją dodam, ponieważ teraz opieram Python i właśnie ją odkryłem. Poradnik Pythona (Python 2, w tym przypadku) daje następujące proste i skuteczne, na przykład:
Oznacza to, że tworzony jest pusty obiekt klasy, a następnie tworzona jest instancja, a pola są dodawane dynamicznie.
Wada tego jest naprawdę prosta. Minusem jest to, że nie jest to szczególnie samok dokumentujące się (zamierzeni członkowie nie są nigdzie wymienieni w „definicji” klasy), a nieuzbrojone pola mogą powodować problemy przy dostępie. Te dwa problemy można rozwiązać przez:
Teraz na pierwszy rzut oka możesz przynajmniej zobaczyć, jakich pól będzie oczekiwać program.
Oba są podatne na literówki,
john.slarly = 1000
odniesie sukces. Mimo to działa.źródło
Oto rozwiązanie, które wykorzystuje klasę (nigdy bez instancji) do przechowywania danych. Podoba mi się, że ten sposób wymaga bardzo niewielkiego pisania i nie wymaga żadnych dodatkowych pakietów itp.
W razie potrzeby możesz dodać więcej pól:
Aby uzyskać wartości, pola są dostępne jak zwykle:
źródło
Osobiście podoba mi się również ten wariant. Rozszerza odpowiedź @ dF .
Obsługuje dwa tryby inicjalizacji (które można łączyć):
Ponadto drukuje się ładniej:
źródło
Poniższe rozwiązanie struktury jest zainspirowane implementacją namedtuple i niektórymi wcześniejszymi odpowiedziami. Jednak w przeciwieństwie do nazwanego, jest zmienny pod względem wartości, ale podobnie jak struktura typu c niezmienna w nazwach / atrybutach, co nie jest normalną klasą lub dyktatem.
Stosowanie:
źródło
W tym celu istnieje pakiet python. patrz cstruct2py
cstruct2py
to czysta biblioteka Pythona do generowania klas Pythona z kodu C i używania ich do pakowania i rozpakowywania danych. Biblioteka może analizować nagłówki C (struktury, związki, wyliczenia i tablice) i emulować je w pythonie. Wygenerowane klasy pythonowe mogą analizować i pakować dane.Na przykład:
Najpierw musimy wygenerować struktury pythonowe:
Teraz możemy zaimportować wszystkie nazwy z kodu C:
Możemy to również zrobić bezpośrednio:
Używanie typów i definicji z kodu C.
Dane wyjściowe będą:
Do
cstruct2py
uruchomienia klonowania :źródło
Myślę, że słownik struktury Python jest odpowiedni dla tego wymagania.
źródło
https://stackoverflow.com/a/32448434/159695 nie działa w Python3.
https://stackoverflow.com/a/35993/159695 działa w Python3.
I rozszerzam go, aby dodać wartości domyślne.
źródło
Jeśli nie masz wersji 3.7 dla @dataclass i potrzebujesz możliwości zmiany, poniższy kod może być dla Ciebie odpowiedni. Jest dość samo dokumentujący i przyjazny dla IDE (autouzupełnianie), zapobiega dwukrotnemu pisaniu, jest łatwo rozszerzalny i bardzo łatwo jest przetestować, czy wszystkie zmienne instancji są całkowicie inicjalizowane:
źródło
Oto szybka i brudna sztuczka:
Jak to działa? Po prostu ponownie użyj wbudowanej klasy
Warning
(pochodnejException
) i użyj jej tak, jak byłaś własną zdefiniowaną klasą.Zaletą jest to, że nie musisz najpierw niczego importować ani definiować, że „Ostrzeżenie” to krótka nazwa i że również wyjaśnia, że robisz coś brudnego, czego nie należy używać w innym miejscu niż twój mały skrypt.
Nawiasem mówiąc, próbowałem znaleźć coś jeszcze prostszego,
ms = object()
ale nie mogłem (ten ostatni przykład nie działa). Jeśli masz, jestem zainteresowany.źródło
Najlepszym sposobem, jaki to zrobiłem, było użycie niestandardowej klasy słownika, jak wyjaśniono w tym poście: https://stackoverflow.com/a/14620633/8484485
Jeśli potrzebna jest obsługa autouzupełniania iPython, po prostu zdefiniuj funkcję dir () w następujący sposób:
Następnie definiujesz swoją pseudo-strukturę tak: (ten jest zagnieżdżony)
Następnie możesz uzyskać dostęp do wartości wewnątrz my_struct w następujący sposób:
print(my_struct.com1.inst)
=>
[5]
źródło
NamedTuple jest wygodny. ale nikt nie dzieli wydajności i pamięci.
Jeśli
__dict__
nie używasz, wybierz pomiędzy__slots__
(wyższą wydajnością i pamięcią masową) iNamedTuple
((jasne do czytania i użytkowania)Możesz przejrzeć ten link ( Wykorzystanie miejsc ), aby uzyskać więcej
__slots__
informacji.źródło