11.Σύντομη περιήγηση στην Πρότυπη Βιβλιοθήκη — Μέρος II¶
Αυτή η δεύτερη περιήγηση καλύπτει τα πιο προηγμένα modules που υποστηρίζουν επαγγελματικές ανάγκες προγραμματισμού. Αυτά τα modules σπάνια εμφανίζονται σε μικρά scripts.
11.1.Μορφοποίηση εξόδου¶
Το modulereprlib
παρέχει μια έκδοση τουrepr()
προσαρμοσμένη για συντομευμένες εμφανίσεις μεγάλων ή βαθιά ένθετων containers:
>>>importreprlib>>>reprlib.repr(set('supercalifragilisticexpialidocious'))"{'a', 'c', 'd', 'e', 'f', 'g', ...}"
Το modulepprint
προσφέρει πιο εξελιγμένο έλεγχο της εκτύπωσης τόσο των ενσωματωμένων (built-in) και των καθορισμένων από τον χρήστη αντικειμένων με τρόπο που είναι ευανάγνωστο από τον διερμηνέα. Όταν το αποτέλεσμα είναι μεγαλύτερο από μία γραμμή, ο «pretty printer» προσθέτει αλλαγές γραμμής και εσοχές για να εμφανιστεί πιο ξεκάθαρα η δομή δεδομένων:
>>>importpprint>>>t=[[[['black','cyan'],'white',['green','red']],[['magenta',...'yellow'],'blue']]]...>>>pprint.pprint(t,width=30)[[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta', 'yellow'], 'blue']]]
Το moduletextwrap
μορφοποιεί τις παραγράφους του κειμένου ώστε να ταιριάζει σε ένα δεδομένο πλάτος οθόνης:
>>>importtextwrap>>>doc="""The wrap() method is just like fill() except that it returns...a list of strings instead of one big string with newlines to separate...the wrapped lines."""...>>>print(textwrap.fill(doc,width=40))The wrap() method is just like fill()except that it returns a list of stringsinstead of one big string with newlinesto separate the wrapped lines.
Το modulelocale
έχει πρόσβαση σε μια βάση δεδομένων μορφών δεδομένων συγκεκριμένης κουλτούρας. Το χαρακτηριστικό ομαδοποίησης της συνάρτησης μορφοποίησης της τοπικής ρύθμισης παρέχει έναν άμεσο τρόπο μορφοποίησης αριθμών με διαχωριστικά ομάδων:
>>>importlocale>>>locale.setlocale(locale.LC_ALL,'English_United States.1252')'English_United States.1252'>>>conv=locale.localeconv()# get a mapping of conventions>>>x=1234567.8>>>locale.format_string("%d",x,grouping=True)'1,234,567'>>>locale.format_string("%s%.*f",(conv['currency_symbol'],...conv['frac_digits'],x),grouping=True)'$1,234,567.80'
11.2.Templating¶
Το modulestring
περιλαμβάνει μια ευέλικτη κλάσηTemplate
με απλοποιημένη σύνταξη κατάλληλη για επεξεργασία από τελικούς χρήστες. Αυτό επιτρέπει στους χρήστες να προσαρμόζουν τις εφαρμογές τους χωρίς να χρειάζεται να αλλάξουν την εφαρμογή.
Η μορφή χρησιμοποιεί ονόματα κράτησης θέσης που σχηματίζονται από$
με έγκυρα αναγνωριστικά Python (αλφαριθμητικούς χαρακτήρες και κάτω παύλες). Περιβάλλοντας το placeholder με αγκύλες επιτρέπει να ακολουθείται από περισσότερα αλφαριθμητικά γράμματα χωρίς ενδιάμεσα κενά. Γράφοντας$$
δημιουργεί ένα ενιαίο$
:
>>>fromstringimportTemplate>>>t=Template('${village}folk send $$10 to $cause.')>>>t.substitute(village='Nottingham',cause='the ditch fund')'Nottinghamfolk send $10 to the ditch fund.'
Η μέθοδοςsubstitute()
κάνει raise έναKeyError
όταν ένα placeholder δεν παρέχεται σε ένα λεξικό ή ένα όρισμα λέξης-κλειδιού. Για εφαρμογές στυλ συγχώνευσης mail, τα δεδομένα που παρέχονται από τον χρήστη ενδέχεται να είναι ελλιπή και η μέθοδοςsafe_substitute()
μπορεί να είναι πιο κατάλληλη — θα αφήσει αμετάβλητα τα placeholders εάν λείπουν δεδομένα:
>>>t=Template('Return the $item to $owner.')>>>d=dict(item='unladen swallow')>>>t.substitute(d)Traceback (most recent call last):...KeyError:'owner'>>>t.safe_substitute(d)'Return the unladen swallow to $owner.'
Οι υποκατηγορίες προτύπων μπορούν να καθορίσουν έναν προσαρμοσμένο οριοθέτη. Για παράδειγμα, ένα batch πρόγραμμα μετονομασίας για ένα πρόγραμμα περιήγησης φωτογραφιών μπορεί να επιλέξει να χρησιμοποιεί σύμβολα ποσοστού για placeholders όπως η τρέχουσα ημερομηνία, ο αριθμός ακολουθίας εικόνων ή η μορφή αρχείου:
>>>importtime,os.path>>>photofiles=['img_1074.jpg','img_1076.jpg','img_1077.jpg']>>>classBatchRename(Template):...delimiter='%'...>>>fmt=input('Enter rename style (%d-date %n-seqnum%f-format): ')Enter rename style (%d-date %n-seqnum %f-format): Ashley_%n%f>>>t=BatchRename(fmt)>>>date=time.strftime('%d%b%y')>>>fori,filenameinenumerate(photofiles):...base,ext=os.path.splitext(filename)...newname=t.substitute(d=date,n=i,f=ext)...print('{0} -->{1}'.format(filename,newname))img_1074.jpg --> Ashley_0.jpgimg_1076.jpg --> Ashley_1.jpgimg_1077.jpg --> Ashley_2.jpg
Μια άλλη εφαρμογή για templating είναι ο διαχωρισμός της λογικής του προγράμματος από τις λεπτομέρειες πολλαπλών μορφών εξόδου. Αυτό καθιστά δυνατή την αντικατάσταση προσαρμοσμένων προτύπων για αρχεία XML, αναφορές απλού κειμένου και αναφορές ιστού HTML.
11.3.Εργασία με δυαδικές διατάξεις εγγραφής δεδομένων¶
Το modulestruct
παρέχει τις συναρτήσειςpack()
καιunpack()
για εργασία με μορφές δυαδικών (binary) εγγραφών μεταβλητού μήκους. Το ακόλουθο παράδειγμα δείχνει πως να κάνετε μια λούπα μέσω των πληροφοριών κεφαλίδας στο ένα αρχείο ZIP χωρίς τη χρήση του modulezipfile
. Οι κωδικοί πακέτου"H"
και"I"
αντιπροσωπεύουν αριθμούς χωρίς υπογραφή δύο και τεσσάρων byte αντίστοιχα. Το"<"
υποδηλώνει ότι είναι τυπικού μεγέθους και σε σειρά byte λίγο endian:
importstructwithopen('myfile.zip','rb')asf:data=f.read()start=0foriinrange(3):# show the first 3 file headersstart+=14fields=struct.unpack('<IIIHH',data[start:start+16])crc32,comp_size,uncomp_size,filenamesize,extra_size=fieldsstart+=16filename=data[start:start+filenamesize]start+=filenamesizeextra=data[start:start+extra_size]print(filename,hex(crc32),comp_size,uncomp_size)start+=extra_size+comp_size# skip to the next header
11.4.Multi-threading¶
Το threading είναι μια τεχνική για την αποσύνδεση εργασιών που είναι διαδοχικά εξαρτώμενες. Τα νήματα μπορούν να χρησιμοποιηθούν για την βελτίωση της ανταπόκρισης των εφαρμογών που δέχονται είσοδο από τον χρήστη ενώ άλλες εργασίες εκτελούνται στο παρασκήνιο. Μια σχετική περίπτωση χρήσης εκτελεί I/O παράλληλα με υπολογισμούς στο άλλο νήμα.
Ο ακόλουθος κώδικας δείχνει πως το module υψηλού επιπέδουthreading
μπορεί να εκτελεί εργασίες στο παρασκήνιο ενώ το κύριο πρόγραμμα συνεχίζει να εκτελείται:
importthreading,zipfileclassAsyncZip(threading.Thread):def__init__(self,infile,outfile):threading.Thread.__init__(self)self.infile=infileself.outfile=outfiledefrun(self):f=zipfile.ZipFile(self.outfile,'w',zipfile.ZIP_DEFLATED)f.write(self.infile)f.close()print('Finished background zip of:',self.infile)background=AsyncZip('mydata.txt','myarchive.zip')background.start()print('The main program continues to run in foreground.')background.join()# Wait for the background task to finishprint('Main program waited until background was done.')
Η κύρια πρόκληση των εφαρμογών πολλαπλών νημάτων είναι ο συντονισμός νημάτων που μοιράζονται δεδομένα ή άλλους πόρους. Για το σκοπό αυτό, το thread module παρέχει έναν αριθμό πρωτόγονων συγχρονισμού, συμπεριλαμβανομένων locks, events, μεταβλητών συνθηκών, και semaphores.
Ενώ αυτά τα εργαλεία είναι ισχυρά, μικρά σφάλματα σχεδιασμού μπορεί να οδηγήσουν σε προβλήματα που είναι δύσκολο να αναπαραχθούν. Επομένως, η προτιμώμενη προσέγγιση στον συντονισμό εργασιών είναι να συγκεντρωθεί όλη η πρόσβαση σε έναν πόρο σε ένα μόνο νήμα και στη συνέχεια να χρησιμοποιηθεί το modulequeue
, για τροφοδοτήσει αυτό το νήμα με αιτήματα από άλλα νήματα. Οι εφαρμογές που χρησιμοποιούν αντικείμεναQueue
για επικοινωνία και συντονισμό μεταξύ νημάτων είναι πιο εύκολο να σχεδιαστούν, είναι πιο ευανάγνωστες και πιο αξιόπιστες.
11.5.Logging¶
Το modulelogging
προσφέρει ένα πλήρως εξοπλισμένο και ευέλικτο σύστημα καταγραφής. Στην απλούστερη μορφή του, τα μηνύματα καταγραφής αποστέλλονται σε ένα αρχείο ή στοsys.stderr
:
importlogginglogging.debug('Debugging information')logging.info('Informational message')logging.warning('Warning:config file%s not found','server.conf')logging.error('Error occurred')logging.critical('Critical error -- shutting down')
Αυτό παράγει την ακόλουθη έξοδο:
WARNING:root:Warning:config file server.conf not foundERROR:root:Error occurredCRITICAL:root:Critical error -- shutting down
Από default (προεπιλογή), τα ενημερωτικά μηνύματα και τα μηνύματα εντοπισμού σφαλμάτων αποκρύπτονται και η έξοδος αποστέλλεται σε τυπικό σφάλμα. Άλλες επιλογές εξόδου περιλαμβάνουν δρομολόγηση μηνυμάτων μέσω email, datagrams, υποδοχών (sockets), ή σε HTTP διακομιστή (server). Τα νέα φίλτρα μπορούν να επιλέξουν διαφορετική δρομολόγηση με βάση την προτεραιότητα του μηνύματος:DEBUG
,INFO
,WARNING
,ERROR
, καιCRITICAL
.
Το σύστημα logging μπορεί να διαμορφωθεί απευθείας από την Python ή μπορεί να φορτωθεί από ένα επεξεργάσιμο αρχείο διαμόρφωσης για προσαρμοσμένη καταγραφή χωρίς την τροποποίηση της εφαρμογής.
11.6.Αδύναμες αναφορές¶
Η Python κάνει αυτόματη διαχείριση μνήμης (καταμέτρηση αναφορών για τα περισσότερα αντικείμενα καιgarbage collection για την εξάλειψη των κύκλων). Η μνήμη ελευθερώνεται λίγο μετά την κατάργηση της τελευταίας αναφοράς σε αυτήν.
Αυτή η προσέγγιση λειτουργεί καλά για τις περισσότερες εφαρμογές, αλλά περιστασιακά υπάρχει ανάγκη παρακολούθησης αντικειμένων μόνο εφόσον χρησιμοποιούνται από κάτι άλλο. Δυστυχώς, η παρακολούθηση τους δημιουργεί μια αναφορά που τα κάνει μόνιμα. Το moduleweakref
παρέχει εργαλεία για την παρακολούθηση αντικειμένων χωρίς τη δημιουργία αναφοράς. Όταν το αντικείμενο δεν χρειάζεται πλέον, αφαιρείται αυτόματα από έναν πίνακα ασθενούς αναφοράς και ενεργοποιείται μια επιστροφή κλήσης για αντικείμενα ασθενούς αναφοράς:
>>>importweakref,gc>>>classA:...def__init__(self,value):...self.value=value...def__repr__(self):...returnstr(self.value)...>>>a=A(10)# create a reference>>>d=weakref.WeakValueDictionary()>>>d['primary']=a# does not create a reference>>>d['primary']# fetch the object if it is still alive10>>>dela# remove the one reference>>>gc.collect()# run garbage collection right away0>>>d['primary']# entry was automatically removedTraceback (most recent call last): File"<stdin>", line1, in<module>d['primary']# entry was automatically removed File"C:/python314/lib/weakref.py", line46, in__getitem__o=self.data[key]()KeyError:'primary'
11.7.Εργαλεία για εργασία με λίστες¶
Πολλές ανάγκες δομών δεδομένων μπορούν να καλυφθούν με τον ενσωματωμένο τύπο λίστας. Ωστόσο, μερικές φορές υπάρχει ανάγκη για εναλλακτικές υλοποιήσεις με διαφορετικούς συμβιβασμούς απόδοσης.
Το modulearray
παρέχει ένα αντικείμενοarray
που μοιάζει με μια λίστα που αποθηκεύει μόνο ομοιογενή δεδομένα και τα αποθηκεύει με πιο συμπαγή τρόπο. Το ακόλουθο παράδειγμα δείχνει έναν πίνακα αριθμών που είναι αποθηκευμένοι ως δύο byte ανυπόγραφων δυαδικών (binary) αριθμών (κωδικός τύπου"H"
) αντί για τα συνηθισμένα 16 byte ανά καταχώρηση για κανονικές λίστες αντικειμένων τύπου Python int:
>>>fromarrayimportarray>>>a=array('H',[4000,10,700,22222])>>>sum(a)26932>>>a[1:3]array('H', [10, 700])
Το modulecollections
παρέχει ένα αντικείμενοdeque
που μοιάζει με λίστα με ταχύτερα προσαρτήματα και αναδύεται από την αριστερή πλευρά αλλά με πιο αργές αναζητήσεις στη μέση. Αυτά τα αντικείμενα είναι κατάλληλα για υλοποίηση ουρών και αναζητήσεων σε πρώτο δέντρο εύρους:
>>>fromcollectionsimportdeque>>>d=deque(["task1","task2","task3"])>>>d.append("task4")>>>print("Handling",d.popleft())Handling task1
unsearched=deque([starting_node])defbreadth_first_search(unsearched):node=unsearched.popleft()formingen_moves(node):ifis_goal(m):returnmunsearched.append(m)
Εκτός από τις εναλλακτικές υλοποιήσεις λιστών, η βιβλιοθήκη προσφέρει επίσης και άλλα εργαλεία όπως το modulebisect
με συναρτήσεις για τον χειρισμό ταξινομημένων λιστών:
>>>importbisect>>>scores=[(100,'perl'),(200,'tcl'),(400,'lua'),(500,'python')]>>>bisect.insort(scores,(300,'ruby'))>>>scores[(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]
Το moduleheapq
παρέχει λειτουργίες για την υλοποίηση σωρών (heaps) που βασίζονται σε κανονικές λίστες. Η καταχώριση με την χαμηλότερη τιμή διατηρείται πάντα στη θέση μηδέν. Αυτό είναι χρήσιμο για εφαρμογές που έχουν επανειλημμένα πρόσβαση στο μικρότερο στοιχείο αλλά δεν θέλουν να εκτελέσουν μια πλήρη ταξινόμηση λίστας:
>>>fromheapqimportheapify,heappop,heappush>>>data=[1,3,5,7,9,2,4,6,8,0]>>>heapify(data)# rearrange the list into heap order>>>heappush(data,-5)# add a new entry>>>[heappop(data)foriinrange(3)]# fetch the three smallest entries[-5, 0, 1]
11.8.Δεκαδική Αριθμητικής Κινητής Υποδιαστολής¶
Το moduledecimal
προσφέρουν έναν τύπο δεδομένωνDecimal
για δεκαδική αριθμητική κινητής υποδιαστολής. Σε σύγκριση με την ενσωματωμένη (built-in) εφαρμογήfloat
του δυαδικού κινητής υποδιαστολής, η κλάση είναι ιδιαίτερα χρήσιμη για
οικονομικές εφαρμογές και άλλες χρήσεις που απαιτούν ακριβή δεκαδική αναπαράσταση,
έλεγχος για την ακρίβεια,
έλεγχος της στρογγυλοποίησης για την εκπλήρωση νομικών ή κανονιστικών απαιτήσεων,
παρακολούθηση σημαντικών δεκαδικών ψηφίων, ή
εφαρμογές όπου ο χρήστης αναμένει ότι τα αποτελέσματα ταιριάζουν με υπολογισμούς που έγιναν με το χέρι.
Για παράδειγμα, ο υπολογισμός ενός φόρου 5% σε χρέωση τηλεφώνου 70 λεπτών δίνει διαφορετικά αποτελέσματα σε δεκαδική κινητή υποδιαστολή και σε δυαδική (binary) κινητή υποδιαστολή. Η διαφορά γίνεται σημαντική εάν τα αποτελέσματα στρογγυλοποιηθούν στο πλησιέστερο λεπτό:
>>>fromdecimalimport*>>>round(Decimal('0.70')*Decimal('1.05'),2)Decimal('0.74')>>>round(.70*1.05,2)0.73
Το αποτέλεσμαDecimal
διατηρεί ένα μηδέν στο τέλος, συνάγοντας αυτόματα τη σημασία τεσσάρων θέσεων από πολλαπλάσια με σημασία δύο θέσεων. Το δεκαδικό αναπαράγει τα μαθηματικά όπως γίνονται με το χέρι και αποφεύγει ζητήματα που μπορεί να προκύψουν όταν η δυαδική κινητή υποδιαστολή δεν μπορεί να αντιπροσωπεύει ακριβώς τις δεκαδικές ποσότητες.
Η ακριβής αναπαράσταση επιτρέπει στην κλάσηDecimal
να εκτελεί υπολογισμούς modulo και δοκιμές ισότητας που είναι ακατάλληλες για δυαδική κινητή υποδιαστολή:
>>>Decimal('1.00')%Decimal('.10')Decimal('0.00')>>>1.00%0.100.09999999999999995>>>sum([Decimal('0.1')]*10)==Decimal('1.0')True>>>0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1==1.0False
Το moduledecimal
παρέχει αριθμητική με όση ακρίβεια χρειάζεται:
>>>getcontext().prec=36>>>Decimal(1)/Decimal(7)Decimal('0.142857142857142857142857142857142857')