#metaprogramowanie

0
1
dlaczego nowoczesne programowanie wygląda tak, że jak mamy jakiś struct typu DataFrame pandas
to w tym structcie z jakiegoś powodu jest wbudowana funkcja sort
zamiast mieć w bibliotece pandas funkcję sort która bierze df i warunki sortowania i zwraca posortowany df
nie rozumiem tego tak bardzo
w sensie że zamiast df = df.sort_values(by='x') powinno być df = pd.sort(df, by='x') : z biblioteki pandas bierzemy funkcję sortującą która działa na df z parametrami dalej, zamiast dataframe'u magicznie się sortującego z samego swojego istnienia (?)
lub np. w pythonie jest logiczne list = sorted(list) vs. jakieś dzikie list = list.sort()
na dodatek to jest strasznie nieintuicyjnie gdy próbujemy składać funkcje, np rozważmy coś takiego:
df.sort_values().filter().plot()
trudno mi jest zrozumieć co tu się dokładnie dzieje, porównajmy to z bardziej logicznym, matematycznym wyrażeniem tego:
plot(filter(sort_values))(df) gdzie ciąg przyczynowo-skutkowy jest jasny, widoczny i zgodny z konwencją (funkcje składamy od prawej do lewej)
alternatywnie można by wprowadzić
dla mnie to wygląda tak jakby ktoś się obraził na konwencję składania funkcji i wymyślił całkowicie nowy sposób byle tylko uniknąć składania funkcji xD
ta konwencja prowadzi do tego że jakikolwiek kod w Pythonie jest dla mnie niezrozumiały mimo że ogarniam mniej-więcej co się dzieje w nawet trochę bardziej skomplikowanych programach w C
Chodzi mi głównie o to, że zamiast jasnego podziału na zmienne (które same z siebie się nie zmieniają bez jasnych instrukcji programu) i działające na nich funkcje, robimy miszmasz że wszystko może mieć wbudowane w siebie funkcje.
To tak jakby zamiast 2+2 (co jest uproszczeniem zapisu suma(2,2) gdzie suma to funkcja z R^2 w R dodająca argumenty) pisać 2.dodaj(2)
ps jeśli nie zauważyliście jeszcze to nie jestem programistą, ani nie mówię że potrafię programować - więc oczekuję odpowiedzi na moim poziomie a nie elektrody
#programowanie bardziej #metaprogramowanie
12
globalbus

@radler "na końcu ma coś w stylu "return this", co zwraca zmodyfikowany obiekt."

W większości przypadków tak, ale są też API, które zamiast this zwrócą nowy obiekt tej samej klasy, a poprzedni zostawią niezmieniony. Najśmieszniejsze są przypadki, gdy klasa ma właściwości copy-on-write, czyli kopią staje się dopiero, gdy coś zmodyfikuje obiekt.

@MurrayRothbard z językami czysto funkcyjnymi trzeba uważać, bo czasem to są akademickie zastosowania, że "da się tak napisać program". Funkcyjne programowanie bardzo elegancko wygląda przy współbieżności, nie ma tego wszystkiego czym się męczy studentów (synchronizacja wątków).

Python, języki JVMowe są wieloparadygmatowe, czyli da się fragment napisać tak, a drugi inaczej, w zależności jak jest dla danego celu wygodniej/czytelniej.

radler

@globalbus Zgadza się. Spotkałem się nawet z takimi klasami, które mają 2 różne metody i jedna zwraca klon, a druga referencje do istniejącego obiektu, ale nazwy tych metod w ogóle nie wskazują która co zwraca .

Strus

@MurrayRothbard W Twoim przykładzie zakładasz, że wszystkie funkcje można wywołać na wszystkim, a w prawdziwym zyciu tak to nie działa. Dlatego składnia foo.do_something() jest dużo lepsza, bo:

  1. Wiesz, że dany obiekt rzeczywiście implementuje daną funkcjonalność

  2. IDE może Ci podpowiedzieć, co możesz z danym obiektem zrobić


Języki takie jak Haskell to inna historia, bo tam każdą funkcję pisze się jak najbardziej generycznie - ale już nie wchodząc w szczegóły, to w większości "standardowych" języków się tak nie da.


Co do czytelności - dla większości ludzi po przyzwyczajeniu bardziej czytelne są wywoływania przez kropkę, tym bardziej, że jak masz dużo wywołań z wieloma argumentami, to każdą funkcję możesz dać w osobnej linii. Przy wywołaniach foo(bar(baz())) tak się za bardzo nie da i szybko robi się syf.

Zaloguj się aby komentować