Typowanie statyczne vs. dynamiczne (Python)

0

Siemacie
Może drogą wstępu: chciałem spytać jak sobie radzicie z brakiem typowania w językach tj. Python(w nim pisze ;)) Ruby, JavaScript itp?

O co mi chodzi dokładniej? Kiedyś, jak zaczynałem od Javy to się trochę do mocnego typowania przyzwyczaiłem i np. jak jeszcze zaczynałem się uczyć pisania okienek w Javie w Swingu, to bardzo pomocna była mi opcja Ctrl+space w moim IDE bo podpowiadała jakiego typu i jakie mają być argumenty. Stąd mogłem wiele wywnioskować, poskrobać w docs'ach javy i jakoś się dochodziło do rozwiązania problemu "co w ten argument wstawić".

Od jakiegoś czasu pisze tak w wolnej, nudnej chwili w pythonie i sprawia mi niejako trudność brak tych cennych podpowiedzi. Przykładowo teraz skrobie sobie w PyQt4: typy są w 95% nieznane, 5% jest niejako podpowiadana (pewnie ze względu na IDE - PyCharm), większość metod które moge użyc na obiekcie również (choć wiadomo nie wszystkie).

Są natomiast rzeczy, których nie podpowiada IDE tak ładnie jak to miało miejsce w wypadku Javy (nawet w Eclipse! :D). Oczywiście, programista nie powinien polegać tylko na IDE "boś dupa a nie programista", ale nie zaprzeczycie chyba, że to na prawdę pomaga, a szczególnie jak ktoś zaczyna.

taki szybki przykład, w wypadku PyQt4:
cen_val = QtGui.QDesktopWidget().availableGeometry().center()

do momentu pobierania availableGeometry() popowiedzi są, ale metoda .center() jest kompletnie nie znana nawet PyCharm'owi (oczywiście działa jak należy)

Żebyście nie odebrali tego jako publiczne wylanie żalu - chciałbym spytać jak sobie radzicie z brakiem typowania w takich językach jak Python? Przeglądacie dokumentacje danych klas/modułów/metod i po kolei, drogą dedukcji rozpatrujecie sprawie? A może "na pałe"? :)

Dzieki za uwagę

0

Python pozwala specyfikować typy poprzez docstringi i PyCharm potrafi wtedy podpowiadać składnie (ba, potrafi nawet przeprowadzić statyczną analizę kodu ;) ). Ale wtedy tracisz możliwość zabawy duck-typingiem, więc coś za coś.

0

@Shalom możesz przybliżyć trochę to co powiedziałeś odnośnie możliwości zabawy duck-typingiem? co masz dokładniej na myśli?

Co do docstringa to po prostu w nim podać typ jaki zwraca np. metoda?

0
azalut napisał(a):

Co do docstringa to po prostu w nim podać typ jaki zwraca np. metoda?

Dokładnie tak.

Dodam, że w środowisku używanym przeze mnie (Wing IDE), typ można określić w Pythonowym kodzie:

if 0: isinstance(zmienna, typ)

https://wingware.com/doc/edit/helping-wing-analyze-code

Jednak uważam, że docstring byłby lepszy ;)

0

http://www.jetbrains.com/pycharm/webhelp/type-hinting-in-pycharm.html

Jeśli chodzi o duck typing to generalnie przecież w pythonie możesz dodawać metody do obiektu przez monkey-patching na zasadzie

moj_obiekt.nowa_metoda = jakaś_funkcja

i potem ten obiekt ma taką funkcję ;] A nijak to nie wynika z jego typu.

1

Dynamiczne typowanie utrudnia programowanie, bo interpreter sam z siebie nie powie o błędzie dopóki nie rzuci wyjątkiem. Moim zdaniem to jest trochę nonszalanckie, ale można sobie z tym radzić. Oto moje wnioski jakie wyciągnąłem na podstawie ostatnich moich lat programowania w Pythonie.

1. Wyposaż się w dobre IDE.
Dobre IDE potrafi wyczaić wiele podstawowych błędów jakie co dzień można popełnić przez swoją nieuwagę.

2. Zamień debbuger na testy jednostkowe.
Testy jednostkowe sprawdzają nie tylko to czy twój kod się wykonuje, ale czy robi dokładnie to czego oczekujesz. Umiejętność pisania testów jest ważna niezależnie od języka w jakim pracujesz.

3. Używaj coverage.
Narzędzia sprawdzające pokrycie kodu pozwalają dostrzec jaki kod nie wykonuje się w trakcie testów. Dzięki temu dowiesz się, które obszary swego projektu lepiej wziąć pod lupę.

**4. Pisz prosty kod. **
Jeżeli stoisz przed wyborem algorytmu wybierz ten, który na chwilę obecną jest wystarczający. Kod, który jest łatwy w zrozumieniu łatwiej jest modyfikować niż ten zoptymalizowany. Kod łatwy w zrozumieniu łatwiej się testuje i poprawia.

5. Pisz czysty kod.
Pojęcie czystego kodu jest opisywane w wielu książkach. Z najbardziej wartościowych rzeczy jakie mogę polecić to przyłożenie uwagi do nazewnictwa i pisanie wielu małych klas i funkcji, które robią jedną rzecz, ale dobrze.

6. Poznaj bpython lub ipython.
Jeśli potrzebujesz coś sprawdzić to używaj tego narzędzia tak często jak tylko możesz :) To idealne środowisko do przeprowadzania eksperymentów, poznawania bibliotek i samego Pythona.

7. Używaj gita
Korzystanie z gita w uproszczeniu przypomina możliwość zapisywania stanu gry w dowolnym momencie. Jeśli coś pójdzie źle zawsze możesz wrócić do stanu wcześniejszego i tym samym uniknąć zła :]

0

@Spine @Shalom rozumiem, że to w jaki sposób podpowiadany jest typ jest związany stricte z IDE. W PyCharmie są to docstringi, a u ciebie Spine w wing'u deklaruje sie to w kodzie bezpośrednio?

@pleasedontkillmymummy
prawde mówiąc zawsze się zastanawiałem na temat testów, ale nigdy nie probowałem ich pisania - bo to moich domowych potrzeb i niewielkich projektów to najzwyczajniej nie było potrzebne :P może warto w końcu poznać jakieś podstawy?
poczytam o tym co podesłałeś, potestuje i zobacze jak to wygląda

jednak najczęściej (w javie) to właśnie IDE podpowiadało mi czy moge na jakimś obiekcie/klasie wywołać jakąś metode/pole czy nie. Teraz mam problem bo albo wykopie to w hektostronnicowych doc'ach (W tym wypadku doc'ach PyQt) albo sie nigdy o nich nie dowiem :D

@Shalom
chodzi Ci o taką sytuacje (monkey-patching):

def do_sth():
    pass

class Someclass():
    pass

Someclass.nowaMetoda() = do_sth()

czy robie coś zle? :P

0

Ja osobiście nie przejmuję się typami. Dlaczego? Bo mam duck typing, więc jedyne co mnie obchodzi w moim programie to by zgadzały się interfejsy. Weźmy np. metodę sum opisaną tak (Ruby):

def sum(seq)
  seq.inject(:+)
end

W Javie to był by ekwiwalent czegoś w stylu (mogą być jakieś błędy):

T sum(Iterable<T> seq) {
  T ret = T.default;
  Iterator<T> it = seq.iterator();
  while (it.hasNext()) {
    ret.add(it.next());
  }
  return ret;
}

Pytanie czy posiadanie tak ogólnego interfejsu jak Iterable coś Ci daje? Tyle, że przez przypadek nie dasz obiektu, który nie posiada iteratorów, ale z kolei nie masz zbytnio możliwości sprawdzenia zawartości tej kolekcji. Czy elementy tej kolekcji będą posiadały metodę add? IDE Ci raczej tego nie podpowie i dowiesz się w czasie kompilacji.

0

To coś w Javie się nie skompiluje, bo bez ograniczenia na T nie masz widocznej metody .add

Żeby ją mieć musiałbyś zdefiniować ją w dodatkowym interfejsie implementowanym przez elementy Iterable'a i kod wyglądałby mniej więcej tak:

<T extends Addable> T sum(Iterable<T> seq) {
  Iterator<T> it = seq.iterator();
  T ret = it.next();
  while (it.hasNext()) {
    ret.add(it.next());
  }
  return ret;
}

Uwaga: wyrzuciłem T.default, bo czegoś takiego nie ma w Javie. Można by przekazać do metody sum obiekt startowy albo wręcz całą monadę dla typu T.

IDE Ci raczej tego nie podpowie i dowiesz się w czasie kompilacji.

Możesz podać jakiś przykład kodu Javowego, które w dobrym IDE Javowym przechodzi, a wywala się podczas kompilacji?

0

@winerfresh

Ja osobiście nie przejmuję się typami. Dlaczego? Bo mam duck typing,

To w takim razie mógłbym prosić o jakiś dobry link lub krótki wykład na temat duck-typingu?:P wiem że ty długo już piszesz w RoR zawodowo, więc ciekawi mnie twoja opinia

A pytanie troche przy okazji:
czym się różni wywołanie klasy tak: "ClassName()" od tak "ClassName"? w przypadku metod nawiasy to wywołanie metody, a brak nawiasów to obiekt metody (nie do konca wiem po co potrzebny, bo nie jestem przyzwyczajony pythonowego stylu jeszcze ;) )
A w wypadku klasy, to jest wywołanie konstruktora (w przypadku nawiasów) lub otrzymanie obiektu klasy (w przypadku braku nawiasów)? Jeśli tak to z czym to się je i po co coś takiego?

0

Jeśli chodzi o artykuł to jest na Wiki to całkiem dobrze opisane.

Zależy w jakim języku. W Pythonie MyClass() to jest wywołanie konstruktora a MyClass to pobranie klasy. W Rubym MyClass() to wywołanie metody MyClass a MyClass to tak samo jak w Pythonie (obiekt konstruuje się przez MyClass.new). Pytanie o co ci chodzi po co coś takiego? Można to stosować w różnych przypadkach, i.e.:

class Post
  class << self
    attr_accessor :renderer
    
    def renderer
      @renderer ||= Redcarpet
    end
  end

  attr_reader :text

  def text=(text)
    @text = self.class.renderer.new.parse(text)
  end
end

Dzięki takiemu zapisowi możesz zrobić coś takiego Post.renderer = Maruku i będziesz używał innego parsera tekstu (przykład częściowo z rzyci więc niespecjalnie może działać). Dzięki takiemu podejściu (Class is first class object) można uprościć trochę rzeczy. W Javie nota bene też coś podobnego istnieje i wygląda jakoś tak (poprawcie jeśli się mylę, Javy nie znam za bardzo co @Wibowit już przedstawił, PS to miało być tylko PoC):

Class<?> klass = MyClass.class;

W wielu przypadkach takie coś upraszcza po prostu implementację niektórych wzorców projektowych i innych struktur poprzez IoC.

1 użytkowników online, w tym zalogowanych: 0, gości: 1