Στη συνέχεια παρουσιάζονται ορισμένα ενδιαφέροντα στοιχεία της Python. Αυτό που ακολουθεί δεν είναι tutorial, αν θέλετε κάτι τέτοιο μπορείτε να βρείτε εξαιρετικά κείμενα on-line.
Note
Δεν χρειάζεται να ξέρετε όσα λέγονται σε αυτήν την παράγραφο για να προγραμματίσετε σε Python. Η γλώσσα τα υλοποιεί για εσάς. Είναι όμως χρήσιμα για όσους προέρχονται από τον κόσμο της C/C++!
Στην Python οι μεταβλητές δεν δηλώνονται και μπορούν να περιέχουν διάφορους τύπους αντικειμένων κατά τη διάρκεια ζωής τους. Το πιο κάτω είναι απολύτως νόμιμο:
i = 23
i += 1
j = i
i = "hello"
Αυτό που συμβαίνει κατά την εκτέλεση των παραπάνω είναι:
Κάποια στιγμή (μη ντετερμινιστική για εμάς!) η Python θα ανακυκλώσει αυτόματα όσα αντικείμενα δεν συνδέονται με μεταβλητές (garbage collection).
Η Python προσφέρει τους κλασσικούς τύπους δεδομένων (int, string κλπ). Τα αντικείμενα των τύπων αυτών είναι immutable, δηλαδή δεν αλλάζουν τιμή (απλά, όπως φάνηκε στην προηγούμενη πράγραφο, δημιουργούνται νέα αντικείμενα).
Τα strings αποτελούν έναν πολύ εύχρηστο τύπο δεδομένων και μερικά χαρακτηριστικά τους δίνονται στη συνέχεια:
s = "abcd"
s2 = 'abcd' # ισοδύναμο με προηγούμενο
>>> s = "abcdefg"
>>> s[0]
'a'
>>> s[3]
'd'
>>> s[-1]
'g'
>>> s[1:4]
'bcd'
>>> s[:-1]
'abcdef'
>>> s[2:]
'cdefg'
[a|b|c|d|e|f|g]
^ ^ ^ ^ ^ ^ ^ ^
0 1 2 3 4 5 6 7
το s[1:4] είναι ίσο με "bcd"
>>> s = "abcdefg"
>>> s[3] = 'x'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "abcdefg"
>>> s = s[:3]+'x'+s[4:]
>>> print s
abcxefg
Τα αντικείμενα τύπου string διαθέτουν μια μεγάλη σειρά από χρήσιμες μεθόδους (http://docs.python.org/library/stdtypes.html#string-methods)
Το δυνατό σημείο της Python είναι τα σύνθετα αντικείμενα που παρέχει, τα οποία χρησιμοποιούμε για όλες τις δομές που θέλουμε να υλοποιήσουμε. Τα δύο βασικότερα είναι οι λίστες (lists) και τα λεξικά (dictionaries). Και οι δύο αυτοί τύποι αντικειμένων είναι mutable, τα αντικείμενά τους δηλαδή μπορούν να αλλάξουν περιεχόμενα.
Οι λίστες ανήκουν στην κατηγορία sequence και υλοποιούν μια διατεταγμένη συλλογή αντικειμένων. Τα αντικείμενα που περιέχονται στη λίστα μπορούν να είναι οποιουδήποτε τύπου (ακόμα και άλλες λίστες). Εφόσον μια λίστα είναι sequence, μπορούμε να πάρουμε μέρος της, όπως σε ένα string:
>>> li = [1,2,'abcd','ef']
>>> li[1]
2
>>> li[-1]
'ef'
>>> li[:-1]
[1, 2, 'abcd']
Μπορούμε ακόμα να προσπελάσουμε ένα προς ένα τα στοιχεία της λίστας με την επαναληπτική δομή for <item> in <sequence>:
>>> for itm in li:
... print itm
...
1
2
abcd
ef
Σκεφτείτε πώς συνδέονται μεταβλητές και αντικείμενα στην Python για να καταλάβετε το επόμενο:
>>> li = [1,2,'abcd','ef']
>>> lm = li
>>> lm[0] = 33
>>> lm
[33, 2, 'abcd', 'ef']
>>> li
[33, 2, 'abcd', 'ef']
Μπορούμε να προσθέσουμε δυναμικά νέα στοιχεία σε μια λίστα:
>>> li = [1,2,3,'ab','cd']
>>> li += [11,22]
>>> li
[1, 2, 3, 'ab', 'cd', 11, 22]
>>> li.append(33)
>>> li
[1, 2, 3, 'ab', 'cd', 11, 22, 33]
Note
Προσέξτε το όρισμα στη μέθοδο append στο προηγούμενο παράδειγμα. Δεν είναι λίστα. Αν ήταν, το αποτέλεσμα θα ήταν διαφορετικό!
>>> l = [1,2,3]
>>> l.append([5,6])
>>> l
[1, 2, 3, [5, 6]]
Αν θέλαμε να προσθέσουμε το 5 και το 6 στη λίστα, θα έπρεπε:
>>> l = [1,2,3]
>>> l += [5,6]
>>> l
[1, 2, 3, 5, 6]
Ή εναλλακτικά (η μέθοδος extend() ισοδυναμεί με το + σε λίστες):
>>> l = [1,2,3]
>>> l.extend([5,6])
>>> l
[1, 2, 3, 5, 6]
Note
Οι λίστες είναι δομές ειδικά βελτιστοποιημένες για ταξινόμηση (sorting). Εάν θέλουμε να ταξινομήσουμε πολύ γρήγορα μια σειρά στοιχείων, η χρήση λίστας είναι MUST!!!
Τα λεξικά (dictionaries) είναι τύπου mapping: ζεύγη αντιστοιχιών (κλειδιού-τιμής).
Οι πιο κοινές λειτουργίες σε λεξικά δίνονται στη συνέχεια.
>>> d = {}
>>> da = { 'mike': 32, 'nick': 43 }
>>> da['stef'] = 67
>>> da['mike'] = 'oops'
>>> da
{'nick': 43, 'mike': 'oops', 'stef': 67}
>>> if 'stef' in da:
... print 'found'
...
found
Note
Η απόπειρα προσπέλασης ενός κλειδιού που δεν υπάρχει, προκαλεί σφάλμα εκτέλεσης! Πρέπει πάντα να εκτελείτε τον έλεγχο ύπαρξης του κλειδιού!
>>> da = { 'mike': 32, 'nick': 43 }
>>> da['stef']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'stef'
>>> for k,v in da.iteritems():
... print k,v
...
nick 43
mike oops
stef 67
Note
Τα λεξικά είναι δομές ειδικά βελτιστοποιημένες για αναζήτηση (searching). Εάν θέλουμε να αναζητήσουμε πολύ γρήγορα ένα στοιχείο μέσα σε ένα μεγάλο σύνολο, η χρήση λεξικού είναι MUST!!!
Αν ξέρουμε ότι το ένα αρχείο κειμένου δεν είναι μεγάλο, μπορούμε να το διαβάσουμε “με τη μία” σε ένα string:
fp = open('test.txt','r')
text = fp.read()
print text
fp.close()
Μπορούμε όμως με μεγαλύτερη ασφάλεια να το διαβάσουμε γραμμή προς γραμμή:
fp = open('test.txt','r')
for line in fp:
print line
fp.close()
Στη δεύτερη περίπτωση:
Note
Duck Typing: “Αν περπατά σαν την πάπια και κάνει σαν την πάπια, τότε για μας είναι πάπια!”. Στις γλώσσες με δυναμικό τύπο δεδομένων, δεν είναι δυνατός ο έλεγχος εκ των προτέρων για το αν επιτρέπεται μια συγκεκριμένη λειτουργία σε ένα αντικείμενο. Αντί αυτού, η γλώσσα αρκείται στο ότι το αντικείμενο παρέχει τη συγκεκριμένη λειτουργία κατά τη στιγμή της εκτέλεσης, ανεξάρτητα από τον τύπο του. Αν π.χ. ένα αντικείμενο συμπεριφέρεται σαν λίστα ως προς την προσπέλαση των στοιχείων του, τότε μπορεί να χρησιμοποιηθεί σαν λίστα, ανεξάρτητα από το τι πραγματικά είναι.
Ας εφαρμόσουμε τα προηγούμενα σε ένα συνοπτικό παράδειγμα. Υποθέστε ότι θέλουμε να διαβάσουμε ένα αρχείο κειμένου και να βρούμε τη συχνότητα εμφάνισης κάθε λέξης. Αυτό γίνεται εύκολα με ένα λεξικό:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Sample app to calculate frequencies of words in a file
"""
# dictionary with words as keys
d = {}
fp = open('test.txt','r')
for line in fp:
l = line.lower().split() # convert to lowercase
# then split on whitespaces
for word in l: # l is a list of words
if word in d: # if word already in dict
d[word] += 1 # incr counter
else: # word not in dict
d[word] = 1 # 1st time
fp.close()
# print words and counts
for word,count in d.iteritems():
print word,count
Note
Πιθανές βελτιώσεις: Θα παρατηρήσατε βέβαια ότι ο προηγούμενος κώδικας δεν είναι ολοκληρωμένος. Π.χ. τα σημεία στίξης θεωρούνται μέρος της λέξης. Όλα αυτά όμως μπορούν να διορθωθούν εύκολα όπως θα δούμε αργότερα!
Μπορούμε να δώσουμε μια ‘διαδικτυακή χροιά’ στον προηγούμενο κώδικα. Με τη βιβλιοθήκη urllib μπορούμε να φέρουμε το περιεχόμενο μιας ιστοσελίδας σαν να διαβάζαμε ένα αρχείο! Χρειάζεται να αλλάξουμε μόνο μία γραμμή στον προηγούμενο κώδικα:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Sample app to calculate frequencies of words in a web page
"""
import urllib
# dictionary with words as keys
d = {}
fp = urllib.urlopen("http://di.ionio.gr/msc/")
for line in fp:
l = line.lower().split() # convert to lowercase
# then split on whitespaces
for word in l: # l is a list of words
if word in d: # if word already in dict
d[word] += 1 # incr counter
else: # word not in dict
d[word] = 1 # 1st time
fp.close()
# print words and counts
for word,count in d.iteritems():
print word,count
Για τους γνώστες της C/C++: θα ήταν λάθος να πιστεύουμε ότι το import είναι το αντίστοιχο του include της C/C++! Στην πραγματικότητα η βιβλιοθήκη που γίνεται imported ‘εκτελείται’ εκείνη τη στιγμή, δημιουργώντας τα αντικείμενα και τις συναρτήσεις της βιβλιοθήκης. Τα αντικείμενα αυτά μπορούμε να χρησιμοποιήσουμε στη συνέχεια στο πρόγραμμά μας.
Note
Αφαίρεση tags: Διαβάζοντας απευθείας από μια ιστοσελίδα έχουμε ένα νέο πρόβλημα: εκτός από τις λέξεις του κειμένου, παίρνουμε επίσης τα tags της HTML. Πώς θα αφαιρεθούν αυτά; (η συνέχεια στο επόμενο..)