Byte of Python - Ελληνική Έκδοση

Αρθρώματα

Εισαγωγή

Έχετε δει πώς μπορείτε να επαναχρησιμοποιήσετε κώδικα στο πρόγραμμά σας ορίζοντας μια φορά συναρτήσεις. Τι κάνετε όμως αν θέλετε να επαναχρησιμοποιήσετε έναν αριθμό συναρτήσεων σε άλλα προγράμματα που γράφετε; Όπως ίσως έχετε μαντέψει η απάντηση είναι τα αρθρώματα.

Υπάρχουν διάφορες μεθόδοι γαι να γράφετε αρθρώματα, αλλά ο απλούστερος τρόπος είναι δημιουργώντας ένα αρχείο με επέκταση .py το οποίο θα περιέχει συναρτήσεις και μεταβλητές.

Ένας άλλος τρόπος είναι να γράφετε τα αρθρώματα στην αρχική γλώσσα στην οποία γράφτηκε o διερμηνευτής της Python. Για παράδειγμα μπορείτε να γράψετε αρθρώματα στη γλώσσα προγραμματισμού C και μόλις μεταγλωτιστούν, να χρησιμοποιηθούν από τον κώδικα που γράφετε σε Python όταν χρησιμοποιείτε τον πρότυπο διερμηνευτή της Python.

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

Παράδειγμα:

#!/usr/bin/python
# Filename: using_sys.py

import sys

print('Οι παράμετροι γραμμής εντολών είναι:')
for i in sys.argv:
    print(i)

print('\n\nΗ μεταβλητή συστήματος PYTHONPATH έχει την τιμή', sys.path, '\n')

Έξοδος:

$ python using_sys.py we are arguments
Οι παράμετροι γραμμής εντολών είναι:
using_sys.py
we
are
arguments

Η μεταβλητή συστήματος PYTHONPATH έχει την τιμή ['', 'C:\\Windows\\system32\\python30.zip',
'C:\\Python30\\DLLs', 'C:\\Python30\\lib',
'C:\\Python30\\lib\\plat-win', 'C:\\Python30', 
'C:\\Python30\\lib\\site-packages']

Πώς λειτουργεί:

Aρχικά εισάγετε το άρθρωμα sys χρησιμοποιώντας την εντολή import. Κατά κύριο λόγο αυτό για την Python σημαίνει ότι θέλουμε να χρησιμοποιήσουμε αυτό το άρθρωμα. Το άρθρωμα sys περιέχει λειτουργικότητα που έχει σχέση με τον διερμηνευτή της Python και το περιβάλλον του δηλ. το σύστημα (sysstem).

Όταν η Python εκτελεί την εντολή import sys, ψάχνει για το άρθρωμα sys. Σε αυτή την περίπτωση, είναι ένα από τα ενσωματωμένα αρθρώματα, και γι αυτό η Python ξέρει που θα το βρει.

Εάν δεν ήταν ένα ενσωματωμένο άρθρωμα δηλ. ένα άρθρωμα γραμμένο σε Python, τότε ο διερμηνευτής της Python θα το έψαχνε στους καταλόγους που βρίσκονται στη μεταβλητή sys.path. Εάν το άρθρωμα βρεθεί τότε οι εντολές στο κυρίως τμήμα του αρθρώματος τρέχουν και τότε το άρθρωμα σας γίνεται διαθέσιμο για να το χρησιμοποιήσετε. Σημειώστε ότι η αρχικοποίηση γίνεται μόνο την πρώτη φορά που εισάγουμε ένα άρθρωμα.

Η μεταβλητή argv στο άρθρωμα sys εισάγεται χρησιμοποιώντας συμβολισμό με τελείες δηλ. sys.argv. Αυτό δείχνει ξεκάθαρα ότι αυτή η ονομασία είναι μέρος του αρθρώματος sys. Ένα ακόμα πλεονέκτημα αυτής της προσέγγισης είναι ότι αυτή η ονομασία δεν συγκρούεται με καμμία άλλη μεταβλητή argv που χρησιμοποιείται στο πρόγραμμά σας.

Σημείωση

Η μεταβλητή sys.argv είναι μια λίστα συμβολοσειρών (οι λίστες εξηγούνται σε επόμενο κεφάλαιο. Eιδικά η sys.argv περιέχει τον κατάλογο των ορισμάτων της γραμμής εντολών (command line arguments) δηλ. τα ορίσματα που έχουν περάσει στο πρόγραμμά σας χρησιμοποιώντας την γραμμή εντολών.

Εάν χρησιμοποιείτε κάποιο IDE (Integrated Development Enviroment δηλ. ολοκληρωμένο περιβάλλον ανάπτυξης) για να γράψετε και να τρέξετε αυτά τα προγράμματα, ψάξε στα μενού για έναν τρόπο να καθορίζετε ορίσματα γραμμής εντολών στο πρόγραμμα.

Εδώ όταν εκτελούμε python using_sys.py we are arguments, τρέχουμε το άρθρωμα using_sys.py με την εντολή python και τα άλλα στοιχεία που ακολουθούν είναι ορίσματα που περνούν στο πρόγραμμα. Η Python αποθηκεύει τα ορίσματα της γραμμής εντολών στη μεταβλητή sys.argv για να τα χρησιμοποιήσουμε.

Θυμηθείτε ότι η ονομασία του σεναρίου εντολών που τρέχει είναι πάντα το πρώτο όρισμα στη λίστα sys.argv. Έτσι σε αυτή την περίπτωση θα έχουμε το 'using_sys.py' σαν sys.argv[0], το 'we' σαν sys.argv[1], το 'are' σαν sys.argv[2] και το 'arguments' σαν sys.argv[3]. Σημειώστε ότι η Python αρχίζει να μετράει από το 0 και όχι από το 1.

Το sys.path περιέχει τη λίστα με τα ονόματα καταλόγων από όπου εισάγονται τα αρθρώματα. Παρατηρήστε ότι η πρώτη συμβολοσειρά στο sys.path είναι άδεια. Αυτή η άδεια συμβολοσειρά δείχνει ότι ο τρέχων κατάλογος είναι επίσης μέρος του sys.path, o οποίος είναι το ίδιο με τη μεταβλητή περιβάλλοντος PYTHONPATH. Αυτό σημαίνει ότι μπορείτε απευθείας να εισάγετε αρθρώματα που βρίσκονται στον τρέχοντα κατάλογο. Διαφορετικά πρέπει να τοποθετήσετε το άρθρωμά σας σε έναν από τους καταλόγους που βρίσκονται στο sys.path.

Σημειώστε ότι ο τρέχων κατάλογος είναι ο κατάλογος από όπου το πρόγραμμα εκκινείται. Τρέξτε import os; print(os.getcwd()) για να βρείτε τον τρέχοντα κατάλογο του προγράμματός σας.

Μεταγλωττισμένα αρχεία με επέκταση .pyc

Η εισαγωγή ενός αρθρώματος είναι μια υπόθεση που κοστίζει, έτσι η Python κάνει μερικά κόλπα για να το κάνετε γρηγορότερα. Ένας τρόπος είναι η δημιουργία μεταγλωττισμένων αρχείων (byte-compiled files) με την επέκταση .pyc η οποία είναι μια ενδιάμεση μορφή στην οποία η Python μετατρέπει το πρόγραμμα (θυμηθείτε το εισαγωγικό τμήμα του βιβλίου για το πώς λειτουργεί η Python). Αυτό το αρχείο με επέκταση .pyc είναι χρήσιμο την επόμενη φορά που θα εισάγετε το άρθρωμα από ένα διαφορετικό πρόγραμμα. Αυτό θα είναι πολύ ταχύτερο γιατί ένα τμήμα της διεργασίας για την εισαγωγή ενός αρθρώματος έχει ήδη γίνει. Επίσης τα byte-compiled αρχεία είναι ανεξάρτητα πλατφόρμας (platform-independent).

Σημείωση

Τα αρχεία .pyc συνήθως δημιουργούνται στον ίδιο κατάλογο με τα αντίστοιχα αρχεία .py. Εάν η Python δεν έχει άδεια για να γράψει σε αρχεία σε αυτόν τον κατάλογο, τότε τα αρχεία .pyc δε θα δημιουργηθούν.

Η εντολή from ... import ...

Eάν θέλετε να εισάγετε απευθείας τη μεταβλητή argv μέσα στο πρόγραμμά σας (για να αποφύγετε την πληκτρολόγηση του sys. κάθε φορά), τότε μπορείτε να χρησιμοποιήσετε την εντολή from sys import argv. Εάν θέλετε να εισάγετε όλες τις ονομασίες που χρησιμοποιούνται στο άρθρωμα sys, τότε μπορείτε να χρησιμοποιήσετε την εντολή from sys import *. Αυτό λειτουργεί σε κάθε άρθρωμα.

Γενικά πρέπει να αποφεύγετε να χρησιμοποιείτε αυτή την εντολή και αντ' αυτής να χρησιμοποιείτε την εντολή import επειδή έτσι το πρόγραμμά σας θα αποφύγει την σύγκρουση των ονομασιών και θα είναι πιο ευανάγνωστο.

Ονομασία αρθρώματος

Κάθε άρθρωμα έχει μια ονομασία και οι εντολές σε ένα άρθρωμα μπορούν να ανακαλύψουν το όνομα του αρθρώματός τους. Αυτό είναι εύχρηστο στην ειδική κατάσταση του υπολογισμού για το εάν το άρθρωμα τρέχει μόνο του ή εισάγεται. Όπως αναφέρθηκε προηγουμένως, όταν ένα άρθρωμα εισάγεται για πρώτη φορά, ο κώδικας σε αυτό το άρθρωμα εκτελείται. Μπορούμε να χρησιμοποιήσουμε αυτή την έννοια για να αλλάξουμε τη συμπεριφορά του αρθρώματος εάν το πρόγραμμα χρησιμοποιείται από μόνο του και όχι όταν εισάγεται από ένα άλλο άρθρωμα. Αυτό μπορεί να επιτευχθεί χρησιμοποιώντας το χαρακτηριστικό (attribute) __name__ του αρθρώματος.

Παράδειγμα:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Filename: using_name.py
if __name__ == '__main__':
    print('Aυτό το πρόγραμμα τρέχει από μόνο του.')
else:
    print('Έχω εισαχθεί από ένα άλλο άρθρωμα.')

Έξοδος:

$ python using_name.py
Αυτό το πρόγραμμα τρέχει από μόνο του.


$ python
>>> import using_name
Έχω εισαχθεί από ένα άλλο άρθρωμα.
>>>

Πώς λειτουργεί:

Για κάθε άρθρωμα ορίζεται το χαρακτηριστικό __name__, και εάν η τιμή του είναι '__main__', τότε συνεπάγεται ότι τρέχει ως αυτόνομο πρόγραμμα από το χρήστη, οπότε μπορούμε να ενεργήσουμε αντίστοιχα.

Κατασκευάζοντας τα δικά σας αρθρώματα

Η δημιουργία των δικών σας αρθρωμάτων είναι εύκολη - το έχετε κάνει ήδη - κι αυτό διότι κάθε πρόγραμμα στη Python είναι επίσης κι ένα άρθρωμα. Για το μόνο που πρέπει να είστε σίγουροι είναι να έχει την επέκταση .py. Το ακόλουθο παράδειγμα θα το κάνει πιο ξεκάθαρο.

Παράδειγμα:

#!/usr/bin/python
# Filename: mymodule.py

def sayhi():
    print('Hi, this is mymodule speaking.')

__version__ = '0.1'

# End of mymodule.py

Το παραπάνω είναι ένα δείγμα αρθρώματος. Όπως μπορείτε να δείτε δεν έχει καμία διαφορά από ένα συνηθισμένο πρόγραμμα σε Python. Kατόπιν θα δούμε πώς να χρησιμοποιούμε αυτό το άρθρωμα σε άλλα προγράμματά μας σε Python.

Θυμηθείτε ότι το άρθρωμα πρέπει να τοποθετείται στον ίδιο κατάλογο με το πρόγραμμα που το εισάγουμε, ή το άρθρωμα πρέπει να βρίσκεται σε έναν από τους καταλόγους που είναι στη λίστα του sys.path.

Παράδειγμα:

#!/usr/bin/python
# Filename: mymodule_demo.py

import mymodule

mymodule.sayhi()
print ('Version', mymodule.__version__)

Έξοδος:

$ python mymodule_demo.py
Hi, this is mymodule speaking.
Version 0.1

Παρατηρήστε ότι χρησιμοποιούμε τον ίδιο συμβολισμό με τελείες για να προσπελάσουμε μέλη του αρθρώματος. Η Python κάνει καλή επαναχρησιμοποίηση του ίδιου συμβολισμού για να του δώσει την χαρακτηριστική «Pythόνια» αίσθηση, έτσι ώστε να μην χρειάζεται να μαθαίνετε καινούργιους τρόπους για να κάνετε πράγματα.

Να μια εκδοχή όπου γίνεται χρήση της σύνταξης from..import:

#!/usr/bin/python
# Filename: mymodule_demo2.py

from mymodule import sayhi, __version__

sayhi()
print('Version', __version__)

Tο αποτέλεσμα του mymodule_demo2.py είναι το ίδιο με το αποτέλεσμα του mymodule_demo.py.

Παρατηρήστε ότι εάν ήταν ήδη δηλωμένο το όνομα της έκδοσης __version__ στο άρθρωμα το οποίο εισάγει το mymodule, θα γινόταν σύγκρουση. Αυτό είναι αρκετά πιθανό διότι είναι κοινή πρακτική για κάθε άρθρωμα να δηλώνει το νούμερο έκδοσής του χρησιμοποιώντας αυτό το όνομα. Γι' αυτό το λόγο συνιστάται να προτιμάτε την εντολή import ακόμα κι αν έτσι γίνεται το πρόγραμμά σας μεγαλύτερο.

Επίσης θα μπορούσατε να χρησιμοποιήσετε το:

from mymodule import *

Αυτό θα εισήγαγε όλα τα δημόσια ονόματα όπως το sayhi αλλά δε θα εισήγαγε το __version__ επειδή αρχίζει με διπλές κάτω παύλες.

Το Zen της Python

Μια από τις αρχές καθοδήγησης της Python είναι ότι «Οι ρητές εντολές είναι καλύτερες από αυτές που εξυπακούονται» (Explicit is better than Implicit). Τρέξτε import this για να μάθετε περισσότερα και δείτε αυτή τη συζήτηση που παραθέτει παραδείγματα για κάθε μια από τις αρχές της Python.

Η συνάρτηση dir

Μπορείτε να χρησιμοποιήσετε την ενσωματωμένη συνάρτηση dir για να δείτε μια λίστα με τα αναγνωριστικά που ορίζει ένα αντικείμενο. Για παράδειγμα, σε ένα άρθρωμα, τα αναγνωριστικά περιλαμβάνουν τις συναρτήσεις, τις κλάσεις και τις μεταβλητές που ορίζονται σε αυτό το άρθρωμα.

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

Παράδειγμα:

$ python

>>> import sys # παίρνει λίστα των χαρακτηριστικών, σε αυτή την περίπτωση, για το άρθρωμα sys

>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__',
'__package__', '__s
tderr__', '__stdin__', '__stdout__', '_clear_type_cache',
'_compact_freelists',
'_current_frames', '_getframe', 'api_version', 'argv',
'builtin_module_names', '
byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook',
'dllhandle'
, 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix',
'executable',
'exit', 'flags', 'float_info', 'getcheckinterval',
'getdefaultencoding', 'getfil
esystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount',
'getsizeof',
'gettrace', 'getwindowsversion', 'hexversion', 'intern', 'maxsize',
'maxunicode
', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache',
'platfor
m', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setprofile',
'setrecursionlimit
', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version',
'version_in
fo', 'warnoptions', 'winver']

>>> dir() # δίνει λίστα χαρακτηριστικών για το τρέχον άρθρωμα
['__builtins__', '__doc__', '__name__', '__package__', 'sys']

>>> a = 5 # δημιουργεί μια νέα μεταβλητή 'a'

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'a', 'sys']

>>> del a # διαγράφει ή αφαιρεί ένα όνομα

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'sys']

>>>

Πώς λειτουργεί:

Αρχικά βλέπουμε τη χρήση της συνάρτησης dir στο εισαχθέν άρθρωμα dir. Mπορούμε να δούμε την τεράστια λίστα των χαρακτηριστικών (attributes) που περιέχει.

Κατόπιν χρησιμοποιούμε την συνάρτηση dir χωρίς να της περάσουμε παραμέτρους. Από προεπιλογή, επιστρέφει τη λίστα του τρέχοντος αρθρώματος. Παρατηρήστε ότι η λίστα των εισαχθέντων αρθρωμάτων είναι επίσης μέρος αυτής της λίστας.

Για να δείτε τη dir σε δράση, ορίζουμε μια καινούργια μεταβλητή a και εκχωρούμε σ' αυτή μια τιμή, μετά τσεκάρουμε τη dir και παρατηρούμε ότι υπάρχει μια επιπρόσθετη τιμή στη λίστα του ίδιου ονόματος. Αφαιρούμε τη μεταβλητή/χαρακτηριστικό του τρέχοντος αρθρώματος χρησιμοποιώντας την εντολή del και η αλλαγή αντανακλάται πάλι στο αποτέλεσμα της συνάρτησης dir.

Μία παρατήρηση σχετικά με τη del: αυτή η εντολή χρησιμοποιείται για να διαγράψει μια μεταβλητή/όνομα και αφού η εντολή έχει τρέξει, σε αυτή την περίπτωση del a, δε μπορείτε πια να εισάγετε τη μεταβλητή a – είναι σαν να μην υπήρξε ποτέ.

Σημειώστε επίσης ότι η συνάρτηση dir() λειτουργεί σε οποιοδήποτε αντικείμενο. Για παράδειγμα, τρέξτε dir(print) για να μάθετε σχετικά με τα χαρακτηριστικά της συνάρτησης print, ή dir(str) για τα χαρακτηριστικά της κλάσης str.

Πακέτα (Packages)

Mέχρι τώρα, πρέπει να έχετε αρχίσει να παρατηρείτε την ιεραρχία με την οποία οργανώνονται τα προγράμματά σας. Οι μεταβλητές συνήθως πηγαίνουν μέσα στις συναρτήσεις. Οι συναρτήσεις και οι καθολικές μεταβλητές συνήθως πηγαίνουν μέσα στα αρθρώματα. Τι θα γινόταν όμως αν θέλατε να οργανώσετε τα αρθρώματα; Γι' αυτό έρχονται εδώ στο προσκήνιο τα πακέτα.

Τα πακέτα είναι απλώς κατάλογοι (ή αλλιώς φάκελοι) αρθρωμάτων με ένα ειδικό αρχείο __init__.py που δείχνει στην Python ότι αυτός ο κατάλογος είναι ειδικός διότι περιέχει αρθρώματα Python.

Ας πούμε ότι θέλετε να δημιουργήσετε ένα πακέτο που ονομάζεται «world» με υποπακέτα που ονομάζονται «asia», «africa», κ.τ.λ. και αυτά τα υποπακέτα με τη σειρά τους περιέχουν αρθρώματα όπως «india», «madagascar», κ.τ.λ.

Ένα παράδειγμα για το πώς θα δομούσατε τους φακέλους:

- <κάποιος κατάλογος που βρίσκεται στο sys.path>/
   - world/
       - __init__.py
       - asia/
           - __init__.py
           - india/
               - __init__.py
               - foo.py
       - africa/
           - __init__.py
           - madagascar/
               - __init__.py
               - bar.py

Tα πακέτα είναι μια ευκολία στην ιεραρχική οργάνωση των αρθρωμάτων. Θα δείτε πολλά τέτοια παραδείγματα στην πρότυπη βιβλιοθήκη.

Σύνοψη

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

Έχουμε δει πώς να χρησιμοποιούμε αυτά τα αρθρώματα και πώς να δημιουργούμε δικά μας αρθρώματα.

Κατόπιν θα μάθουμε μερικές ενδιαφέρουσες έννοιες που ονομάζονται δομές δεδομένων.