Cum te poate ajuta Zen-ul lui Python să scrii un cod mai bun

Doriți să vă îmbunătățiți la scrierea codului Python? Iată cum Zen of Python vă poate ajuta să faceți primii pași către el.

Python este foarte simplu de învățat. Dar scrierea de cod idiomatic și Pythonic care este ușor de întreținut poate fi o provocare, în special pentru programatorii începători. PEP-20 a introdus „Zenul lui Python“, o poezie de Tim Peters, care subliniază importanța scrierii codului Pythonic care să respecte cele mai bune practici.

Pentru a citi Zen of Python, puteți porni un Python REPL și rulați:

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

După cum s-a văzut, majoritatea aforismelor din Zen-ul lui Python se explică de la sine. Unele aforisme ar trebui să fie cuplate cu următoarea la interpretare, în timp ce altele contrazic un aforism anterior. Cu toate acestea, Zen-ul lui Python este o lectură distractivă, captivantă și practică!

Interpretarea Zen-ului lui Python

Zen-ul Python a fost propus să aibă 20 de principii directoare pentru programarea în Python. Cu toate acestea, există doar 19 aforisme până acum. Să trecem peste ele.

Frumos este mai bun decât urât.

Acest aforism subliniază importanța scrierii unui cod elegant și pitonic.

Următorul fragment de cod are un miros de cod:

def square(num):
    squares = []
    for i in range(num):
        squares.append(i*i)
    return squares

Functia:

  • Inițializează o listă goală
  • Are o buclă în interiorul funcției care adaugă elemente la sfârșitul listei și
  • În sfârșit, returnează o listă
  9 instrumente de simulare a atacurilor cibernetice pentru îmbunătățirea securității

Deși acest lucru este corect din punct de vedere funcțional – nu este Pythonic – și este greu de întreținut.

Îl poți scrie mult mai elegant folosind generatoare. Iată echivalentul funcției de generator al funcției de mai sus:

def square(num):
    for i in range(num):
        yield i*i

Sau și mai bine, puteți avea următoarea expresie de înțelegere a generatorului:

num = ...
squares = (i*i for i in range(num))

Explicit este mai bine decât implicit.

Când scrieți cod, nu lăsați alți dezvoltatori și utilizatori să ghicească comportamentul implicit sau implicit al codului. Fii explicit. Luați exemplul importurilor de wildcard:

from some_module import * # wildcard import
from some_other_module import *

result = some_function() # where did this come from?

Evitați, pe cât posibil, să utilizați importurile de wildcard. Pentru că nu este explicit și ineficient. Fiți specific când importați funcții și clase din alte module:

from some_module import this_function # explicit import

result = this_function() # we now know.

Simplu este mai bine decât complex.

Acest aforism afirmă că ar trebui să păstrăm codul simplu și să evităm complexitatea inutilă. De exemplu: poate doriți să inversați un șir și să implementați următoarea soluție recursivă:

def reverse_string(my_string):
  if my_string == "":
    return my_string
  else:
    return reverse_string(my_string[1:]) + my_string[:1]

Deși funcționează, aceasta este probabil o soluție supraproiectată la această problemă, având în vedere că există modalități mai simple și mai Pythonic de a face acest lucru.

Iată abordarea prin tăierea șirurilor:

>>> rev_string = my_string[::-1]
>>> rev_string
'nohtyP'

Și iată abordarea folosind metode și funcții încorporate:

>>> rev_string = ''.join(reversed(my_string))
>>> rev_string
'nohtyP'

Complex este mai bine decât complicat.

Deci, ce transmite următorul aforism din Zen lui Python?

Inversarea șirurilor în Python este o operație super simplă. În practică, totuși, este posibil să avem nevoie de o logică mai complexă. Iată un exemplu destul de simplu:

Să presupunem că trebuie să vă conectați la o bază de date:

  • Mai întâi ar trebui să analizați un fișier de configurare toml – pentru a prelua informațiile de configurare ale bazei de date.
  • Conectorul bazei de date trebuie instalat.
  • Puteți defini apoi o funcție pentru a vă conecta la baza de date, a anticipa erorile de conectare, a implementa gestionarea erorilor și multe altele.
  • În cele din urmă, după conectarea la baza de date, o puteți interoga.

Deși acest lucru este încă destul de simplu, are nevoie de o logică mai complexă în comparație cu inversarea șirurilor. Dar asta nu înseamnă că trebuie să fie complicat. Puteți utiliza în continuare funcționalitatea codului modulelor încorporate în mod eficient și puteți organiza codul astfel încât alți dezvoltatori să poată citi, înțelege și contribui la el.

Flat este mai bine decât imbricat.

O structură plată este ușor de analizat și de înțeles decât o structură imbricată. Pe măsură ce lucrați la un proiect, ați putea fi tentat să izolați funcționalitatea prin crearea de module separate. Cu toate acestea, prea multă granularitate poate fi excesivă.

Acestea fiind spuse, s-ar putea să fie nevoie adesea să treceți dincolo de structura plată. Dar chiar dacă aveți nevoie de cuibărit, păstrați-l la minimum.

  Cum să creați o liniuță suspendată în Word și Google Docs

Iată un exemplu:

from db_info.config.actions.parse.parse_config import parse_toml # too difficult to parse!
...

from db_config.parse_config import parse_toml # much better!
...

Rară este mai bine decât dens.

Dacă abia sunteți la început în călătoria dvs. de dezvoltator, ați putea fi tentat să folosiți în exces unele dintre caracteristicile limbajului. Listele de înțelegere, de exemplu, sunt Pythonic, dar numai atunci când le folosiți acolo unde sunt necesare.

Uită-te la următoarea înțelegere:

prices_dict = {'melons':40,'apples':70,'berries':55}
items = [(fruit,price) for fruit in prices_dict.keys() if fruit.startswith('m') for price in prices_dict.values() if price < 50]
print(items)
# Output: [('melons', 40)]

Înțelegerea listei este prea densă și greu de analizat. În acest caz, utilizarea unui echivalent for buclă cu condiționale va fi mai ușor de citit. Înseamnă că înțelegerea este greu de înțeles. 🙂

Lizibilitatea contează.

Ar trebui să scrieți întotdeauna cod care poate fi citit. Iată câteva modalități simple de a îmbunătăți lizibilitatea codului:

  • Utilizarea numelor de variabile descriptive
  • Adăugarea de documente pentru funcții și clase
  • Cod de comentariu acolo unde este necesar
  • Adăugarea de indicii de tip pentru argumente și tipuri de funcții returnate

Cazurile speciale nu sunt suficient de speciale pentru a încălca regulile.

Ar trebui, pe cât posibil, să respectați regulile limbii și cele mai bune practici recomandate.

Dar este întotdeauna posibil acest lucru? Nu, și de aceea avem următorul aforism.

Deși caracterul practic bate puritatea.

Aceasta este o continuare a aforismului anterior. Deși este recomandat să urmați regulile limbii, în anumite cazuri, este perfect să nu respectați unele dintre principii.

Erorile nu ar trebui să treacă niciodată în tăcere.

În Python, erorile de rulare sunt destul de frecvente. Ca o bună practică, ar trebui să gestionați întotdeauna erorile și să nu le reduceți la tăcere ca o remediere rapidă.

Puteți anticipa și implementa gestionarea adecvată a erorilor, pentru diferitele tipuri de erori:

try:  
    # doing this
except ErrorType1:
    # do something
except ErrorType2:
    # do something else
...

Ar trebui să evitați excepțiile simple și generice. Versiunile mai noi de Python (de la Python 3.11) acceptă înlănțuirea excepțiilor și grupurile de excepții pentru a efectua o gestionare mai sofisticată a excepțiilor.

Cu excepția cazului în care este redus la tăcere în mod explicit.

Aceasta urmează aforismului anterior. Dacă proiectarea necesită sau permite ca eroarea să fie redusă la tăcere, atunci aceasta ar trebui făcută în mod explicit.

De exemplu: atunci când vă conectați la baza de date, puteți întâlni OperationalError din cauza informațiilor de configurare nevalide. Încercați să vă conectați folosind configurația personalizată. În cazul în care există o OperationalError, utilizați configurația implicită și încercați să vă conectați la baza de date.

try:
   # connecting using custom config
except OperationalError:
   # connect using default config

În fața ambiguității, refuzați tentația de a ghici.

Acest aforism din Zen lui Python se explică de la sine. Când aveți îndoieli, nu ghiciți. Dar rulați codul și verificați rezultatul. Apoi, în funcție de comportamentul dorit, îmbunătățiți lizibilitatea sau modificați logica după cum este necesar.

Luați următorul exemplu simplu cu un tuplu de booleeni:

>>> True, True == (True, True)
(True, False)
>>> True, (True == (True, True))
(True, False)
>>> (True, True) == (True, True)
True

Ar trebui să existe o singură modalitate evidentă de a face acest lucru.

Pentru a îndeplini o anumită sarcină, ar trebui să existe una și o singură modalitate pitonică recomandată de a o face. Cu toate acestea, pentru orice problemă, putem avea mai multe soluții.

  13 jocuri interesante de jucat pe Apple Arcade

Chiar și în exemplul simplu de inversare a șirurilor, ne-am uitat la o soluție recursivă, tăierea șirurilor și metoda join().

Aceasta este, de asemenea, o glumă interioară, având în vedere utilizarea inconsecventă a liniuțelor. În general, folosim liniuțe em fără spații de început și de final. Sau îl folosim atât cu spațiile de început, cât și cu cele de sfârșit.

Deci, iată ce putem deduce. Aforismul care subliniază că ar trebui să existe un singur mod pitanic de a face lucrurile poate fi scris în mai mult de două moduri.

Deși acest lucru poate să nu fie evident la început decât dacă ești olandez.

Scris pe o notă ușoară, acesta se referă la Guido Van Rossum, creatorul lui Python (care este olandez). Cel mai (cel mai) mod Pythonic de a îndeplini o anumită sarcină – vine în mod natural doar pentru creatorii Python.

Așadar, pentru dezvoltatori, este nevoie de experiență – și de învățare din experiență – pentru a deveni mai bun în accesarea caracteristicilor limbajului.

Acum este mai bine decât niciodată.

Ca și în cazul altor câteva aforisme din Zen-ul lui Python, acesta poate fi interpretat și în câteva moduri diferite.

O interpretare este că, în calitate de dezvoltator, este destul de obișnuit să amâni pentru a începe codificarea unui proiect. În loc să așteptați să planificați cele mai fine detalii ale proiectului, să începeți acum este o idee mai bună.

O altă interpretare posibilă este: codul care rulează într-un număr finit de pași – și se termină – este adesea mai bun decât codul care are erori și se blochează într-o buclă infinită.

Deși niciodată nu este adesea mai bun decât acum.

Acest aforism pare să îl contrazică pe cel precedent. Deși este mai bine să nu amânăm, ar trebui totuși să ne gândim la problemă și să proiectăm codul în consecință.

Codarea unui modul – fără a-l gândi corect – plin de mirosuri de cod și anti-modele este o idee proastă. Deoarece un astfel de cod este dificil de refactorizat și de implementat măsuri corective.

Dacă implementarea este greu de explicat, este o idee proastă.

Orice logică – oricât de complexă ar fi ea – poate fi întotdeauna implementată într-o formă care este simplu de explicat și ușor de înțeles.

Dacă implementarea este dificil de explicat, probabil că există o complexitate inutilă. Codul poate fi modificat sau refactorizat, astfel încât să fie mai ușor de urmărit.

Dacă implementarea este ușor de explicat, poate fi o idee bună.

Acest lucru este legat de aforismul anterior și se explică de la sine. Dacă implementarea poate fi explicată în termeni simpli, atunci este probabil o idee bună.

Pentru că un astfel de cod a cărui implementare poate fi descrisă – în termeni simpli – este foarte probabil să fie lizibil și ușor de urmărit – cu o complexitate minimă.

Spațiile de nume sunt o idee grozavă – hai să facem mai multe dintre ele!

În Python, obiectele dintr-un anumit domeniu pot fi accesate folosind numele lor în spațiul de nume. De exemplu, puteți crea o clasă și o puteți utiliza ca șablon pentru a crea instanțe ale clasei. Acum variabilele de instanță vor fi toate în spațiul de nume al instanței.

Acest lucru ne permite să folosim obiecte cu același nume, fără conflicte, deoarece se află în spații de nume diferite. Cu toate acestea, ar trebui să le utilizați numai după cum este necesar și să vă asigurați că simplitatea și lizibilitatea codului nu sunt compromise.

Concluzie

Asta e tot pentru acest tutorial! Sper că acest ghid v-a ajutat să înțelegeți cum Zen of Python pune accentul pe stilul de cod și bunele practici de codare în Python. Cu cât codificați mai mult, cu atât mai bine veți înțelege.

Dacă sunteți interesat să învățați cum să scrieți cod concis și ușor de citit, citiți acest articol despre Python one-liners.