7. Είσοδος και Έξοδος
*********************

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


7.1. Ομορφότερη Μορφοποίηση Εξόδου
==================================

So far we've encountered two ways of writing values: *expression
statements* and the "print()" function.  (A third way is using the
"write()" method of file objects; the standard output file can be
referenced as "sys.stdout". See the Library Reference for more
information on this.)

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

* Για να χρησιμοποιήσετε formatted string literals, ξεκινήστε μια
  συμβολοσειρά με "f" or "F" πριν από το αρχικό εισαγωγικό ή το τριπλό
  εισαγωγικό. Μέσα σε αυτήν την συμβολοσειρά, μπορείτε να γράψετε μια
  έκφραση Python μεταξύ χαρακτήρων "{" και "}" που μπορεί να
  αναφέρεται σε μεταβλητές ή κυριολεκτικές τιμές.

     >>> year = 2016
     >>> event = 'Referendum'
     >>> f'Results of the {year} {event}'
     'Results of the 2016 Referendum'

* The "str.format()" method of strings requires more manual effort.
  You'll still use "{" and "}" to mark where a variable will be
  substituted and can provide detailed formatting directives, but
  you'll also need to provide the information to be formatted.

     >>> yes_votes = 42_572_654
     >>> no_votes = 43_132_495
     >>> percentage = yes_votes / (yes_votes + no_votes)
     >>> '{:-9} YES votes  {:2.2%}'.format(yes_votes, percentage)
     ' 42572654 YES votes  49.67%'

* Τέλος, μπορείτε να κάνετε μόνοι σας όλο τον χειρισμό συμβολοσειράς
  χρησιμοποιώντας λειτουργίες slicing και συνένωσης συμβολοσειρών για
  να δημιουργήσετε οποιαδήποτε διάταξη μπορείτε να φανταστείτε.  Ο
  τύπος συμβολοσειράς έχει ορισμένες μεθόδους που εκτελούν χρήσιμες
  λειτουργίες για την προσθήκη συμβολοσειρών σε ένα δεδομένο πλάτος
  στήλης.

Όταν δεν χρειάζεστε φανταχτερή έξοδο, άλλα θέλετε απλώς μια γρήγορη
εμφάνιση ορισμένων μεταβλητών για σκοπούς εντοπισμού σφαλμάτων,
μπορείτε να μετατρέψετε οποιαδήποτε τιμή σε μια συμβολοσειρά με τις
συναρτήσεις "repr()" ή "str()".

Η συνάρτηση "str()" προορίζεται να επιστρέφει αναπαραστάσεις τιμών που
είναι αρκετά αναγνώσιμες από τον άνθρωπο, ενώ το "repr()" προορίζεται
για τη δημιουργία αναπαραστάσεων που μπορούν να διαβαστούν από τον
διερμηνέα (ή θα επιβάλουν ένα "SyntaxError" αν δεν υπάρχει ισοδύναμη
σύνταξη).  Για αντικείμενα που δεν έχουν συγκεκριμένη αναπαράσταση για
ανθρώπινη κατανάλωση, η "str()" θα επιστρέψει την ίδια τιμή με το
"repr()".  Πολλές τιμές, όπως αριθμοί ή δομές όπως λίστες και λεξικά,
έχουν την ίδια αναπαράσταση χρησιμοποιώντας οποιαδήποτε συνάρτηση. Τα
strings, συγκεκριμένα, έχουν δύο διακριτές παραστάσεις.

Μερικά παραδείγματα:

   >>> s = 'Hello, world.'
   >>> str(s)
   'Hello, world.'
   >>> repr(s)
   "'Hello, world.'"
   >>> str(1/7)
   '0.14285714285714285'
   >>> x = 10 * 3.25
   >>> y = 200 * 200
   >>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
   >>> print(s)
   The value of x is 32.5, and y is 40000...
   >>> # The repr() of a string adds string quotes and backslashes:
   ... hello = 'hello, world\n'
   >>> hellos = repr(hello)
   >>> print(hellos)
   'hello, world\n'
   >>> # The argument to repr() may be any Python object:
   ... repr((x, y, ('spam', 'eggs')))
   "(32.5, 40000, ('spam', 'eggs'))"

Το module "string" περιέχει μια κλάση "Template" που προσφέρει έναν
ακόμη τρόπο αντικατάστασης τιμών σε συμβολοσειρές, χρησιμοποιώντας
placeholders όπως "$x" και αντικαθιστώντας τις με τιμές από ένα
λεξικό, αλλά προσφέρει πολύ λιγότερο έλεγχο της μορφοποίησης.


7.1.1. Μορφοποιημένα String Literals
------------------------------------

Τα Formatted string literals (ονομάζονται επίσης f-strings για
συντομία) σας επιτρέπουν να συμπεριλάβετε την τιμή των εκφράσεων
Python μέσα σε μια συμβολοσειρά, θέτοντας πρόθεμα στη συμβολοσειρά με
"f" ή "F" και γράφοντας εκφράσεις ως "{expression}".

Ένας προαιρετικός αναθέτης (specifier) μορφής μπορεί να ακολουθεί την
έκφραση. Αυτό επιτρέπει μεγαλύτερο έλεγχο στον τρόπο μορφοποίησης της
τιμής. Το παρακάτω παράδειγμα στρογγυλοποιεί το pi σε τρία ψηφία μετά
το δεκαδικό:

   >>> import math
   >>> print(f'The value of pi is approximately {math.pi:.3f}.')
   The value of pi is approximately 3.142.

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

   >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
   >>> for name, phone in table.items():
   ...     print(f'{name:10} ==> {phone:10d}')
   ...
   Sjoerd     ==>       4127
   Jack       ==>       4098
   Dcab       ==>       7678

Μπορούν να χρησιμοποιηθούν άλλοι τροποποιητές για την μετατροπή της
τιμής πριν τη μορφοποίηση της. Το "'!a'" ισχύει για "ascii()", το
"'!s'" ισχύει για "str()", και το "'!r'" ισχύει για "repr()":

   >>> animals = 'eels'
   >>> print(f'My hovercraft is full of {animals}.')
   My hovercraft is full of eels.
   >>> print(f'My hovercraft is full of {animals!r}.')
   My hovercraft is full of 'eels'.

Ο αναθέτης (specifier) "=" μπορεί να χρησιμοποιηθεί για να επεκτείνει
μια έκφραση στο κείμενο της έκφρασης, ένα σύμβολο ίσο, και μετά την
αναπαράσταση της αξιολογούμενης έκφρασης:

>>> bugs = 'roaches'
>>> count = 13
>>> area = 'living room'
>>> print(f'Debugging {bugs=} {count=} {area=}')
Debugging bugs='roaches' count=13 area='living room'

Δείτε το self-documenting expressions για περισσότερες πληροφορίες
σχετικά με τον αναθέτη (specifier) "=". Για αναφορά σε αυτές τις
προδιαγραφές μορφής, ανατρέξτε στον οδηγό αναφοράς για το Format
Specification Mini-Language.


7.1.2. Η μέθοδος String format()
--------------------------------

Η βασική χρήση της μεθόδου "str.format()" μοιάζει με αυτό:

   >>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
   We are the knights who say "Ni!"

Οι αγκύλες και οι χαρακτήρες μέσα σε αυτές (που ονομάζονται πεδία
μορφής) αντικαθίστανται με τα αντικείμενα που μεταβιβάζονται στη
μέθοδο "str.format()".  Ένας αριθμός στις αγκύλες μπορεί να
χρησιμοποιηθεί για να αναφέρεται στη θέση του αντικειμένου που
μεταβιβάζεται στη μέθοδο "str.format()".

   >>> print('{0} and {1}'.format('spam', 'eggs'))
   spam and eggs
   >>> print('{1} and {0}'.format('spam', 'eggs'))
   eggs and spam

Εάν χρησιμοποιούνται keyword ορίσματα στη μέθοδο "str.format()", οι
τιμές τους αναφέρονται χρησιμοποιώντας το όνομα του ορίσματος.

   >>> print('This {food} is {adjective}.'.format(
   ...       food='spam', adjective='absolutely horrible'))
   This spam is absolutely horrible.

Τα ορίσματα θέσης και λέξης-κλειδιού μπορούν να συνδυαστούν αυθαίρετα:

   >>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
   ...                                                    other='Georg'))
   The story of Bill, Manfred, and Georg.

Εάν έχετε μια συμβολοσειρά πολύ μακριάς μορφής που δεν θέλετε να
χωρίσετε, θα ήταν ωραίο να αναφέρετε τις μεταβλητές που θα
μορφοποιηθούν με βάση το όνομα αντί για τη θέση.  Αυτό μπορεί να γίνει
απλά περνώντας το λεξικό και χρησιμοποιώντας αγκύλες "'[]'" για
πρόσβαση στα κλειδιά

   >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
   >>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
   ...       'Dcab: {0[Dcab]:d}'.format(table))
   Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Αυτό θα μπορούσε επίσης να γίνει περνώντας το λεξικό "table" ως
ορίσματα λέξεων-κλειδιών με την σημείωση "**".

   >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
   >>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
   Jack: 4098; Sjoerd: 4127; Dcab: 8637678

This is particularly useful in combination with the built-in function
"vars()", which returns a dictionary containing all local variables.

Για παράδειγμα, οι ακόλουθες γραμμές παράγουν ένα τακτοποιημένο σύνολο
στηλών που δίνουν ακέραιους αριθμούς και τα τετράγωνα και τους κύβους
τους:

   >>> for x in range(1, 11):
   ...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
   ...
    1   1    1
    2   4    8
    3   9   27
    4  16   64
    5  25  125
    6  36  216
    7  49  343
    8  64  512
    9  81  729
   10 100 1000

Για μια πλήρη επισκόπηση της μορφοποίησης συμβολοσειρών με
"str.format()", δείτε Format String Syntax.


7.1.3. Χειροκίνητη Μορφοποίηση Συμβολοσειρών
--------------------------------------------

Ακολουθεί ο ίδιος πίνακας τετραγώνων και κύβων, μορφοποιημένος
χειροκίνητα:

   >>> for x in range(1, 11):
   ...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
   ...     # Note use of 'end' on previous line
   ...     print(repr(x*x*x).rjust(4))
   ...
    1   1    1
    2   4    8
    3   9   27
    4  16   64
    5  25  125
    6  36  216
    7  49  343
    8  64  512
    9  81  729
   10 100 1000

(Σημειώστε ότι το ένα κενό μεταξύ κάθε στήλης προστέθηκε με τον τρόπο
που λειτουργεί το "print()": προσθέτει πάντα κενά μεταξύ των ορισμάτων
του.)

Η μέθοδος "str.rjust()" των αντικειμένων συμβολοσειράς τοποθετεί δεξιά
μια συμβολοσειρά σε ένα πεδίο δεδομένου πλάτους συμπληρώνοντας την με
κενά στα αριστερά. Υπάρχουν παρόμοιες μέθοδοι "str.ljust()" και
"str.center()". Αυτές οι μέθοδοι δεν γράφουν τίποτα, απλώς επιστρέφουν
μια συμβολοσειρά. Εάν η συμβολοσειρά εισόδου είναι πολύ μεγάλη, δεν
την περικόπτουν, αλλά την επιστρέφουν αμετάβλητη· αυτό θα μπερδέψει τη
διάταξη της στήλης σας, αλλά αυτό είναι συνήθως καλύτερο από την
εναλλακτική, που θα ήταν ψέματα για μια τιμή. (Αν θέλετε πραγματικά
περικοπή, μπορείτε πάντα να προσθέσετε μια λειτουργία slice, όπως στο
"x.ljust(n)[:n]".)

Υπάρχει μια άλλη μέθοδος, η "str.zfill()", η οποία συμπληρώνει μια
αριθμητική συμβολοσειρά στα αριστερά με μηδενικά.  Καταλαβαίνει τα
σύμβολα συν και πλην:

   >>> '12'.zfill(5)
   '00012'
   >>> '-3.14'.zfill(7)
   '-003.14'
   >>> '3.14159265359'.zfill(5)
   '3.14159265359'


7.1.4. Παλιά μορφοποίηση συμβολοσειράς
--------------------------------------

The % operator (modulo) can also be used for string formatting. Given
"'string' % values", instances of "%" in "string" are replaced with
zero or more elements of "values". This operation is commonly known as
string interpolation. For example:

   >>> import math
   >>> print('The value of pi is approximately %5.3f.' % math.pi)
   The value of pi is approximately 3.142.

Περισσότερες πληροφορίες μπορείτε να βρείτε στην ενότητα printf-style
String Formatting.


7.2. Ανάγνωση και Εγγραφή Αρχείων
=================================

Η "open()" επιστρέφει ένα *file object*, και χρησιμοποιείται πιο συχνά
με δύο ορίσματα θέσης και ένα όρισμα λέξης-κλειδιού: "open(filename,
mode, encoding=None)"

   >>> f = open('workfile', 'w', encoding="utf-8")

Το πρώτο όρισμα είναι μια συμβολοσειρά που περιέχει το όνομα αρχείου.
Το δεύτερο όρισμα είναι μια άλλη συμβολοσειρά που περιέχει μερικούς
χαρακτήρες που περιγράφουν τον τρόπο με τον οποίο θα χρησιμοποιηθεί το
αρχείο. Η *mode* μπορεί να είναι "'r'" όταν το αρχείο θα είναι μόνο
για διάβασμα, "'w'" μόνο για εγγραφή (ένα υπάρχον αρχείο με το ίδιο
όνομα θα διαγραφεί) και το "'a'" ανοίγει το αρχείο για προσάρτηση·
οποιαδήποτε δεδομένα γράφονται στο αρχείο και προστίθενται αυτόματα
στο τέλος. Το "'r+'" ανοίγει το αρχείο τόσο για ανάγνωση όσο και για
γραφή. Το όρισμα *mode* είναι προαιρετικό· το "'r'" θα θεωρείται εάν
παραληφθεί.

Κανονικά, τα αρχεία ανοίγουν σε *text mode*, που σημαίνει ότι
διαβάζετε και γράφετε συμβολοσειρές από και προς το αρχείο, οι οποίες
κωδικοποιούνται σε μια συγκεκριμένη *κωδικοποίηση*. Εάν δεν έχει
καθοριστεί η *κωδικοποιήση*, η προεπιλογή είναι εξαρτώμενη από την
πλατφόρμα (δείτε "open()"). Επειδή το UTF-8 είναι το σύγχρονο de-facto
standard, "encoding="utf-8"" συνίσταται εκτός εάν γνωρίζετε ότι πρέπει
να χρησιμοποιήσετε διαφορετική κωδικοποίηση. Η προσθήκη ενός "'b'" στη
λειτουργία ανοίγει το αρχείο σε *binary mode*. Τα δεδομένα δυαδικής
λειτουργίας διαβάζονται και γράφονται ως αντικείμενα "bytes". Δεν
μπορείτε να καθορίσετε *κωδικοποίηση* όταν ανοίγετε αρχείο σε δυαδική
λειτουργία.

Στη λειτουργία κειμένου, η προεπιλογή (default) κατά την ανάγνωση
είναι να μετατρέψετε τις καταλήξεις γραμμών για συγκεκριμένη πλατφόρμα
("\n" στο Unix, "\r\n" στα Windows) σε μόνο "\n".  Όταν γράφετε σε
λειτουργία κειμένου, η προεπιλογή είναι να μετατρέπονται οι εμφανίσεις
"\n" σε καταλήξεις γραμμών για συγκεκριμένη πλατφόρμα. Αυτή η
παρασκηνιακή τροποποίηση στα δεδομένα αρχείων είναι καλή για αρχεία
κειμένου, αλλά θα καταστρέψει δυαδικά δεδομένα όπως αυτό σε αρχεία
"JPEG" ή "EXE".  Να είστε πολύ προσεκτικοί να χρησιμοποιείτε τη
δυαδική λειτουργία όταν διαβάζετε και γράφετε τέτοια αρχεία.

Είναι καλή πρακτική να χρησιμοποιείτε το keyword "with" όταν
ασχολούμαστε με αντικείμενα αρχείου.  Το πλεονέκτημα είναι ότι το
αρχείο κλείνει σωστά μετά την ολοκλήρωση της εκτέλεσής του, ακόμα κι
αν κάποια στιγμή προκύψει εξαίρεση.  Χρησιμοποιώντας το "with" είναι
επίσης πολύ πιο σύντομο από την σύνταξη ισοδύναμου "try"-"finally"
blocks:

   >>> with open('workfile', encoding="utf-8") as f:
   ...     read_data = f.read()

   >>> # We can check that the file has been automatically closed.
   >>> f.closed
   True

Εάν δεν χρησιμοποιείτε τη keyword "with", τότε θα πρέπει να καλείτε τη
"f.close()" για να κλείσετε το αρχείο και να ελευθερώσετε αμέσως τυχόν
πόρους συστήματος που χρησιμοποιούνται από αυτό.

Προειδοποίηση:

  Η κλήση του "f.write()" χωρίς τη χρήση της keyword "with" ή η κλήση
  του "f.close()" **μπορεί** να οδηγήσει στα ορίσματα του "f.write()"
  να μην εγγραφεί πλήρως στο δίσκο, ακόμα και αν το πρόγραμμα εξέλθει
  με επιτυχία.

Μετά το κλείσιμο ενός αντικειμένου αρχείου, είτε μια δήλωση "with"
είτε καλώντας "f.close()", οι προσπάθειες χρήσης του αντικειμένου
αρχείου θα αποτύχουν αυτόματα.

   >>> f.close()
   >>> f.read()
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   ValueError: I/O operation on closed file.


7.2.1. Μέθοδοι Αντικειμένων Αρχείων
-----------------------------------

Τα υπόλοιπα παραδείγματα σε αυτήν την ενότητα θα υποθέσουν ότι ένα
αντικείμενο αρχείου που ονομάζεται "f" έχει ήδη δημιουργηθεί.

Για να διαβάσετε τα περιεχόμενα ενός αρχείου, καλέστε το
"f.read(size)", το οποίο διαβάζει κάποια ποσότητα δεδομένων και την
επιστρέφει ως συμβολοσειρά (σε λειτουργία κειμένου) ή ως αντικείμενο
bytes (σε δυαδική λειτουργία). Το *size* είναι προαιρετικό αριθμητικό
όρισμα.  Όταν το *size* παραλείπεται ή είναι αρνητικό, ολόκληρο το
περιεχόμενο του αρχείου θα διαβαστεί και θα επιστραφεί∙ είναι δικό σας
πρόβλημα εάν το αρχείο είναι διπλάσιο από τη μνήμη του υπολογιστή σας.
Διαφορετικά, διαβάζονται και επιστρέφονται το πολύ *size* χαρακτήρες
(σε λειτουργία κειμένου) ή byte *size* (σε δυαδική λειτουργία). Εάν
έχει φτάσει το τέλος του αρχείου, το "f.read()" θα επιστρέψει μια κενή
συμβολοσειρά ("''").

   >>> f.read()
   'This is the entire file.\n'
   >>> f.read()
   ''

Το "f.readline()" διαβάζει μία γραμμή από το αρχείο· ένας χαρακτήρας
νέας γραμμής ("\n") παραμένει στο τέλος της συμβολοσειράς, και
παραλείπεται μόνο στην τελευταία γραμμή του αρχείου εάν το αρχείο δεν
τελειώνει σε μια νέα γραμμή.  Αυτό καθιστά την τιμή επιστροφής σαφή·
εάν το "f.readline()" επιστρέφει μια κενή συμβολοσειρά, έχει φτάσει
στο τέλος του αρχείου, ενώ μια κενή γραμμή αντιπροσωπεύεται από
"'\n'", μια συμβολοσειρά που περιέχει μόνο μία νέα γραμμή.

   >>> f.readline()
   'This is the first line of the file.\n'
   >>> f.readline()
   'Second line of the file\n'
   >>> f.readline()
   ''

Για την ανάγνωση γραμμών από ένα αρχείο, μπορείτε να κάνετε loop πάνω
από το αντικείμενο του αρχείου. Αυτό είναι αποδοτικό στη μνήμη,
γρήγορο και οδηγεί σε απλό κώδικα:

   >>> for line in f:
   ...     print(line, end='')
   ...
   This is the first line of the file.
   Second line of the file

Εάν θέλετε να διαβάσετε όλες τις γραμμές ενός αρχείου σε μια λίστα,
μπορείτε επίσης να χρησιμοποιήσετε το "list(f)" ή "f.readlines()".

Το "f.write(string)" γράφει τα περιεχόμενα του *string* στο αρχείο,
επιστρέφοντας τον αριθμό των χαρακτήρων που γράφτηκαν.

   >>> f.write('This is a test\n')
   15

Άλλοι τύποι αντικειμένων πρέπει να μετατραπούν -- είτε σε μια
συμβολοσειρά (σε λειτουργία κειμένου) ή σε ένα αντικείμενο bytes (σε
δυαδική λειτουργία) -- πριν τα γράψετε:

   >>> value = ('the answer', 42)
   >>> s = str(value)  # convert the tuple to string
   >>> f.write(s)
   18

Το "f.tell()" επιστρέφει έναν ακέραιο που δίνει την τρέχουσα θέση του
αντικειμένου αρχείου στο αρχείο που αντιπροσωπεύεται ως αριθμό byte
από την αρχή του αρχείου όταν βρίσκεται σε δυαδική λειτουργία και έναν
αδιαφανή αριθμό όταν βρίσκεται σε λειτουργία κειμένου.

Για να αλλάξετε τη θέση του αντικειμένου, χρησιμοποιήστε το
"f.seek(offset, whence)".  Η θέση υπολογίζεται από την προσθήκη
*offset* σε ένα σημείο αναφοράς· το σημείο αναφοράς επιλέγεται από το
όρισμα *whence*.  Μια 0 τιμή *whence* μετρά από την αρχή του αρχείο το
1 χρησιμοποιεί την τρέχουσα θέση αρχείου και το 2 χρησιμοποιεί το
τέλος του αρχείου ως σημείο αναφοράς.  Το *whence* μπορεί να
παραληφθεί και να οριστεί από προεπιλογή 0, χρησιμοποιώντας την αρχή
του αρχείου ως σημείο αναφοράς.

   >>> f = open('workfile', 'rb+')
   >>> f.write(b'0123456789abcdef')
   16
   >>> f.seek(5)      # Go to the 6th byte in the file
   5
   >>> f.read(1)
   b'5'
   >>> f.seek(-3, 2)  # Go to the 3rd byte before the end
   13
   >>> f.read(1)
   b'd'

Σε αρχεία κειμένου (αυτά που ανοίγουν χωρίς "b" στη λειτουργία
string), επιτρέπονται μόνο αναζητήσεις σε σχέση με την αρχή του
αρχείου (η εξαίρεση είναι η αναζήτηση μέχρι το ίδιο το αρχείο που
τελειώνει με "seek(0, 2)") και οι μόνες έγκυρες τιμές *offset* είναι
αυτές που επιστρέφονται από το "f.tell()", ή μηδέν. Οποιαδήποτε άλλη
τιμή *offset* παράγει  απροσδιόριστη συμπεριφορά.

File objects have some additional methods, such as "isatty()" and
"truncate()" which are less frequently used; consult the Library
Reference for a complete guide to file objects.


7.2.2. Αποθήκευση δομημένων δεδομένων με "json"
-----------------------------------------------

Strings can easily be written to and read from a file.  Numbers take a
bit more effort, since the "read()" method only returns strings, which
will have to be passed to a function like "int()", which takes a
string like "'123'" and returns its numeric value 123.  When you want
to save more complex data types like nested lists and dictionaries,
parsing and serializing by hand becomes complicated.

Αντί να χρειάζεται οι χρήστες να γράφουν και να διορθώνουν συνεχώς
κώδικα για να αποθηκεύουν πολύπλοκους τύπους δεδομένων σε αρχεία, η
Python σας επιτρέπει να χρησιμοποιείτε τη δημοφιλή μορφή ανταλλαγής
δεδομένων που ονομάζεται JSON (JavaScript Object Notation).  Το
standard module που ονομάζεται "json" μπορεί να λάβει ιεραρχίες
δεδομένων Python, και να τις μετατρέψει σε αναπαραστάσεις
συμβολοσειρών· αυτή η διαδικασία ονομάζεται *serializing*..  Η
ανασύνθεση των δεδομένων από την αναπαράσταση συμβολοσειράς ονομάζεται
*deserializing*.  Μεταξύ σειριοποίησης και αποσειριοποίησης, η
συμβολοσειρά που αντιπροσωπεύει το αντικείμενο μπορεί να έχει
αποθηκευτεί σε ένα αρχείο ή δεδομένα ή να έχει σταλεί μέσω μιας
σύνδεσης δικτύου σε κάποιο απομακρυσμένο μηχάνημα.

Σημείωση:

  Η μορφή JSON χρησιμοποιείται συνήθως από σύγχρονες εφαρμογές για να
  επιτρέπει την ανταλλαγή δεδομένων.  Πολλοί προγραμματιστές είναι ήδη
  εξοικειωμένοι με αυτήν, γεγονός που την καθιστά καλή επιλογή για
  διαλειτουργικότητα.

Εάν έχετε ένα αντικείμενο "x", μπορείτε να δείτε την αναπαράσταση
συμβολοσειράς JSON με μια απλή γραμμή κώδικα:

   >>> import json
   >>> x = [1, 'simple', 'list']
   >>> json.dumps(x)
   '[1, "simple", "list"]'

Μια άλλη παραλλαγή της συνάρτησης "dumps()", που ονομάζεται "dump()",
απλώς σειριοποιεί το αντικείμενο σε ένα *text file*.  Έτσι, εάν το "f"
είναι ένα αντικείμενο *text file* που ανοίγει για εγγραφή, μπορούμε να
κάνουμε αυτό:

   json.dump(x, f)

Για να αποκωδικοποιήσετε ξανά το αντικείμενο, εάν το "f" είναι ένα
αντικείμενο *binary file* ή *text file* που έχει ανοίξει για ανάγνωση:

   x = json.load(f)

Σημείωση:

  Τα αρχεία JSON πρέπει να είναι κωδικοποιημένα σε UTF-8.
  Χρησιμοποιήστε το "encoding="utf-8"" όταν ανοίγετε το αρχείο JSON ως
  *text file* τόσο για ανάγνωση όσο και για εγγραφή.

Αυτή η απλή τεχνική σειριοποίησης μπορεί να χειριστεί λίστες και
λεξικά, άλλα η σειριοποίηση αυθαίρετων στιγμιοτύπων κλάσεων σε JSON
απαιτεί λίγη επιπλέον προσπάθεια. Η αναφορά για το module "json"
περιέχει μια εξήγηση για αυτό.

Δείτε επίσης:

  "pickle" - το pickle module

  Σε αντίθεση με το JSON, το *pickle* είναι ένα πρωτόκολλο που
  επιτρέπει τη σειριοποίηση αυθαίρετα πολύπλοκων αντικειμένων Python.
  Ως εκ τούτου, είναι συγκεκριμένο για την Python και δεν μπορεί να
  χρησιμοποιηθεί για επικοινωνία με εφαρμογές γραμμένες σε άλλες
  γλώσσες.  Είναι επίσης ανασφαλές από προεπιλογή: η αποσειριοποίηση
  pickle δεδομένων που προέρχονται από μια μη αξιόπιστη πηγή μπορεί να
  εκτελέσει αυθαίρετο κώδικα, εάν τα δεδομένα έχουν δημιουργηθεί από
  έναν έμπειρο εισβολέα.
