Nie jesteś zalogowany.
Jeśli nie posiadasz konta, zarejestruj je już teraz! Pozwoli Ci ono w pełni korzystać z naszego serwisu. Spamerom dziękujemy!
Prosimy o pomoc dla małej Julki — przekaż 1% podatku na Fundacji Dzieciom zdazyć z Pomocą.
Więcej informacji na dug.net.pl/pomagamy/.
Wszyscy obecni zgadzają się ze stwierdzeniem, że praca w trybie tekstowym nierzadko jest szybsza, wygodniejsza, itd itp, prawda? :) otóż pomyślałem sobie, bash i generalnie shell uniksowy jest OK, ale ma swoje wady.
A jak coś wokół mnie nie działa, to to naprawiam.
Tak w sumie to pozazdrościłem dotnetowcom ich Monada, i możliwości pracy na obiektach (zamiast strumieni tekstu).
Początkowo miałem bardzo ambitny plan napisania własnego shella w Pythonie. Nawet działał. Porwałem sporo kodu z kilku innych projektów, i miał: customizowalny prompt, anonimowe pipe'y, kontrolę zadań (bg, fg, ^Z, jobs, kill, itd), bloki warunkowe i pętle, i parę tam innych bzdur. Gdy zacząłem go przerabiać do pracy na obiektach, zrozumiałem że zwykły shell ze zwykłymi programami nie podoła - każdy program powinien być funkcją w pythonie, a najlepiej obiektem (niech żyje Java...)... Dobra, do rzeczy. Oczywiście projekt upadł, jak wszystkie poprzednie.
Wróciłem na parę tygodni do basha. Pewnego dnia, podczas pracy nad gierką w pygame zacząłem rozglądać się nad narzędziami do debugowania i profilowania kodu w pythonie. No i trafiłem na luźno związanego z tematem IPythona.
Zacytuję z opisu paczki:
IPython can be used as a replacement for the standard Python shell, or it can be used as a complete working environment for scientific computing (like Matlab or Mathematica) when paired with the standard Python scientific and numerical tools. It supports dynamic object introspections, numbered input/output prompts, a macro system, session logging, session restoring, complete system shell access, verbose and colored traceback reports, auto-parentheses, auto-quoting, and is embeddable in other Python programs.[/quote]
W opisie sporo o matematyczno-naukowych zastosowaniach IPy, ale olać to. Prawdziwą moc widać gdy spróbujemy zacząć używać go jako zastępcy dla basha. Oczywiście nie był planowany ani pisany z myślą o tym zastosowaniu, ale czas to naprawić. A że Python jest bardzo pięknym językiem, owa naprawa to żadna robota :)
Pierwszy krok to apt-get install ipython. Po chwili odpalam IPy, i zaczynam się bawić. Już na wstępie IPy sugeruje parę ciekawych opcji: %magic oraz system introspekcji obiektów. Zacznę od tego drugiego.
Powiedzmy że jest jakaś ciekawa fajna komenda, no powiedzmy że ciekawie brzmi. W bashu czy zsh dajemy man <cmd> i wczytujemy się w długi opis. W IPy, powiedzmy:
Kod:
In [1]: ls? Type: System alias Base Class: <type 'tuple'> String Form: (0, 'ls -F') Namespace: Alias Length: 2 Docstring: Alias to the system command: ls -FImho bardzo wygodne. W podobny sposób można sprawdzić zawartość dowolnej zmiennej czy uzyskać szczegółowe info na temat dowolnego obiektu.
Warto zauważyć że jeżeli wyjście nie zmieści się w całości na ekranie, IPy sam się domyśli, że dobrze jest je puścić przez less.
Działa też coś takiego jak dopełnianie nazw tabem. W zwykłym interpreterze Pythona aby uzyskać podobny efekt należy ustawić jakąś zmienną środowiskową która wskaże plik konfiguracyjny i w owym pliku zaimportować kilka modułów, pamiętając o try:...except oczywiście. Nie każdemu się chce :P W IPy dopełnianie działa zarówno dla nazw zmiennych, funkcji, klas, metod, aliasów, magii, jak i ścieżek do plików.
A właśnie, magia. Polecenia takie jak cd, bg czy edit korzystają z "magicznych" funkcji napisanych bezpośrednio w Pythonie. Oczywiście można je dodawać samemu, ale by stało się to opcją należy lekko przetjuningować konfigurację IPy.
Otwieramy plik '~/.ipython/ipythonrc'. Można sobie pozmieniać różne opcyjki, ale zejdźmy do polecenia execfile (tutaj mała uwaga, składnia owego pliku konfiguracyjnego ma niewiele wspólnego ze składnią samego IPy - dlatego zaraz dodamy prawdziwy plik rc). W mojej domyślnej instalacji znajduje się w okolicach linii 570. Dodajemy gdzieś tutaj:
Kod:
execfile ~/.ipythonrc.pyOczywiście nazwę można sobie wybrać :D
Odwiedzamy ów plik i dodajemy następujący kod, (C) by ja, licencja dowolna OSS wedle uznania, gwarancji brak, i tak dalej. No dobra, przerobiłem go z example-magic.py :)
Kod:
def newmagic_hello(self,parameter_s=''): """Tutaj króciutki opis funkcji.""" print "Hello, world!" from IPython.iplib import InteractiveShell for numagic in dir(): if numagic[0:9] == "newmagic_" exec "InteractiveShell.magic_"+numagic[9:]+" = newmagic_"+numagic[9:] exec "del " + numagicTeraz wystarczy dodawać kolejne funkcje według konwencji:
Kod:
def newmagic_nazwafunkcji(self, parameter_s=''): ...Uwaga na listę parametrów, IPy oczekuje dokładnie takiej i żadnej innej (aby uzyskać efekt podobny do argv[1:argc] wystarczy wziąć wynik parameter_s.split(" ")).
No dobra, i co w tym takiego zajefajnego? Otóż pomyślałem o wykorzystaniu modułu pickle aby transportować obiekty pomiędzy owymi magicznymi funkcjami. Ale możliwe że ktoś wpadnie na lepszy pomysł. Na początek jednak wziąłem już na stół polecenia ps, kill, i tym podobne. Możliwe że kiedyś "[]: ps | where user wredna_siostra | kill" stanie się rzeczywistością :D
Niedawno byłem wielkim fanem "zwykłego" interpretera Pythona. Jednakże po pracy z CLispem brakowało mi automatycznego odpalania debuggera przy wyjątkach. Otóż można skonfigurować IPy (tylko już nie pamiętam gdzie :P) by przy niepochwyconym wyjątku uruchamiał pdb. I od CLispa różni się też tym, że można z niego wyjść szybkim ^D. To taki sajdnołt.
A właśnie - apropos lispa. Znienawidziłem nawiasy. Toteż bardzo ucieszyłem się z kolejnej magii: [b]nawiasy są w IPy mniej więcej zbędne[/b]. Mniej więcej tak (fragmencik sesji):
Kod:
In [4]: str 4+3j ------> str(4+3j) Out[4]: '(4+3j)' In [5]: def foo(bar): ...: print bar ...: In [6]: foo 'masakra!' ------> foo('masakra!') masakra!O ile zestaw parametrów dla funkcji jest jednoznaczny (na przykład nie próbujemy wdusić samych dwóch czy trzech krotek, co IPy może pomylić z wywołaniem rezultatu funkcji jako kolejnej funkcji), nawiasy okazują się zbędne. Działa też na obiektach:
Kod:
In [7]: class bar: ...: def __init__(self): ...: pass ...: In [8]: bee = bar() In [9]: foo bee ------> foo(bee) <__main__.bar instance at 0xb77e7f2c> In [10]: foo bar -------> foo(bar) __main__.barZ przydatnych bajerów jest też autoquote. Czasem tak mi się absolutnie nie chce wpisywać cudzysłowów że aż się zastanawiam czy autorzy IPy nie czytali moich myśli gdy zastanawiali się jak jeszcze można ulepszyć ten program:
Kod:
In [11]: ;foo bar -------> foo("bar") barCzyli wystarczy poprzedzić nazwę funkcji średnikiem. Gwoli ścisłości, działa też z przecinkiem, tylko nie kojarzę różnicy...
Podczas tworzenia mojej gierki zainteresowałem się też wątkami w Pythonie. IPy ma jednakże coś o wiele piękniejszego od modułów thread i threading; wątki można startować podobnie jak z użyciem & w bashu, podając po prostu nazwę funkcji do wywołania jako argument dla polecenia bg:
Kod:
In [12]: bg foo('meow') Starting job # 0 in a separate thread. In [13]: meow In [14]:Jak to już bywa z m-t I/O jest kiepsko zsynchronizowane :P
Nic mi nie wiadomo na temat jakiejkolwiek obsługi zwykłych anonimowych pipe'ów, jednak skoro pracujemy na obiektach, nie robi to aż takiej różnicy. Pracuję właśnie nad dostosowaniem IPy do normalnej pracy, tak aby stał się w praktyce zamiennikiem dla uniksowego shella, i na liście TODO umieściłem implementację łatwych w użyciu ekwiwalentów wszystkich standardowych poleceń uniksa. Jak będzie gotowe to gdzieś porzucę.
Aha, no i na koniec (ktoś doczytał aż tutaj!?) gdyby ktoś zatęsknił za bashem, można wywoływać normalne polecenia powłoki, poprzedzając je wpierw wykrzyknikiem, ot tak:
Kod:
In [14]: !ls /usr/share/doc | grep python ipython python python2.4 python2.4-minimal python-apt python-beagle python-cairo (ciach...)Dla mnie IPython jest przedłużeniem zwykłego shella Pythona. Jest do innych shelli niczym fvwm do innych menedżerów okien. Jest do innych języków programowania jak... No, tutaj nie mam porównania... Nieważne. Jest po prostu genialny.
Aha, jest też automatyczna indentacja, numerowanie I/O (można się dostać do wyników poprzednich poleceń), aliasy dla komend basha, pełne wsparcie readline (wraz z reverse I-search), zapisywanie sesji (aczkolwiek tego jeszcze nie próbowałem), bardzo ślicznie pokolorowane ślady przy nieobsłużonych wyjątkach, o debugerze wspominałem, magiczne ? potrafi też ponoć jakoś wyświetlać pełny kod klas i funkcji, historia katalogów odwiedzanych przez cd, i pewnie jeszcze pełno innych rzeczy, które odkryję jak tylko zechce mi się spojrzeć w kod :D
Wszystkim kochającym środowisko tekstowe, i/lub ewentualnie Pythona, polecam pobawić się trochę z tą paczką, bo to jest po prostu genialne. O tym że IPy jest moją powłoką logowania już wspominałem? :)
[ /\/\/\ o_0 ----->>> Ascii Art Userbar User ]
"steal and steal and steal some more and give it to all your friends and keep on stealin'"
- Reznor
Offline
Ciekawy tekst. :)
Offline
Przykleić!!
Offline
Również uważam, że jest to bardzo przydatny i wartościowy artykuł. Dzięki :)
Offline
[img]http://wstaw.org/m/2017/09/21/download.jpg[/img]
Offline
Time (s) | Query |
---|---|
0.00012 | SET CHARSET latin2 |
0.00004 | SET NAMES latin2 |
0.00128 | SELECT u.*, g.*, o.logged FROM punbb_users AS u INNER JOIN punbb_groups AS g ON u.group_id=g.g_id LEFT JOIN punbb_online AS o ON o.ident='3.12.34.209' WHERE u.id=1 |
0.00080 | REPLACE INTO punbb_online (user_id, ident, logged) VALUES(1, '3.12.34.209', 1732349065) |
0.00045 | SELECT * FROM punbb_online WHERE logged<1732348765 |
0.00036 | SELECT topic_id FROM punbb_posts WHERE id=74203 |
0.00093 | SELECT id FROM punbb_posts WHERE topic_id=9573 ORDER BY posted |
0.00050 | SELECT t.subject, t.closed, t.num_replies, t.sticky, f.id AS forum_id, f.forum_name, f.moderators, fp.post_replies, 0 FROM punbb_topics AS t INNER JOIN punbb_forums AS f ON f.id=t.forum_id LEFT JOIN punbb_forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=3) WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.id=9573 AND t.moved_to IS NULL |
0.00023 | SELECT search_for, replace_with FROM punbb_censoring |
0.00132 | SELECT u.email, u.title, u.url, u.location, u.use_avatar, u.signature, u.email_setting, u.num_posts, u.registered, u.admin_note, p.id, p.poster AS username, p.poster_id, p.poster_ip, p.poster_email, p.message, p.hide_smilies, p.posted, p.edited, p.edited_by, g.g_id, g.g_user_title, o.user_id AS is_online FROM punbb_posts AS p INNER JOIN punbb_users AS u ON u.id=p.poster_id INNER JOIN punbb_groups AS g ON g.g_id=u.group_id LEFT JOIN punbb_online AS o ON (o.user_id=u.id AND o.user_id!=1 AND o.idle=0) WHERE p.topic_id=9573 ORDER BY p.id LIMIT 0,25 |
0.00085 | UPDATE punbb_topics SET num_views=num_views+1 WHERE id=9573 |
Total query time: 0.00688 s |