Przykro mi, jeśli jest to całkowicie absurdalne pytanie, ale jestem ciekawy, jakie są najlepsze praktyki i nie mogę znaleźć dobrej odpowiedzi w Google.
W Pythonie zwykle używam pustej klasy jako super-catchallowego kontenera struktury danych (coś w rodzaju pliku JSON) i dodając atrybuty po drodze:
class DataObj:
"Catch-all data object"
def __init__(self):
pass
def processData(inputs):
data = DataObj()
data.a = 1
data.b = "sym"
data.c = [2,5,2,1]
Daje mi to ogromną elastyczność, ponieważ obiekt kontenerowy może zasadniczo przechowywać wszystko. Więc jeśli pojawią się nowe wymagania, po prostu dodam go jako kolejny atrybut do obiektu DataObj (który przekazuję w moim kodzie).
Jednak ostatnio (programistom FP) wywarło na mnie wrażenie, że jest to okropna praktyka, ponieważ bardzo utrudnia czytanie kodu. Należy przejść przez cały kod, aby dowiedzieć się, jakie atrybuty ma DataObj.
Pytanie : Jak mogę to przepisać, aby uzyskać większą łatwość konserwacji bez utraty elastyczności?
Czy są jakieś pomysły z programowania funkcjonalnego, które mogę zastosować?
Szukam najlepszych praktyk.
Uwaga : jednym z pomysłów jest wstępne zainicjowanie klasy za pomocą wszystkich atrybutów, które można napotkać, np
class DataObj:
"Catch-all data object"
def __init__(self):
data.a = 0
data.b = ""
data.c = []
def processData(inputs):
data = DataObj()
data.a = 1
data.b = "sym"
data.c = [2,5,2,1]
Czy to naprawdę dobry pomysł? Co jeśli nie wiem, jakie są moje atrybuty a priori?
Odpowiedzi:
Ty nie. Elastyczność jest właśnie przyczyną problemu. Jeśli dowolny kod w dowolnym miejscu może zmienić atrybuty obiektu, łatwość konserwacji jest już podzielona na części. Idealnie, każda klasa ma zestaw atrybutów, które są ustawione w kamieniu po
__init__
i takie same dla każdego wystąpienia. Nie zawsze jest to możliwe lub rozsądne, ale powinno tak być zawsze, gdy nie masz naprawdę dobrych powodów, aby tego uniknąć.To nie jest dobry pomysł. Jasne, wtedy atrybut istnieje, ale może mieć fałszywą wartość, a nawet prawidłową, która zakrywa kod nieprzypisujący wartości (lub błędnie napisany).
AttributeError
jest przerażające, ale błędne wyniki są gorsze. Ogólnie wartości domyślne są w porządku, ale aby wybrać rozsądną wartość domyślną (i zdecydować, co jest wymagane), musisz wiedzieć, do czego służy obiekt.W takim razie jesteś wkręcony i powinieneś użyć dykta lub listy zamiast twardych nazw atrybutów. Ale rozumiem, że miałeś na myśli „... w czasie, gdy piszę klasę kontenera”. Zatem odpowiedź brzmi: „Możesz edytować pliki w trybie lockstep, duh”. Potrzebujesz nowego atrybutu? Dodaj atrybut fregowania do klasy kontenera. Jest więcej kodu używającego tej klasy i nie potrzebuje on tego atrybutu? Rozważ podzielenie rzeczy na dwie osobne klasy (użyj miksów, aby pozostać SUCHYM), więc włącz opcjonalnie, jeśli ma to sens.
Jeśli boisz się pisać powtarzające się klasy kontenerów: Zastosuj metaprogramowanie rozważnie lub użyj,
collections.namedtuple
jeśli nie musisz mutować członków po utworzeniu (Twoi znajomi z FP byliby zadowoleni).źródło
Zawsze możesz skorzystać z klasy Buncha Alexa Martellego . W Twoim przypadku:
W ten sposób czytelnik przynajmniej zrozumie, że dane są po prostu głupim magazynem danych i od razu widać, które wartości są przechowywane pod inną nazwą, ponieważ wszystko dzieje się w jednym wierszu.
I tak, robienie rzeczy w ten sposób jest czasem dobrym pomysłem.
źródło
Prawdopodobnie skorzystałbym z drugiego podejścia, prawdopodobnie
None
do wskazania nieprawidłowych danych. Prawdą jest, że trudno jest odczytać / zachować, jeśli dodasz atrybuty później. Jednak więcej informacji na temat celu tej klasy / obiektu dałoby wgląd w to, dlaczego pierwszy pomysł jest złym projektem: gdzie miałbyś kiedykolwiek całkowicie pustą klasę bez metod lub danych domyślnych? Dlaczego nie miałbyś wiedzieć, jakie atrybuty ma klasa?Jest możliwe , że
processData
może być lepiej jak metoda (process_data
podążać Pythona nazewnictwa), ponieważ działa na klasy. Biorąc pod uwagę przykład, wygląda na to, że może być lepsza jako struktura danych (gdziedict
może wystarczyć).Biorąc pod uwagę prawdziwy przykład, możesz rozważyć przesłanie pytania do CodeReview , gdzie mogą one pomóc w przebudowaniu kodu.
źródło