10. Σύντομη ξενάγηση στην Standard Βιβλιοθήκη
*********************************************


10.1. Διεπαφή Λειτουργικού Συστήματος
=====================================

Το module "os" παρέχει δεκάδες λειτουργίες για αλληλεπίδραση με το
λειτουργικό σύστημα:

   >>> import os
   >>> os.getcwd()      # Return the current working directory
   'C:\\Python314'
   >>> os.chdir('/server/accesslogs')   # Change current working directory
   >>> os.system('mkdir today')   # Run the command mkdir in the system shell
   0

Βεβαιωθείτε ότι χρησιμοποιείτε το στυλ "import os" αντί για το "from
os import *".  Αυτό θα κρατήσει το "os.open()" υπό τη σκίαση της
ενσωματωμένης συνάρτησης "open()" που λειτουργεί πολύ διαφορετικά.

Οι ενσωματωμένες συναρτήσεις "dir()" και "help()" είναι χρήσιμες ως
διαδραστικά βοηθήματα για εργασία με μεγάλα modules όπως "os":

   >>> import os
   >>> dir(os)
   <επιστρέφει μια λίστα από όλες τις συναρτήσεις module>
   >>> help(os)
   <επιστρέφει μια εκτενή σελίδα εγχειριδίου που δημιουργήθηκε από τα docstrings του module>

Για καθημερινές διαχειριστικές εργασίες σε αρχεία και καταλόγους, το
module "shutil" παρέχει μια διεπαφή υψηλότερου επιπέδου που είναι πιο
εύκολη στην χρήση:

   >>> import shutil
   >>> shutil.copyfile('data.db', 'archive.db')
   'archive.db'
   >>> shutil.move('/build/executables', 'installdir')
   'installdir'


10.2. Wildcard Αρχεία
=====================

Το module "glob" παρέχει μια λειτουργία για τη δημιουργία λιστών
αρχείων από αναζητήσεις με χαρακτήρες μπαλαντέρ καταλόγου:

   >>> import glob
   >>> glob.glob('*.py')
   ['primes.py', 'random.py', 'quote.py']


10.3. Ορίσματα γραμμής εντολών
==============================

Τα κοινά scripts βοηθητικών προγραμμάτων συχνά χρειάζονται να
επεξεργάζονται ορίσματα γραμμής εντολών. Αυτά τα ορίσματα
αποθηκεύονται στο χαρακτηριστικό *argv* του module "sys" ως λίστα.
Για παράδειγμα, ας πάρουμε το ακόλουθο αρχείο "demo.py":

   # File demo.py
   import sys
   print(sys.argv)

Εδώ είναι το αποτέλεσμα από την εκτέλεση του "python demo.py one two
three" στη γραμμή εντολών:

   ['demo.py', 'one', 'two', 'three']

Το module "argparse" παρέχει έναν πιο εξελιγμένο μηχανισμό για την
επεξεργασία ορισμάτων γραμμής εντολών.  Το ακόλουθο script εξάγει ένα
ή περισσότερα ονόματα αρχείων και έναν προαιρετικό αριθμό γραμμών που
θα εμφανιστούν:

   import argparse

   parser = argparse.ArgumentParser(
       prog='top',
       description='Show top lines from each file')
   parser.add_argument('filenames', nargs='+')
   parser.add_argument('-l', '--lines', type=int, default=10)
   args = parser.parse_args()
   print(args)

Όταν εκτελείται στη γραμμή εντολών το "python top.py --lines=5
alpha.txt beta.txt", το script ορίζει το "args.lines" σε "5" και το
"args.filenames" σε "['alpha.txt', 'beta.txt']".


10.4. Ανακατεύθυνση εξόδου σφάλματος και τερματισμός προγράμματος
=================================================================

Το module "sys" έχει επίσης χαρακτηριστικά για *stdin*, *stdout*, και
*stderr*. Το τελευταίο είναι χρήσιμο για την εκπομπή προειδοποιήσεων
και μηνυμάτων σφαλμάτων ώστε να είναι ορατά ακόμα και όταν το *stdout*
έχει ανακατευθυνθεί:

   >>> sys.stderr.write('Warning, log file not found starting a new one\n')
   Warning, log file not found starting a new one

Ο πιο άμεσος τρόπος για να τερματίσετε ένα script είναι να
χρησιμοποιήσετε το "sys.exit()".


10.5. Ταίριασμα μοτίβων συμβολοσειρών
=====================================

Το module "re" παρέχει εργαλεία κανονική έκφρασης για προηγμένη
επεξεργασία συμβολοσειρών. Για πολύπλοκη αντιστοίχιση και χειρισμό, οι
τυπικές εκφράσεις προσφέρουν συνοπτικές, βελτιστοποιημένες λύσεις:

   >>> import re
   >>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
   ['foot', 'fell', 'fastest']
   >>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
   'cat in the hat'

Όταν χρειάζονται μόνο απλές δυνατότητες, προτιμώνται οι μέθοδοι
συμβολοσειρών, επειδή είναι ευκολότερες στην ανάγνωση και τον
εντοπισμό σφαλμάτων:

   >>> 'tea for too'.replace('too', 'two')
   'tea for two'


10.6. Μαθηματικά
================

Το module "math" δίνει πρόσβαση στις υποκείμενες συναρτήσεις της
βιβλιοθήκης C για μαθηματικά κινητής υποδιαστολής:

   >>> import math
   >>> math.cos(math.pi / 4)
   0.70710678118654757
   >>> math.log(1024, 2)
   10.0

Το module "random" παρέχει εργαλεία για να κάνουμε τυχαίες επιλογές:

   >>> import random
   >>> random.choice(['apple', 'pear', 'banana'])
   'apple'
   >>> random.sample(range(100), 10)   # sampling without replacement
   [30, 83, 16, 4, 8, 81, 41, 50, 18, 33]
   >>> random.random()    # random float from the interval [0.0, 1.0)
   0.17970987693706186
   >>> random.randrange(6)    # random integer chosen from range(6)
   4

Το module "statistics" υπολογίζει βασικές στατιστικές ιδιότητες (μέσος
όρος, διάμεσος, διακύμανση, κ.λπ.) αριθμητικών δεδομένων:

   >>> import statistics
   >>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
   >>> statistics.mean(data)
   1.6071428571428572
   >>> statistics.median(data)
   1.25
   >>> statistics.variance(data)
   1.3720238095238095

Το έργο SciPy <https://scipy.org> έχει πολλές άλλες ενότητες για
αριθμητικούς υπολογισμούς.


10.7. Πρόσβαση στο Διαδίκτυο
============================

Υπάρχει ένας αριθμός modules για πρόσβαση στο διαδίκτυο και
επεξεργασία πρωτοκόλλων διαδικτύου. Δύο από τα πιο απλά είναι το
"urllib.request" για να την ανάκτηση δεδομένων από διευθύνσεις URL και
το "smtplib" για την αποστολή αλληλογραφίας:

   >>> from urllib.request import urlopen
   >>> with urlopen('http://worldtimeapi.org/api/timezone/etc/UTC.txt') as response:
   ...     for line in response:
   ...         line = line.decode()             # Convert bytes to a str
   ...         if line.startswith('datetime'):
   ...             print(line.rstrip())         # Remove trailing newline
   ...
   datetime: 2022-01-01T01:36:47.689215+00:00

   >>> import smtplib
   >>> server = smtplib.SMTP('localhost')
   >>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
   ... """To: jcaesar@example.org
   ... From: soothsayer@example.org
   ...
   ... Beware the Ides of March.
   ... """)
   >>> server.quit()

(Σημειώστε ότι το δεύτερο παράδειγμα χρειάζεται διακομιστή
αλληλογραφίας που εκτελείται σε localhost.)


10.8. Ημερομηνίες και ώρες
==========================

Το module "datetime" παρέχει κλάσεις για χειρισμό ημερομηνιών και ωρών
με απλούς και σύνθετους τρόπους. Ενώ υποστηρίζεται η αριθμητική
ημερομηνία και ώρα, η υλοποίηση εστιάζεται στην αποτελεσματική εξαγωγή
μελών για μορφοποίηση και χειρισμό εξόδου.  Το module επίσης
υποστηρίζει αντικείμενα που έχουν επίγνωση ζώνης ώρας.

   >>> # dates are easily constructed and formatted
   >>> from datetime import date
   >>> now = date.today()
   >>> now
   datetime.date(2003, 12, 2)
   >>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
   '12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'

   >>> # dates support calendar arithmetic
   >>> birthday = date(1964, 7, 31)
   >>> age = now - birthday
   >>> age.days
   14368


10.9. Συμπίεση Δεδομένων
========================

Οι συνήθεις μορφές αρχειοθέτησης και συμπίεσης δεδομένων
υποστηρίζονται άμεσα από modules όπως: "zlib", "gzip", "bz2", "lzma",
"zipfile" και "tarfile".

   >>> import zlib
   >>> s = b'witch which has which witches wrist watch'
   >>> len(s)
   41
   >>> t = zlib.compress(s)
   >>> len(t)
   37
   >>> zlib.decompress(t)
   b'witch which has which witches wrist watch'
   >>> zlib.crc32(s)
   226805979


10.10. Μέτρηση επίδοσης
=======================

Ορισμένοι χρήστες Python αναπτύσσουν βαθύ ενδιαφέρον να γνωρίζουν τη
σχετική απόδοση διαφορετικών προσεγγίσεων στο ίδιο πρόβλημα. Η Python
παρέχει ένα εργαλείο μέτρησης που απαντά σε αυτές τις ερωτήσεις
αμέσως.

Για παράδειγμα, μπορεί να είναι δελεαστικό να χρησιμοποιήσετε τη
δυνατότητα tuple packing και unpacking αντί της παραδοσιακής
προσέγγισης για την εναλλαγή ορισμάτων. Το module "timeit" δείχνει
γρήγορα ένα ταπεινό πλεονέκτημα απόδοσης:

   >>> from timeit import Timer
   >>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
   0.57535828626024577
   >>> Timer('a,b = b,a', 'a=1; b=2').timeit()
   0.54962537085770791

Σε αντίθεση με το λεπτό επίπεδο ευκρίνειας του "timeit", τα modules
"profile" και "pstats" παρέχουν εργαλεία για τον εντοπισμό κρίσιμων
χρονικών τμημάτων σε μεγαλύτερα μπλοκ κώδικα.


10.11. Έλεγχος ποιότητας
========================

Μια καλή προσέγγιση για την ανάπτυξη λογισμικού υψηλής ποιότητας είναι
να γράφονται tests για κάθε λειτουργία καθώς αναπτύσσεται και να
εκτελούνται συχνά αυτά τα tests κατά τη διαδικασία ανάπτυξης.

Το module "doctest" παρέχει ένα εργαλείο για τη σάρωση ενός module και
την επικύρωση tests που είναι ενσωματωμένες στις συμβολοσειρές
εγγράφων ενός προγράμματος.  Η κατασκευή του test είναι τόσο απλή όσο
η αποκοπή και επικόλληση μιας τυπικής κλήσης μαζί με τα αποτελέσματα
της στη συμβολοσειρά εγγράφων. Αυτό βελτιώνει την τεκμηρίωση
παρέχοντας στον χρήστη ένα παράδειγμα και επιτρέπει στην ενότητα
doctest να βεβαιωθεί ότι ο κώδικας παραμένει πιστός στην τεκμηρίωση:

   def average(values):
       """Υπολογίζει έναν αριθμητικό μέσο για μια λίστα από αριθμούς.

       >>> print(average([20, 30, 70]))
       40.0
       """
       return sum(values) / len(values)

   import doctest
   doctest.testmod()   # automatically validate the embedded tests

Το module "unittest" δεν είναι τόσο εύκολο όσο το module "doctest",
αλλά επιτρέπει τη διατήρηση ενός πιο ολοκληρωμένου συνόλου tests σε
ξεχωριστό αρχείο:

   import unittest

   class TestStatisticalFunctions(unittest.TestCase):

       def test_average(self):
           self.assertEqual(average([20, 30, 70]), 40.0)
           self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
           with self.assertRaises(ZeroDivisionError):
               average([])
           with self.assertRaises(TypeError):
               average(20, 30, 70)

   unittest.main()  # Calling from the command line invokes all tests


10.12. Batteries Included
=========================

Η Python έχει μια φιλοσοφία "συμπεριλαμβάνονται μπαταρίες".  Αυτό
φαίνεται καλύτερα μέσα από τις εξελιγμένες και ισχυρές δυνατότητες των
μεγαλύτερων πακέτων της. Για παράδειγμα:

* Τα modules "xmlrpc.client" και "xmlrpc.server" καθιστούν την
  υλοποίηση κλήσεων απομακρυσμένων διαδικασιών σε μια σχεδόν ασήμαντη
  εργασία.  Παρά τα ονόματα των modules, δεν απαιτείται άμεση γνώση ή
  χειρισμός της XML.

* Το πακέτο "email" είναι μια βιβλιοθήκη για τη διαχείριση μηνυμάτων
  ηλεκτρονικού ταχυδρομείου, συμπεριλαμβανομένων MIME και άλλων
  μηνυμάτων εγγράφων που βασίζονται σε **RFC 2822**. Σε αντίθεση με τα
  "smtplib" και "poplib" που στην πραγματικότητα στέλνουν και
  λαμβάνουν μηνύματα, το πακέτο email έχει ένα πλήρες σύνολο εργαλείων
  για τη δημιουργία ή την αποκωδικοποίηση πολύπλοκων δομών μηνυμάτων
  (συμπεριλαμβανομένων των συνημμένων) και για την εφαρμογή
  κωδικοποίηση και πρωτόκολλο κεφαλίδων στο διαδίκτυο.

* Το πακέτο "json" παρέχει ισχυρή υποστήριξη για την ανάλυση αυτής της
  δημοφιλούς μορφής ανταλλαγής δεδομένων.  Το module "csv" υποστηρίζει
  την άμεση ανάγνωση και εγγραφή αρχείων σε μορφή τιμής διαχωρισμένου
  με κόμματα, που συνήθως υποστηρίζεται από βάσεις δεδομένων και
  υπολογιστικά φύλλα.  Η XML επεξεργασία υποστηρίζεται από τα πακέτα
  "xml.etree.ElementTree", "xml.dom" και "xml.sax". Μαζί, αυτές οι
  μονάδες και τα πακέτα απλοποιούν σημαντικά την ανταλλαγή δεδομένων
  μεταξύ εφαρμογών Python και άλλων εργαλείων.

* Το module "sqlite3" αποτελεί έναν wrapper για τη βιβλιοθήκη της
  βάσης δεδομένων SQLite, παρέχοντας μια συνεχής βάση δεδομένων που
  μπορεί να ενημερωθεί και να προσπελαστεί χρησιμοποιώντας ελαφρώς μη
  τυπική σύνταξη SQL.

* Η διεθνοποίηση υποστηρίζεται από έναν αριθμό modules,
  συμπεριλαμβανομένων των "gettext", "locale", και το πακέτο "codecs".
