Wprowadzenie
Witamy w książce Python mniej poważnie. Korzystając z języka programowania Python, będziemy w niej odkrywać Marsa, Jowisza i najdalsze zakątki galaktyki, dusze poetów, świat wielkich finansów, podziemia szpiegostwa i fałszowania głosów, oszustwa w teleturniejach i znacznie więcej. Użyjemy łańcuchów Markowa do napisania haiku, symulacji Monte Carlo do modelowania rynków finansowych, uśredniania obrazów do usprawnienia naszej astrofotografii oraz algorytmów
genetycznych do wyhodowania armii gigantycznych szczurów, zdobywając jednocześnie doświadczenie w pracy z takimi modułami jak pygame, Pylint, pydocstyle, tkinter, python-docx, matplotlib i pillow. Przede wszystkim jednak będziemy się dobrze bawić.
Dla kogo jest ta książka?
Książkę tę można traktować jako drugi podręcznik do nauki Pythona. Została ona zaprojektowana w taki sposób, aby można ją było wykorzystywać jako uzupełnienie książki dla początkujących lub kursu wprowadzającego. Dzięki niej można będziesz w stanie kontynuować samodzielną naukę, stosując podejście oparte na projektach, bez marnowania pieniędzy lub miejsca na półce na dokładne przerabianie pojęć, które już znasz. Nie martw się jednak, że zostaniesz bez pomocy - cały kod jest odpowiednio opisany i objaśniony.
Projekty te przeznaczone są dla każdego, kto chce używać programowania do przeprowadzania eksperymentów, testowania teorii, symulowania natury lub po prostu do zabawy. Mowa tutaj również o osobach, które wykorzystują programowanie w swojej pracy (np. naukowcy lub inżynierowie), ale które nie są tak naprawdę programistami, a także osobach, które nazywam "zdeterminowanymi niespecjalistami" - dyletantami i amatorami, którzy czerpią przyjemność z rozwiązywania problemów programistycznych w wolnym czasie. Jeśli chciałeś pobawić się prezentowanymi tu koncepcjami, ale rozpoczynanie potencjalnie skomplikowanych projektów od zera uznałeś za zbyt trudne lub czasochłonne, to ta książka jest dla Ciebie.
Co jest w tej książce?
W miarę wykonywania tych projektów, będziesz pogłębiać swoją wiedzę na temat przydatnych bibliotek i modułów języka Python, poznawać nowe skróty, wbudowane funkcje i pomocne techniki, a także ćwiczyć projektowanie, testowanie i optymalizowanie programów. Dodatkowo będziesz w stanie przełożyć wykonywaną pracę na rzeczywiste aplikacje, zbiory danych i problemy.
Cytując Ralpha Waldo Emersona, "nigdy nie osiągnięto niczego wielkiego bez entuzjazmu", a dotyczy to również uczenia się. Ostatecznym celem tej książki jest pobudzić Twoją wyobraźnię i pomóc Ci samodzielnie rozwijać interesujące projekty. Nie przejmuj się, jeśli na początku będą Ci się one wydawać zbyt ambitne. Odrobina staranności połączona z dużą ilością googlowania mogą zdziałać cuda - i to dużo szybciej niż myślisz
Poniżej znajduje się krótkie omówienie rozdziałów zawartych w tym podręczniku. Nie musisz czytać ich po kolei, ale najłatwiejsze projekty znajdują się na początku książki, a do tego nowe pojęcia, moduły i techniki omawiam bardziej szczegółowo, gdy są one prezentowane po raz pierwszy.
Rozdział 1: Generator zabawnych pseudonimów Ten "rozgrzewkowy" projekt wprowadza przewodniki po stylach Python PEP 8 i PEP 257, jak również moduły Pylint i pydocstyle, które analizują zgodność naszego kodu z tymi wskazówkami. Końcowym produktem jest generator zabawnych pseudonimów zainspirowany serialem telewizyjnym Psych.
Rozdział 2: Znajdowanie zaklęć Naucz się profilować swój kod, starając się uchronić czarodziejkę Zatannę przed bolesną śmiercią. Przeszukaj słowniki online pod kątem magicznych palindromów wielowyrazowych, których Zatanna potrzebuje do pokonania cofającego czas wroga.
Rozdział 3: Rozwiązywanie anagramów Napisz program, który pomaga użytkownikowi utworzyć frazę anagramową z jego imienia i nazwiska. Przykładowo Clint Eastwood daje w rezultacie old west action. Następnie pomóż Tomowi Marvolo Riddle'owi utworzyć jego anagram, "I am Lord Voldemort" przy użyciu sit lingwistycznych.
Rozdział 4: Dekodowanie szyfrów z amerykańskiej wojny domowej Zbadaj i złam jeden z najbardziej udanych szyfrów wojskowych w historii - szyfr trasowy Unii. Następnie pomóż szpiegom po obu stronach wysłać i zdekodować sekretne komunikaty za pomocą zygzakującego szyfru płotkowego.
Rozdział 5: Kodowanie szyfrów z brytyjskiej wojny domowej Odczytaj wiadomość ukrytą w tekście, dekodując szyfr z czasów brytyjskiej wojny domowej. Następnie uratuj Marię, królową Szkotów, projektując i stosując kod, który pozwoli jej wykonać trudniejsze zadanie, jakim jest napisanie ukrytej wiadomości.
Rozdział 6: Pisanie atramentem sympatycznym Pomóż kretowi w firmie zdradzić ojca Sherlocka Holmesa i uniknąć wykrycia, wykorzystując do tego celu elektroniczny atrament sympatyczny. Rozdział ten oparty jest na odcinku serialu Elementary.
Rozdział 7: Hodowanie olbrzymich szczurów za pomocą algorytmów genetycznych Użyj algorytmów genetycznych - zainspirowanych ewolucją Darwina - do wyhodowania rasy superszczurów o rozmiarze suczki rasy Bulmastif. Następnie pomóż Jamesowi Bondowi złamać w mgnieniu oka kod sejfu z 10 miliardami możliwych kombinacji.
Rozdział 8: Zliczanie sylab w wierszach haiku Naucz swój komputer zliczać sylaby w języku angielskim jako wstęp do pisania w kolejnym rozdziale japońskich wierszy, nazywanych haiku.
Rozdział 9: Pisanie haiku z użyciem łańcuchów Markowa Naucz swój komputer pisać haiku poprzez połączenie modułu do zliczania sylab z rozdziału 8 z łańcuchami Markowa i korpusem szkoleniowym złożonym z kilkuset starożytnych i nowoczesnych haiku.
Rozdział 10: Czy jesteśmy sami? Poznawanie paradoksu FermiegoZbadaj nieobecność pozaziemskich sygnałów radiowych za pomocą równania Drake'a, wymiary Drogi Mlecznej oraz założenia dotyczące rozmiaru wykrywalnych "bąbli emisji". Zapoznaj się z popularnym modułem tkinter i wykorzystaj go do utworzenia graficznej reprezentacji galaktyki i własnego bąbla radiowego Ziemi.
Rozdział 11: Problem Monty'ego Halla Pomóż najmądrzejszej kobiecie na świecie wygrać spór dotyczący problemu Monty'ego Halla. Następnie użyj programowania obiektowego do utworzenia wersji popularnej gry Monty'ego z użyciem zabawnego interfejsu graficznego.
Rozdział 12: Zabezpieczanie kwoty na specjalny cel Zaplanuj swoją (lub swoich rodziców) bezpieczną emeryturę za pomocą symulacji finansowej z użyciem metody Monte Carlo.
Rozdział 13: Symulowanie pozaziemskiego wulkanu Użyj modułu pygame do zasymulowania erupcji wulkanicznej na Io, jednym z księżyców Jowisza.
Rozdział 14: Odwzorowywanie Marsa za pomocą sondy Mars Orbiter Zbuduj grę arkadową opartą na grawitacji i spróbuj umieścić satelitę na kołowej orbicie odwzorowywania, starając się przy tym nie zużyć całego paliwa i nie spłonąć w atmosferze. Wyświetlaj odczyty kluczowych parametrów, śledź ścieżki orbitalne, dodaj cień planety i powoli obracaj Marsa wokół jego osi, a wszystko to przy poznawaniu mechaniki orbitalnej!
Rozdział 15: Usprawnianie astrofotografii za pomocą uśredniania planet Ujawnij pasy chmur oraz Wielką Czerwoną Plamę na Jowiszu poprzez optyczne uśrednienie słabej jakości klatek wideo za pomocą biblioteki Pythona do manipulowania obrazami. Naucz się pracować z plikami, folderami i ścieżkami do katalogów przy użyciu wbudowanych modułów os i shutil.
Rozdział 16: Znajdowanie oszustw za pomocą prawa Benforda Użyj prawa Benforda do zbadania fałszerstw w amerykańskich wyborach prezydenckich z 2016 roku. Użyj modułu matplotlib do podsumowania wyników w formie wykresu.
Każdy rozdział kończy się przynajmniej jednym ćwiczeniem lub trudniejszym projektem.
Dla każdego z ćwiczeń podane jest rozwiązanie. Nie oznacza to jednak, że jest to najlepsze rozwiązanie - możliwe, że uda Ci się uzyskać coś lepszego, tak więc nie podglądaj!
W przypadku trudniejszych projektów będziesz jednak zdany wyłącznie na siebie. Gdy Cortez zaatakował Meksyk w 1519 roku, spalił on swoje karawele, tak aby jego konkwistadorzy wiedzieli, że nie ma już drogi powrotnej i że będą oni musieli stawić czoło Aztekom z okrutną i niezachwianą determinacją. Z tego powodu wyrażenie "spalić za sobą mosty" (oryginalnie "burn your boats", czyli dosł. "spalić swoje łodzie") oznacza dziś entuzjazm lub pełne zaangażowanie w realizowane zadanie. W taki właśnie sposób należy stawić czoło tym wyzwaniom - jak gdyby Twoje łodzie były spalone. Gdy to zrobisz, prawdopodobnie nauczysz się więcej z tych ćwiczeń niż z jakiejkolwiek innej części tej książki!
Wersja Pythona, platforma i IDE
Każdy z projektów tej książki skonstruowałem przy użyciu Pythona w wersji 3.5 w środowisku Windows 10. Jeśli używasz innego systemu operacyjnego, to nie powinieneś mieć żadnych problemów: w odpowiednich miejscach podaję kompatybilne moduły dla innych platform.
Przykłady kodu oraz zrzuty ekranu prezentowane w tej książce pochodzą albo z edytora tekstowego Python IDLE, albo z powłoki interaktywnej. IDLE to skrót od Integrated Development and Learning Environment. Jest to zintegrowane środowisko programowania (IDE) z dodaną literą L, tak aby akronim ten odnosił się do znanego z Monty Pythona Erica Idle. Powłoka interaktywna, nazywana również interpretatorem, jest oknem, które pozwala na natychmiastowe wykonywanie poleceń i testowanie kodu bez potrzeby tworzenia plików.
IDLE ma jednak kilka wad, takich jak brak kolumny z numerami wierszy, ale jest za to darmowy i dostarczany z Pythonem, więc każdy ma do niego dostęp. Jeśli tylko chcesz, to możesz bez przeszkód używać innego IDE. Do pobrania dostępnych jest wiele innych produktów, takich jak Geany (wymawiane jak angielskie słowo genie), PyCharm czy PyScripter. Geany działa na wielu systemach operacyjnych, łącznie z Uniksem, macOS i Windows. PyCharm działa w Linuksie, systemie Windows i macOS, natomiast PyScripter w systemie Windows. Pełna lista dostępnych narzędzi deweloperskich dla języka Python i kompatybilnych platform znajduje się na stronie https://wiki.python.org/moin/DevelopmentTools/.
Kod
Dla każdego z projektów tej książki podane są wszystkie wiersze kodu. Zachęcam do wprowadzania ich ręcznie wszędzie tam, gdzie to możliwe. Pewien nauczyciel powiedział mi kiedyś, że "uczymy się za pomocą naszych rąk" i muszę się zgodzić, że ręczne wprowadzanie kodu sprawia, iż przykładamy wtedy maksymalną uwagę do tego, co robimy.
Jeśli jednak potrzebujesz szybko całego projektu lub przypadkowo usuniesz całą swoją pracę, to cały jego kod, wraz a rozwiązaniami ćwiczeń, możesz pobrać ze strony https://www.nostarch.com/impracticalpython/.
Styl kodu
Ta książka poświęcona jest rozwiązywaniu problemów i zabawie, tak więc kod może czasami odbiegać od dobrych praktyk i szczytowej wydajności. Okazjonalnie będziemy wykorzystywać wyrażenia listowe lub specjalne operatory, ale w większości przypadków skupimy się na prostym i zrozumiałym kodzie, który ułatwi nam naukę.
Tego rodzaju uproszczenie jest ważne dla programujących nieprogramistów, którzy będą czytać tę książkę. Większość ich kodu może być "kodem Kleenex", czyli użytym jedno- lub dwukrotnie dla określonego celu, a następnie wyrzuconym. Jest to rodzaj kodu, który może być udostępniony kolegom lub narzucony im z powodu zmian kadrowych, tak więc powinien on być łatwy do czytania i zrozumienia.
Cały główny kod projektów jest opisany i objaśniony w standardowym stylu i zazwyczaj zgodny ze wskazówkami zawartymi w przewodniku Python Enhancement Proposal 8, znanym również jako PEP 8. Szczegóły dotyczące wytycznych PEP 8 i oprogramowania pozwalającego na ich honorowanie znajdują się w rozdziale 1.
Gdzie uzyskać pomoc?
Podejmowanie wyzwania programistycznego może stanowić pewien problem. Kodowanie nie zawsze jest czymś, co możemy intuicyjnie rozgryźć - nawet przy użyciu tak przyjaznego języka jak Python. W ramach kolejnych rozdziałów będę podawał linki i odwołania do przydatnych źródeł informacji, ale w przypadku projektów tworzonych samodzielne nic nie zastąpi wyszukiwarki internetowej.
Aby móc z powodzeniem wyszukiwać informacje, musisz najpierw wiedzieć, o co chcesz zapytać. Może to być z początku frustrujące, ale pomyśl o tym jak o grze w dwadzieścia pytań. Udoskonalaj swoje słowa kluczowe wraz każdym kolejnym wyszukiwaniem, aż znajdziesz konkretną odpowiedź lub osiągniesz punkt malejących zysków.
Jeśli poszukiwania w książkach i w sieci zawiodą, to kolejnym krokiem będzie poproszenie kogoś o pomoc. Możesz to zrobić online za opłatą lub za darmo na takich forach jak Stack Overflow (https://stackoverflow.com/). Pamiętaj jednak, że członkowie tych stron nie znoszą głupców. Zanim coś napiszesz, upewnij się, że zapoznałeś się z ich stronami "Jak należy zadawać pytania?". Jedną z takich stron w witrynie Stack Overflow możesz przykładowo znaleźć pod adresem http://stackoverflow.com/help/how-to-ask/.
Naprzód!
Dziękuję, że poświęciłeś czas na przeczytanie tego wprowadzenia! Z pewnością chcesz wyciągnąć z tej książki tak wiele, jak to tylko możliwe, i jest to dobry początek. Gdy dojdziesz do drugiego końca tej książki, będziesz bardziej biegły w Pythonie i lepiej przygotowany do rozwiązywania złożonych rzeczywistych problemów. Ruszajmy do pracy.
1 .Generator zabawnych pseudonimów
Swego czasu na kanale telewizyjnym USA Network emitowany był komediodramat detektywistyczny zatytułowany Psych1, w którym obdarzony niesamowitą spostrzegawczością szpieg amator Sean rozwiązywał kolejne sprawy, udając przy tym medium. Znakiem firmowym serialu był sposób, w jaki Sean przedstawiał swojego pomocnika Gusa, posługując się wymyślanymi na poczekaniu
zabawnymi pseudonimami, takimi jak Galileo Humpkins, Lavender Gooms czy Bad News Marvin Barnes. Wywarło to na mnie wrażenie, ponieważ przed laty jeden z pracowników agencji Census Bureau2 dał mi listę prawdziwych nazwisk, które były tak samo dziwne, jak te wymyślane przez Seana.
Projekt 1: Generowanie pseudonimów
W ramach tego projektu, w formie rozgrzewki, napiszemy prosty program w Pythonie do generowania zwariowanych nazw poprzez losowe łączenie ze sobą imion i nazwisk. Przy odrobinie szczęścia uda nam się wygenerować szereg aliasów, z których niejeden pomocnik byłby dumny. Powtórzymy również najlepsze praktyki kodowania i wykorzystamy zewnętrzne programy, które pomogą nam pisać kod spełniający te wytyczne.
Jeśli nie darzysz sympatią serialu Psych, możesz zastąpić nazwy z mojej listy w kodzie, używając własnych żartów lub motywu przewodniego. Z łatwością możemy zmienić ten projekt w generator imion z serialu Gra o tron, bądź też odkryć prywatne nazwisko "Benedicta Cumberbatcha". Moim ulubionym jest Bendylick Cricketbat.
Cel
Losowe generowanie śmiesznych imion i nazwisk dla pomocników za pomocą kodu w Pythonie, który jest zgodny z przyjętym stylem kodowania.
Planowanie i tworzenie projektu
Czas poświęcony na planowanie nigdy nie jest czasem straconym. Nie ma znaczenia, czy programujemy dla zabawy, czy dla zysku - w pewnym momencie będziemy musieli oszacować (dosyć dokładnie), jak długo zajmie nam tworzenie danego projektu, jakie przeszkody możemy napotkać, oraz jakie narzędzia i zasoby będą nam potrzebne do wykonania tej pracy. Abyśmy jednak byli w stanie to zrobić, musimy najpierw wiedzieć, co tak naprawdę chcemy stworzyć!
Pewien odnoszący sukcesy menedżer powiedział mi kiedyś, że jego sekretem jest po prostu zadawanie mnóstwa pytań: Co próbujesz zrobić? Dlaczego to robisz? Dlaczego robisz to w ten sposób? Ile masz czasu? Ile masz pieniędzy? Odpowiadanie na te pytania jest bardzo pomocne w procesie projektowania i daje nam czyste pole widzenia.
W swojej książce Myśl w języku Python! Nauka programowania3, Allen Downey opisuje dwa rodzaje planów projektowania przy tworzeniu oprogramowania: "prototyp i poprawki" oraz "projektowane programowanie". W przypadku prototypu i poprawek rozpoczynamy od prostego programu, a następnie za pomocą poprawek (wyedytowanego kodu) obsługujemy problemy napotkane podczas testowania. Podejście to może być przydatne, gdy staramy się rozwiązać złożony problem, którego nie rozumiemy zbyt dobrze. Może ono jednak również wytwarzać skomplikowany i zawodny kod. Jeśli dobrze rozumiemy problem i znamy sposób jego rozwiązania, powinniśmy posłużyć się planem zaprojektowanego programowania, aby uniknąć przyszłych problemów i ich późniejszych poprawek. Podejście to może sprawić, że kodowanie będzie łatwiejsze i bardziej wydajne, a do tego zwykle prowadzi ono do trwalszego i bardziej solidnego kodu.
Wszystkie projekty w tej książce rozpoczynać będziemy od jasno zdefiniowanego problemu lub celu, który będzie podstawą do naszych decyzji projektowych. Następnie omawiać będziemy strategię w celu lepszego zrozumienia problemów i utworzenia planu projektowanego programowania.
Strategia
Rozpoczniemy od dwóch list, first i last, które przechowywać będą śmieszne imiona i nazwiska. Listy te będą względnie krótkie, więc nie będą one wymagać dużej ilości pamięci, nie będą musiały być dynamicznie aktualizowane i nie powinny stwarzać żadnych problemów w czasie działania. Ponieważ będziemy jedynie odczytywać nazwy zawarte w tych listach, jako kontener wykorzystamy krotkę.
Mając zdefiniowane dwie krotki z imionami i nazwiskami, za dotknięciem klawisza będziemy generować nowe nazwy, łącząc w pary imiona i nazwiska. W ten sposób użytkownik będzie mógł łatwo powtarzać ten proces, aż do uzyskania wystarczająco śmiesznego wyniku.
Powinniśmy również w jakiś sposób uwydatnić to imię i nazwisko w oknie interpretatora, tak aby wyróżniało się ona na tle innych poleceń. Powłoka IDLE nie dostarcza zbyt wielu opcji związanych z czcionką, ale jak wiemy - i to nazbyt dobrze - błędy oznaczane są kolorem czerwonym. Domyślnie funkcja print() wypisuje informacje na standardowe wyjście, ale po załadowaniu modułu sys możemy przekierować wyjście na standardowy kanał błędów (wraz z jego charakterystyczną czerwoną kolorystyką) za pomocą parametru file: print(coś, file=sys.stderr).
Na koniec ustalimy, jakie rekomendacje dotyczące stylu kodowania istnieją dla programowania w Pythonie. Wytyczne te powinny dotyczyć nie tylko samego kodu, ale także dokumentacji zagnieżdżonej w obrębie tego kodu.
Pseudokod
"Na Amerykanów zawsze można liczyć, że jak już wyczerpią wszystkie złe rozwiązania, wreszcie zastosują właściwe". Cytat ten, luźno wiązany z Winstonem Churchillem, podsumowuje sposób, w jaki wiele osób podchodzi do pisania pseudokodu.
Pseudokod jest ogólnym, nieformalnym sposobem opisywania programów komputerowych za pomocą ustrukturyzowanego języka - angielskiego lub dowolnego innego języka ludzkiego. Powinien on przypominać uproszczony język programowania i zawierać słowa kluczowe oraz odpowiednie wcięcia. Dzięki niemu deweloperzy mogą pominąć całą nieprzeniknioną składnię prawdziwych języków programowania i skupić się na podstawowej logice. Mimo że jest on używany na szeroką skalę, pseudokod nie ma żadnego oficjalnego standardu, a jedynie wytyczne.
Jeśli w pewnym momencie poczujemy się sfrustrowani, to może być to spowodowane tym, że nie poświęciliśmy czasu na napisanie pseudokodu. Głęboko w to wierzę, ponieważ pseudokod zawsze - bez wyjątków - prowadził mnie w kierunku rozwiązań, gdy przed jego napisaniem nie mogłem sobie z czymś poradzić. Z tego względu w większości projektów w tej książce używać będziemy pewnego rodzaju pseudokodu. Mam nadzieję, że dostrzeżesz jego użyteczność, ale liczę również na to, że zdyscyplinujesz się do pisania go w swoich własnych projektach.
Bardzo ogólny pseudokod dla naszego generatora śmiesznych pseudonimów może wyglądać tak:
Wczytaj listę imion
Wczytaj listę nazwisk
Wybierz losowo imię
Przypisz to imię do zmiennej
Wybierz losowo nazwisko
Przypisz to nazwisko do zmiennej
Wypisz te nazwy na ekranie w odpowiedniej kolejności i w kolorze czerwonym
Zapytaj użytkownika, czy chce grać dalej
Jeśli użytkownik gra dalej:
powtórz
Jeśli użytkownik chce zakończyć
zakończ i zamknij program
Jeśli nie staramy się zaliczyć jakiegoś kursu programowania lub dostarczyć jasnych instrukcji innym osobom, powinniśmy się skupić na celu tego pseudokodu i nie zawracać sobie głowy niewolniczym stosowaniem się do (nieustandaryzowanych) wytycznych dotyczących jego pisania. Nie poprzestawajmy również na samym programowaniu - proces pisania pseudokodu możemy stosować do wielu innych rzeczy. Gdy już się do niego przyzwyczaimy, zauważymy, że pomaga nam on realizować inne zadania, takie jak obliczanie podatków, planowanie inwestycji, budowanie domu czy przygotowywanie wyjazdu na kemping. Jest to świetny sposób na zebranie myśli i przeniesienie sukcesów z programowania do prawdziwego życia.
Kod
Listing 1.1 zawiera kod generatora pseudonimów, pseudonyms.py, który kompiluje się i wypisuje ich listę z dwóch krotek zawierających imiona i nazwiska. Jeśli nie chcesz wpisywać wszystkich nazw, możesz wpisać ich podzbiór lub pobrać ten kod w całości ze strony https://nostarch.com/impracticalpython/.
pseudonyms.py
import sys, random
print("Welcome to the Psych 'Sidekick Name Picker.'\n")
print("A name just like Sean would pick for Gus:\n\n")
first = ('Baby Oil', 'Bad News', 'Big Burps', "Bill 'Beenie-Weenie'",
"Bob 'Stinkbug'", 'Bowel Noises', 'Boxelder', "Bud 'Lite' ",
'Butterbean', 'Buttermilk', 'Buttocks', 'Chad', 'Chesterfield',
'Chewy', 'Chigger", "Cinnabuns', 'Cleet', 'Cornbread', 'Crab Meat',
'Crapps', 'Dark Skies', 'Dennis Clawhammer', 'Dicman', 'Elphonso',
'Fancypants', 'Figgs', 'Foncy', 'Gootsy', 'Greasy Jim', 'Huckleberry',
'Huggy', 'Ignatious', 'Jimbo', "Joe 'Pottin Soil'", 'Johnny',
'Lemongrass', 'Lil Debil', 'Longbranch', '"Lunch Money"',
'Mergatroid', '"Mr Peabody"', 'Oil-Can', 'Oinks', 'Old Scratch',
'Ovaltine', 'Pennywhistle', 'Pitchfork Ben', 'Potato Bug',
'Pushmeet','Rock Candy', 'Schlomo', 'Scratchensniff', 'Scut',
"Sid 'The Squirts'", 'Skidmark', 'Slaps', 'Snakes', 'Snoobs',
'Snorki', 'Soupcan Sam', 'Spitzitout', 'Squids', 'Stinky',
'Storyboard', 'Sweet Tea', 'TeeTee', 'Wheezy Joe',
"Winston 'Jazz Hands'", 'Worms')
last = ('Appleyard', 'Bigmeat', 'Bloominshine', 'Boogerbottom',
'Breedslovetrout', 'Butterbaugh', 'Clovenhoof', 'Clutterbuck',
'Cocktoasten', 'Endicott', 'Fewhairs', 'Gooberdapple', 'Goodensmith',
'Goodpasture', 'Guster', 'Henderson', 'Hooperbag', 'Hoosenater',
'Hootkins', 'Jefferson', 'Jenkins', 'Jingley-Schmidt', 'Johnson',
'Kingfish', 'Listenbee', "M'Bembo", 'McFadden', 'Moonshine', 'Nettles',
'Noseworthy', 'Olivetti', 'Outerbridge', 'Overpeck', 'Overturf',
'Oxhandler', 'Pealike', 'Pennywhistle', 'Peterson', 'Pieplow',
'Pinkerton', 'Porkins', 'Putney', 'Quakenbush', 'Rainwater',
'Rosenthal', 'Rubbins', 'Sackrider', 'Snuggleshine', 'Splern',
'Stevens', 'Stroganoff', 'Sugar-Gold', 'Swackhamer', 'Tippins',
'Turnipseed', 'Vinaigrette', 'Walkingstick', 'Wallbanger', 'Weewax',
'Weiners', 'Whipkey', 'Wigglesworth', 'Wimplesnatch', 'Winterkorn',
'Woolysocks')
while True:
firstName = random.choice(first)
lastName = random.choice(last)
print("\n\n")
print("{} {}".format(firstName, lastName), file=sys.stderr)
print("\n\n")
try_again = input("\n\nTry again? (Press Enter else n to quit)\n ")
if try_again.lower() == "n":
break
input("\nPress Enter to exit.")
Listing 1.1. Generowanie śmiesznych pseudonimów na podstawie krotek z nazwami
Najpierw importujemy moduły sys i random . Modułu sys użyjemy w celu uzyskania dostępu do funkcjonalności związanej z komunikatami o błędach konkretnego systemu, dzięki czemu będziemy mogli pokolorować nasze wyjście w oknie IDLE na przykuwający uwagę kolor czerwony. Z kolei moduł random pozwoli nam wybierać w sposób losowy elementy z naszych list z imionami i nazwiskami.
Instrukcje print w punkcie przedstawiają program użytkownikowi. Polecenie \n wymusza przejście do nowego wiersza, natomiast znaki pojedynczego cudzysłowu '' pozwalają nam używać cudzysłowu w wydruku bez konieczności stosowania znaku ucieczki (ukośnik wsteczny), który znacząco by pogorszył czytelność kodu.
Następnie definiujemy nasze krotki z imionami i nazwiskami, po czym inicjujemy pętlę while . Ustawienie zmiennej while = True oznacza po prostu "wykonuj, dopóki nie powiem, kiedy przestać". Ostatecznie użyjemy instrukcji break, aby zakończyć działanie pętli.
Pętla rozpoczyna się od losowego wyboru imienia z krotki first, po czym następuje przypisanie tego imienia do zmiennej firstName . W celu zwrócenia losowego elementu z niepustego ciągu - w tym wypadku krotki z imionami - wykorzystujemy metodę choice z modułu random.
Następnie wybieramy losowo nazwisko z krotki last i przypisujemy je do zmiennej lastName . Gdy mamy już oba te elementy, wypisujemy je i poprzez dostarczenie opcjonalnego argumentu file=sys.stderr do instrukcji print nakłaniamy interpreter IDLE do użycia czerwonej czcionki dla błędów. Do konwersji zmiennych przechowujących imię i nazwisko na ciągi znakowe użyjemy nowszej metody formatowania ciągów znaków zamiast starszego operatora formatowania ciągów znaków (%). Więcej informacji na temat tej nowej metody można znaleźć pod adresem https://docs.python.org/3.7/library/string.html.
Po wyświetleniu nazwy pytamy użytkownika, czy chce zagrać jeszcze raz, czy zakończyć. Używamy do tego funkcji input(), w ramach której podajemy instrukcję w cudzysłowie. W tym przypadku, aby zapewnić lepszą czytelność śmiesznych pseudonimów w oknie interpretera IDLE, wstawiamy dodatkowo kilka pustych wierszy. Jeśli użytkownik odpowie, wciskając klawisz enter, nic nie zostanie zwrócone do zmiennej try_again . Wówczas warunek w instrukcji if nie zostanie spełniony, pętla while będzie kontynuować swoje działanie i zostanie wyświetlona nowa nazwa. Jeśli zamiast tego użytkownik wciśnie klawisz N, wówczas instrukcja if spowoduje wykonanie polecenia break, przez co pętla zakończy się, ponieważ instrukcja while nie będzie już dłużej wyznaczać wartości True. Aby wyeliminować potencjalny wpływ klawisza capslock gracza, możemy posłużyć się metodą .lower(), która zamienia wszystkie znaki w ciągu na małe litery. Innymi słowy, nie ma znaczenia, czy użytkownik wprowadza dużą, czy małą literę N, ponieważ program zawsze będzie odczytywał ją jako małą.
Na koniec prosimy użytkownika o wyjście za pomocą klawisza enter . Wciśnięcie klawisza enter nie przypisuje do zmiennej wartości zwracanej przez funkcję input(), program kończy działanie, a okno konsoli zostaje zamknięte. Wciśnięcie klawisza f5 w oknie edytora IDLE wykonuje ukończony program.
Powyższy kod działa, ale samo działanie to zbyt mało - programy w języku Python powinny działać w odpowiednim stylu.
Korzystanie z przewodnika po stylach tworzonego przez społeczność Pythona
Zgodnie z jedną z wytycznych zawartych w PEP 20, "Zen of Python" (https://www.python.org/dev/peps/pep-0020/), "powinien istnieć pewien - a najlepiej tylko jeden - oczywisty sposób wykonania czegoś". W duchu dostarczania jednego oczywistego "właściwego sposobu" wykonywania rzeczy i budowania konsensusu wokół tych praktyk, społeczność języka Python wydaje propozycje zmian lub rozszerzeń dla języka Python (Python Enhancement Proposal, PEP), które są konwencjami kodowania dla kodu Pythona tworzącego standardową bibliotekę w głównej dystrybucji Pythona. Najważniejszą z tych konwencji jest PEP 8, będąca przewodnikiem po stylach programowania w Pythonie. PEP 8 stale ewoluuje, w miarę jak określane są nowe konwencje, a stare wycofywane są z powodu zmian w języku.
PEP 8 (https://www.python.org/dev/peps/pep-0008/) wyznacza standardy w zakresie konwencji nazewnictwa, używania pustych wierszy, tabulatorów i spacji, maksymalnej długości wiersza, komentarzy itd. Propozycje te mają na celu podnieść czytelność kodu i sprawić, że będzie on spójny w ramach szerokiego spektrum programów pisanych w Pythonie. Osoby uczące się programowania powinny starać się przyswoić i stosować przyjęte konwencje, zanim złe nawyki zakorzenią się na dobre. Kod w tej książce będzie spełniać wytyczne PEP 8, przy czym niektóre z konwencji zostały zmienione (przykładowo poprzez użycie mniejszej ilości komentarzy, mniejszej liczby pustych wierszy oraz krótszych ciągów docstring) z szacunku do branży wydawniczej.
Ustandaryzowane nazwy i procedury są ważne zwłaszcza w przypadku pracy w zespołach wielofunkcyjnych. Wiele informacji może zostać utraconych w procesie tłumaczenia pomiędzy naukowcami i inżynierami, jak miało to miejsce w 1999 roku, kiedy to inżynierowie stracili sondę Mars Climate Orbiter, ponieważ różne zespoły używały różnych jednostek pomiarowych. Przez niemal dwie dekady budowałem komputerowe modele Ziemi, które były wykorzystywane w zastosowaniach inżynierskich. Inżynierowie używali skryptów do wczytywania tych modeli do ich własnego oprogramowania. W celu zwiększenia wydajności i zapewnienia pomocy osobom mniej doświadczonym udostępniali oni te skrypty między projektami. Ponieważ te "pliki poleceń" były dostosowywane do każdego projektu, inżynierowie z oczywistych powodów denerwowali się, gdy nazwy atrybutów zmieniały się podczas aktualizacji modelu. W zasadzie jednym z ich wewnętrznych wytycznych było "Błagaj, przekup lub zastrasz swojego twórcę modelu, aby używał spójnych nazw właściwości!".
Sprawdzanie kodu za pomocą narzędzia Pylint
Powinniśmy zaznajomić się z wytycznymi PEP 8, ale wciąż będziemy popełniać błędy, a porównywanie naszego kodu z przewodnikiem będzie nas mocno opóźniać. Na szczęście programy takie jak Pylint, pycodestyle i Flake8 mogą pomóc nam w łatwy sposób podążać za rekomendacjami PEP 8 dotyczącymi stylów. Na potrzeby tego projektu skorzystamy z narzędzia Pylint.
Instalowanie narzędzia Pylint
Pylint jest narzędziem do sprawdzania kodu źródłowego, błędów i jakości kodu w języku Python. Aby pobrać jego darmową kopię, należy przejść na stronę https://www.pylint.org/#install i znaleźć przycisk instalacji dla swojej platformy. Przycisk ten ukaże polecenia do instalacji narzędzia Pylint. Na przykład w systemie Windows przechodzimy do folderu zawierającego kopię języka Python (np. C:\Python35), otwieramy menu kontekstowe za pomocą kombinacji SHIFT + prawy przycisk myszy, a następnie wybieramy opcję open command window here (Otwórz tutaj okno polecenia) lub open PowerShell window here (Otwórz tutaj okno programu PowerShell), w zależności od tego, z jakiej wersji systemu Windows korzystamy. W otwartym oknie wpisujemy pip install pylint.
Uruchamianie narzędzia Pylint
W systemie Windows narzędzie Pylint uruchamianie jest z poziomu okna wiersza polecenia, a w przypadku nowszych systemów - z okna programu PowerShell (oba te okna można otworzyć za pomocą kombinacji shift + prawy przycisk myszy, użytej w folderze zawierającym moduł Pythona, który chcemy sprawdzić). Aby uruchomić ten program, należy wpisać polecenie pylint nazwapliku (patrz rys. 1.1). Rozszerzenie .py jest opcjonalne, zaś ścieżka do katalogu może się różnić od tej widocznej na rysunku. W przypadku systemu macOS lub innego systemu opartego na systemie Unix należy posłużyć się emulatorem terminala.
Rysunek 1.1. Okno wiersza polecenia systemu Windows z poleceniem uruchamiającym narzędzie Pylint
Okno wiersza polecenia wyświetli rezultaty działania narzędzia Pylint. Oto przykład przydatnego wyniku:
C:\Python35\Python 3 Stuff\Psych>pylint pseudonyms.py
No config file found, using default configuration
************* Module pseudonyms
C: 45, 0: No space allowed around keyword argument assignment
print(firstName, lastName, file = sys.stderr)
^ (bad-whitespace)
C: 1, 0: Missing module docstring (missing-docstring)
C: 2, 0: Multiple imports on one line (sys, random) (multiple-imports)
C: 7, 0: Invalid constant name "first" (invalid-name)
C: 23, 0: Invalid constant name "last" (invalid-name)
C: 40, 4: Invalid constant name "firstName" (invalid-name)
C: 42, 4: Invalid constant name "lastName" (invalid-name)
C: 48, 4: Invalid constant name "try_again" (invalid-name)
Wielka litera na początku każdego wiersza jest kodem komunikatu. Przykładowo kod C: 15, 0 odnosi się do naruszenia standardu kodowania w wierszu 15, kolumnie 0. Poszczególne kody komunikatów narzędzia Pylint można odczytać za pomocą poniższego klucza:
R Refaktoryzuj z powodu naruszenia metryki "dobrej praktyki"
C Konwencja dotycząca naruszenia standardu kodowania
W Ostrzeżenie przed problemami stylistycznymi lub pomniejszymi problemami programistycznymi
E Błąd dotyczący istotnych problemów programistycznych (tj. najprawdopodobniej jakiś błąd w kodzie)
F Błąd krytyczny, który uniemożliwia dalsze przetwarzanie
Pylint zakończy swój raport, przyznając naszemu programowi ocenę zgodności z PEP 8. W naszym przykładzie kod otrzymał ocenę 4 na 10:
Global evaluation
-----------------
Your code has been rated at 4.00/10 (previous run: 4.00/10, +0.00)
Obsługiwanie fałszywych błędów dotyczących nazw stałych
Jak można zauważyć, Pylint niepoprawnie zakłada, że wszystkie nazwy zmiennych w przestrzeni globalnej odnoszą się do stałych, a tym samym powinny być pisane wielkimi literami. Mankament ten możemy rozwiązać na kilka sposobów. Pierwszym z nich jest zagnieżdżenie naszego kodu w funkcji main(), jak to pokazano na listingu 1.2, dzięki czemu nie będzie się on znajdował w przestrzeni globalnej.
def main():
jakiś wcięty kod
jakiś wcięty kod
jakiś wcięty kod
if __name__ == "__main__":
main()
Listing 1.2. Definicja i wywołanie funkcji main()
Zmienna __name__ jest specjalną wbudowaną zmienną, za pomocą której możemy sprawdzić, czy program uruchamiany jest w trybie samodzielnym, czy jako moduł zaimportowany. Pamiętajmy, że moduł jest po prostu programem w Pythonie, używanym wewnątrz innego programu. Jeśli uruchomimy program bezpośrednio, wówczas zmienna __name__ ustawiona zostanie na wartość __main__. Na listingu 1.2 użyto zmiennej __name__, aby zagwarantować, że po zaimportowaniu programu funkcja main() nie zostanie uruchomiona, dopóki sami jej jawnie nie wywołamy . Gdy jednak program zostanie uruchomiony bezpośrednio, warunek w instrukcji if zostanie spełniony i funkcja main() zostanie wywołana automatycznie . Nie zawsze musimy korzystać z tej konwencji. Przykładowo, jeśli nasz kod definiuje po prostu jakąś funkcję, możemy wczytać ją jako moduł i wywołać bez potrzeby używania zmiennej __name__.
Wszystko z wyjątkiem instrukcji import umieścimy w funkcji main(), w pliku pseudonyms.py, a wywołanie funkcji main() umieścimy w instrukcji if, jak na listingu 1.2. Możesz wprowadzić te zmiany samodzielnie lub pobrać gotowy program pseudonyms_main.py z witryny tej książki. Uruchamiamy ponownie narzędzie Pylint. W oknie polecenia powinniśmy otrzymać następujące wyniki:
C:\Python35\Python 3 Stuff\Psych>pylint pseudonyms_main
No config file found, using default configuration
************* Module pseudonyms_main
C: 47, 0: No space allowed around keyword argument assignment
print(firstName, lastName, file = sys.stderr)
^ (bad-whitespace)
C: 1, 0: Missing module docstring (missing-docstring)
C: 2, 0: Multiple imports on one line (sys, random) (multiple-imports)
C: 4, 0: Missing function docstring (missing-docstring)
C: 42, 8: Invalid variable name "firstName" (invalid-name)
C: 44, 8: Invalid variable name "lastName" (invalid-name)
Teraz te denerwujące komentarze odnośnie nieprawidłowych nazw stałych zniknęły, ale to jeszcze nie koniec. Choć bardzo lubię nazwy w notacji camelCase, jak na przykład firstName, jednak konwencje Pythona nie pozwalają na jej stosowanie.
Konfigurowanie narzędzia Pylint
W przypadku oceniania prostych skryptów wolę używać domyślnych ustawień narzędzia Pylint i ignorować fałszywe błędy dotyczące nazw stałych. Lubię również korzystać z opcji -rn (skrót dla -reports=n), aby wyłączać wyświetlanie obszernych ilości statystyk, które są zwracane przez Pylint:
C:\Python35\Python 3 Stuff\Psych>pylint -rn pseudonyms_main.py
Zwróćmy uwagę, że użycie opcji -rn wyłączy opcję oceny kodu.
Kolejnym problemem z narzędziem Pylint jest to, że jego maksymalna długość wiersza wynosi domyślnie 100 znaków, ale PEP 8 zaleca 79 znaków. Aby dostosować się do wytycznych PEP 8, można uruchomić Pylint z następującą opcją:
C:\Python35\Python 3 Stuff\Psych>pylint --max-line-length=79 pseudonyms_main
Teraz zobaczymy, że wstawienie wcięć dla imion i nazwisk w funkcji main() spowodowało, iż niektóre wiersze przekroczyły zalecaną długość:
C: 12, 0: Line too long (80/79) (line-too-long)
C: 14, 0: Line too long (83/79) (line-too-long)
--wycinek--
Raczej nie będziemy chcieli konfigurować narzędzia Pylint przy każdym uruchomieniu i na szczęście nie musimy tego robić. Zamiast tego możemy za pomocą polecenia --generate-rcfile utworzyć nasz własny niestandardowy plik konfiguracyjny. Przykładowo, aby zawiesić raportowanie i ustawić maksymalną długość wiersza na 79 znaków, należy w wierszu polecenia wprowadzić poniższe polecenie:
twoja ścieżka>pylint -rn --max-line-length=79 --generate-rcfile > nazwa.pylintrc
Wszelkie opcje, które chcemy wprowadzić, umieszczamy przed instrukcją --generate-rcfile > nazwa.pylintrc, wpisując naszą własną nazwę przed rozszerzeniem .pylintrc. Plik konfiguracji możemy utworzyć samodzielnie, jak to pokazaliśmy, albo też w czasie oceniania programu w Pythonie. Plik .pylintrc jest automatycznie zapisywany w naszym bieżącym katalogu roboczym, przy czym istnieje opcja pozwalająca na dodanie ścieżki do katalogu (więcej informacji na ten temat można znaleźć na stronach https://pylint.org oraz https://pylint.readthedocs.io/en/latest/user_guide/run.html).
Aby wykorzystać ponownie nasz niestandardowy plik konfiguracji, używamy opcji --rcfile, po której podajemy nazwę tego pliku i nazwę programu, który oceniamy. Przykładowo, aby użyć pliku myconfig.pylintrc dla programu pseudonyms_main.py, należy użyć polecenia:
C:\Python35\Python 3 Stuff\Psych>pylint --rcfile myconfig.pylintrc pseudonyms_main
Opisywanie kodu za pomocą ciągów docstring
Pylint wskazuje, że w programie pseudonyms_main.py brakuje ciągu dokumentacyjnego docstring. Zgodnie z przewodnikiem po stylach PEP 257 (https://www.python.org/dev/peps/pep-0257/), ciąg dokumentacyjny docstring jest literałem znakowym, występującym jako pierwsza instrukcja w definicji modułu, funkcji, klasy lub metody. Ciąg docstring jest po prostu krótkim opisem tego, co robi nasz kod, i może zawierać szczegóły na temat różnych aspektów kodu, takich jak na przykład wymagane przez niego dane. Poniżej, w potrójnych znakach cudzysłowu, znajduje się przykład pojedynczego ciągu docstring dla funkcji:
def circ(r):
"""Return the circumference of a circle with radius of r."""
c = 2 * r * math.pi
return c
Powyższy ciąg docstring określa, co dana funkcja robi, ale ciągi docstring mogą być dłuższe i zawierać więcej informacji. Na przykład poniżej znajduje się wielowierszowy ciąg docstring dla tej samej funkcji, który wyświetla informacje dotyczące danych i wartości wyjściowych tej funkcji:
def circ(r):
"""Return the circumference of a circle with radius of r.
Arguments:
r - radius of circle
Returns:
float: circumference of circle
"""
c = 2 * r * math.pi
return c
Niestety ciągi docstring zależą od konkretnej osoby, projektu i firmy, tak więc istnieje dla nich wiele zaleceń, które stoją ze sobą w sprzeczności. Google ma swój własny format oraz świetny przewodnik. Niektórzy członkowie społeczności naukowej stosują standard docstring o nazwie NumPy. Również reStructuredText jest popularnym formatem, używanym głównie w połączeniu z narzędziem Sphinx, które wykorzystuje ciągi docstring do generowania dokumentacji dla projektów w Pythonie w formatach HTML i PDF. Ktoś, kto kiedykolwiek czytał dokumentację (https://readthedocs.org/) dla jakiegoś modułu Python, widział narzędzie Sphinx w akcji. Łącza prowadzące do wytycznych dla niektórych z tych różnych stylów znajdują się w części "Materiały dodatkowe", na stronie 15.
Aby sprawdzić, w jakim stopniu nasze ciągi docstring spełniają wymagania konwencji PEP 257, możemy posłużyć się darmowym narzędziem o nazwie pydocstyle. Aby zainstalować je w systemie Windows lub dowolnym innym systemie operacyjnym, należy otworzyć okno wiersza polecenia i wpisać pip install pydocstyle (jeśli Python zainstalowany jest zarówno w wersji 2, jak i wersji 3, to należy użyć narzędzia pip3).
Aby uruchomić narzędzie pydocstyle, otwieramy wiersz polecenia w folderze zawierającym kod, który chcemy sprawdzić. Jeśli nie podamy nazwy pliku, pydocstyle zostanie uruchomiony dla wszystkich programów w Pythonie dostępnych w tym folderze i otrzymamy taki wynik:
C:\Python35\Python 3 Stuff\Psych>pydocstyle
.\OLD_pseudonyms_main.py:1 at module level:
D100: Missing docstring in public module
.\OLD_pseudonyms_main.py:4 in public function 'main':
D103: Missing docstring in public function
.\ pseudonyms.py:1 at module level:
D100: Missing docstring in public module
.\ pseudonyms_main_broken.py:1 at module level:
D200: One-line docstring should fit on one line with quotes (found 2)
.\ pseudonyms_main_broken.py:6 in public function 'main':
D205: 1 blank line required between summary line and description
(found 0)
Jeśli podamy plik, w którym nie ma żadnych problemów z ciągami docstring, pydocstyle nie zwróci nam niczego:
C:\Python35\Python 3 Stuff\Psych>pydocstyle pseudonyms_main_fixed.py
C:\Python35\Python 3 Stuff\Psych>
We wszystkich projektach w tej książce używać będziemy stosunkowo prostych ciągów docstring, aby zredukować w ten sposób wizualny szum w opatrzonym opisem kodzie. Jeśli chcesz, możesz je bez przeszkód rozbudowywać, aby je w ten sposób przećwiczyć. Uzyskane rezultaty zawsze można sprawdzić za pomocą narzędzia pydocstyle.
Sprawdzanie stylu naszego kodu
Gdy dorastałem, mój wujek dojeżdżał z naszego miasteczka do większego miasta, aby miejscowy fryzjer "wystylizował" jego włosy. Nigdy nie rozumiałem, czym różni się to od zwykłego strzyżenia, ale wiem natomiast, w jaki sposób "wystylizować" kod naszego generatora śmiesznych pseudonimów, tak aby spełniał on wymagania PEP 8 i PEP 257.
Tworzymy kopię pliku pseudonyms_main.py o nazwie pseudonyms_main_fixed.py i natychmiast oceniamy ją za pomocą narzędzia Pylint przy użyciu tego polecenia:
Twoja ścieżka>pylint --max-line-length=79 pseudonyms_main_fixed
Nie ukrywamy raportu za pomocą opcji -rn. Na dole okna polecenia powinniśmy zobaczyć poniższy wynik:
Global evaluation
----------------
Your code has been rated at 3.33/1
Teraz poprawiamy kod w oparciu o wynik Pylint. W poniższym przykładzie wytłuściłem wszystkie poprawki. Wprowadziłem zmiany do krotek z nazwami, aby rozwiązać w ten sposób problemy z długością wierszy. Poprawiony kod jest również dostępny do pobrania w formie pliku pseudonyms_main_fixed.py ze strony https://www.nostarch.com/impracticalpython/.
pseudonyms_main_fixed.py
"""Generate funny names by randomly combining names from 2 separate lists."""
import sys
import random
def main():
"""Choose names at random from 2 tuples of names and print to screen."""
print("Welcome to the Psych 'Sidekick Name Picker.'\n")
print("A name just like Sean would pick for Gus:\n\n")
first = ('Baby Oil', 'Bad News', 'Big Burps', "Bill 'Beenie-Weenie'",
"Bob 'Stinkbug'", 'Bowel Noises', 'Boxelder', "Bud 'Lite'",
'Butterbean', 'Buttermilk', 'Buttocks', 'Chad', 'Chesterfield',
'Chewy', 'Chigger', 'Cinnabuns', 'Cleet', 'Cornbread',
'Crab Meat', 'Crapps', 'Dark Skies', 'Dennis Clawhammer',
'Dicman', 'Elphonso', 'Fancypants', 'Figgs', 'Foncy', 'Gootsy',
'Greasy Jim', 'Huckleberry', 'Huggy', 'Ignatious', 'Jimbo',
"Joe 'Pottin Soil'", 'Johnny', 'Lemongrass', 'Lil Debil',
'Longbranch', '"Lunch Money"', 'Mergatroid', '"Mr Peabody"',
'Oil-Can', 'Oinks', 'Old Scratch', 'Ovaltine', 'Pennywhistle',
'Pitchfork Ben', 'Potato Bug', 'Pushmeet', 'Rock Candy',
'Schlomo', 'Scratchensniff', 'Scut', "Sid 'The Squirts'",
'Skidmark', 'Slaps', 'Snakes', 'Snoobs', 'Snorki', 'Soupcan Sam',
'Spitzitout', 'Squids', 'Stinky', 'Storyboard', 'Sweet Tea',
'TeeTee', 'Wheezy Joe', "Winston 'Jazz Hands'", 'Worms')
last = ('Appleyard', 'Bigmeat', 'Bloominshine', 'Boogerbottom',
'Breedslovetrout', 'Butterbaugh', 'Clovenhoof', 'Clutterbuck',
'Cocktoasten', 'Endicott', 'Fewhairs', 'Gooberdapple',
'Goodensmith', 'Goodpasture', 'Guster', 'Henderson', 'Hooperbag',
'Hoosenater', 'Hootkins', 'Jefferson', 'Jenkins',
'Jingley-Schmidt', 'Johnson', 'Kingfish', 'Listenbee', "M'Bembo",
'McFadden', 'Moonshine', 'Nettles', 'Noseworthy', 'Olivetti',
'Outerbridge', 'Overpeck', 'Overturf', 'Oxhandler', 'Pealike',
'Pennywhistle', 'Peterson', 'Pieplow', 'Pinkerton', 'Porkins',
'Putney', 'Quakenbush', 'Rainwater', 'Rosenthal', 'Rubbins',
'Sackrider', 'Snuggleshine', 'Splern', 'Stevens', 'Stroganoff',
'Sugar-Gold', 'Swackhamer', 'Tippins', 'Turnipseed',
'Vinaigrette', 'Walkingstick', 'Wallbanger', 'Weewax', 'Weiners',
'Whipkey', 'Wigglesworth', 'Wimplesnatch', 'Winterkorn',
'Woolysocks')
while True:
first_name = random.choice(first)
last_name = random.choice(last)
print("\n\n")
# Oszukaj IDLE za pomocą ustawienia "krytycznego błędu", aby wypisać
# imię i nazwisko na czerwono.
print("{} {}".format(first_name, last_name), file=sys.stderr)
print("\n\n")
try_again = input("\n\nTry again? (Press Enter else n to quit)\n ")
if try_again.lower() == "n":
break
input("\nPress Enter to exit.")
if __name__ == "__main__":
main()
Pylint ocenił ten poprawiony kod na 10 punktów:
Global evaluation
----------------
Your code has been rated at 10.00/10 (previous run: 3.33/10, +6.67)
Jak zobaczyliśmy w poprzednim podrozdziale, uruchomienie narzędzia pydocstyle na pliku pseudonyms_main_fixed.py nie zgłasza żadnych błędów, ale nie myślmy, że oznacza to, iż wszystko jest poprawne lub nawet zadowalające. Przykładowo następujący ciąg znaków również przechodzi ten test: """ksjkdls lskjds kjs jdi wllk sijkljs dsdw noiu sss.""".
Trudno jest pisać krótkie, zwięzłe i naprawdę przydatne ciągi docstring i komentarze. PEP 257 pomoże nam z ciągami docstring, ale komentarze mają bardziej luźny styl i "otwarty zakres". Zbyt duża ilość komentarzy tworzy wizualny szum i może zrażać użytkownika, a wiele z nich nie jest nawet potrzebnych, ponieważ dobrze napisany kod w dużej mierze dokumentuje się sam. Dobrym powodem do wstawienia komentarza może być chociażby chęć objaśnienia zamiaru i próba uniknięcia popełnienia błędu przez użytkownika, jak w przypadku, gdy wymagane są konkretne jednostki pomiarowe lub formaty danych. Aby znaleźć właściwą równowagę w komentowaniu kodu, zwracajmy uwagę na dobre przykłady, gdy będziemy je napotykać. Ponadto warto zadać sobie pytanie, co my sami chcielibyśmy zobaczyć, gdybyśmy otrzymali nasz własny kod po pięcioletniej przerwie!
Narzędzia Pylint i pydocstyle są w łatwe w instalacji, łatwe w uruchamianiu i pomogą nam zapoznać się ze standardami kodowania przyjętymi w społeczności języka Python i do nich dostosować. Gdy szukamy pomocy, przepuszczenie naszego kodu przez narzędzie Pylint przed opublikowaniem go na forum internetowym również jest uznawane za dobrą praktykę i może spowodować, że uzyskamy w ten sposób "bardziej uprzejme i łagodniejsze" odpowiedzi!
Podsumowanie
Teraz powinniśmy już wiedzieć, w jaki sposób pisać kod i dokumentację, które spełniają oczekiwania społeczności języka Python. Jednak, co bardziej istotne, wygenerowaliśmy szereg naprawdę zabawnych pseudonimów dla pomocnika, gangstera, informatora, czy kogokolwiek innego. Oto kilka z moich ulubionych:
Pitchfork Ben Pennywhistle 'Bad News' Bloominshine
Chewy Stroganoff 'Sweet Tea' Tippins
Spitzitout Winterkorn Wheezy Joe Jenkins
'Big Burps' Rosenthal Soupcan Sam Putney
Bill 'Beenie-Weenie' Clutterbuck Greasy Jim Wigglesworth
Dark Skies Jingley-Schmidt Chesterfield Walkingstick
Potato Bug Quakenbush Jimbo Woolysocks
Worms Endicott Fancypants Pinkerton
Cleet Weiners Dicman Overpeck
Ignatious Outerbridge Buttocks Rubbins
Materiały dodatkowe
Interaktywna wersja tych zasobów znajduje się na stronie https://www.nostarch.com/impracticalpython/.
Pseudokod
Opisy pewnych dosyć formalnych standardów związanych z pseudokodem dostępne są na stronach http://users.csc.calpoly.edu/~jdalbey/SWE/pdl_std.html oraz http://www.slideshare.net/sabiksabz/pseudo-code-basics/.
Przewodniki po stylach
Poniżej znajduje się lista przewodników po stylach, po które możemy sięgać podczas tworzenia programów w Pythonie.
- Przewodnik PEP 8 można znaleźć pod adresem
https://www.python.org/dev/peps/pep-0008/. - Wytyczne PEP 257 dostępne są na stronie
https://www.python.org/dev/peps/pep-0257/. - Google ma swój własny przewodnik po stylach i formatach:
https://google.github.io/styleguide/pyguide.html. - Przykłady stylu Google można znaleźć na stronie
https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html. - Standardy dla ciągów docstring biblioteki NumPy znajdują się pod adresem
https://numpydoc.readthedocs.io/en/latest/. - Przykłady ciągów docstring w formacie NumPy można znaleźć pod adresem
https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html. - Więcej informacji na temat formatu reStructuredText można znaleźć na stronach
https://docs.python.org/devguide/documenting.html,
https://docs.python.org/3.1/documenting/rest.html oraz
https://wiki.python.org/moin/reStructuredText/. - Podręcznik "The Hitchhiker's Guide to Python" (
http://docs.python-guide.org/en/latest/writing/style/) zawiera podrozdział poświęcony stylom kodowania i narzędziu
autopep8, które automatycznie formatuje kod zgodnie z wytycznymi PEP 8 (do pewnego stopnia). - Książka "Efektywny Python. 59 sposobów na lepszy kod"4 autorstwa Bretta Slatkina zawiera przydatny podrozdział poświęcony dokumentowaniu programów.
Moduły zewnętrzne
Poniżej znajdują się pewne zasoby wyjaśniające sposób korzystania z zewnętrznych modułów.
- Szczegóły na temat modułu Pylint znajdują się na stronie https://docs.pylint.org/en/1.8/tutorial.html. - Szczegóły na temat narzędzia pydocstyle można znaleźć pod adresem http://www.pydocstyle.org/en/latest/.
Ćwiczenia
Spróbuj wykonać te projekty, aby przećwiczyć pracę z ciągami znaków. Moje własne rozwiązania dla tych projektów dostępne są w dodatku na końcu książki.
Świńska łacina
Aby utworzyć tzw. świńską łacinę, należy wybrać jakieś angielskie słowo rozpoczynające się od spółgłoski, przenieść tę spółgłoskę na jego koniec, a następnie dodać do niego końcówkę "ay". Jeśli słowo rozpoczyna się od samogłoski, to na końcu słowa dodajemy końcówkę "way". Jedną z najbardziej znanych fraz w świńskiej łacinie jest "ixnay on the ottenray", wypowiedziane przez Martiego Feldmana w mistrzowskiej komedii Mela Brooksa pt. "Młody Frankenstein".
Napisz program, który przyjmuje na wejściu słowo, a następnie przy wykorzystaniu indeksowania i wycinania zwraca odpowiednik tego słowa w świńskiej łacinie. Uruchom Pylint i pydocstyle na swoim kodzie i popraw wszelkie błędy w stylu. Rozwiązanie dla tego projektu znajduje się w dodatku na końcu tej książki. Jest ono również dostępne w pliku pig_latin_practice.py na stronie https://www.nostarch.com/impracticalpython/.
Wykres słupkowy dla języka angielskiego
Sześć najczęściej używanych liter w języku angielskim można zapamiętać przy użyciu skrótu mnemonicznego "etaoin". Napisz skrypt w języku Python, który pobiera na wejściu zdanie (ciąg znaków) i zwraca prosty wykres słupkowy, widoczny na rysunku 1.2. Wskazówka: wykorzystałem tutaj strukturę danych słownika oraz dwa moduły, których jeszcze nie omawialiśmy: pprint oraz collections/defaultdict.
Rysunek 1.2. Wykres słupkowy wygenerowany przez program ETAOIN_practice.py zaprezentowany w dodatku tej książki
Wyzwania
Rozwiązania dla poniższych projektów nie są podane. Trzeba rozwiązać te problemy samodzielnie!
Wykres słupkowy dla języków romańskich
Przy użyciu translatora online zmień swój tekst na inny system zapisu oparty na łacinie (np. język hiszpański lub francuski), uruchom ponownie kod z projektu "Wykres słupkowy dla języka angielskiego" i porównaj uzyskane wyniki. Przykładowo hiszpańska wersja tekstu z rysunku 1.2 generuje wyniki pokazane na rysunku 1.3.
Rysunek 1.3. Wynik działania programu ETAOIN_challenge.py po wprowadzeniu na wejściu hiszpańskiego tłumaczenia tekstu z rysunku 1.2
W zdaniu w języku hiszpańskim jest dwa razy więcej liter L i trzy razy więcej liter U. Aby móc bezpośrednio porównać ze sobą wykresy słupkowe dla różnych danych, zmień kod w taki sposób, aby każda litera alfabetu miała swój klucz i była wyświetlana nawet wtedy, gdy nie istnieje dla niego żadna wartość.
Drugie imię
Przepisz kod generatora śmiesznych pseudonimów w taki sposób, aby uwzględniał drugie imiona. Najpierw utwórz nową krotkę middle_name, a następnie rozdziel istniejące pary "pierwsze imię-drugie imię" (takie jak "Joe 'Pottin Soil'" lub "Sid 'The Squirts'") i dodaj je do tej krotki. Do krotki middle_name powinny zostać również przeniesione oczywiste ksywki (np. "Oil Can"). Na koniec dodaj jakieś nowe drugie imiona (takie jak "The Big News", "Grunts" lub "Tinkie Winkie"). Użyj modułu random w taki sposób, aby drugie imię wybierane było tylko raz na dwie lub trzy próby.
Coś całkowicie innego
Utwórz swoją własną listę śmiesznych pseudonimów i dodaj ją do generatora. Wskazówka: tego rodzaju imiona można łatwo znaleźć w napisach końcowych filmów.