598 lines
12 KiB
Plaintext
598 lines
12 KiB
Plaintext
.. default-role:: literal
|
|
.. default-domain: python
|
|
|
|
Typage, types de base
|
|
======================
|
|
|
|
python est un langage dynamiquement typé. qu'est-ce que cela signifie ?
|
|
|
|
- pas de déclaration des types (attention différent de l'inférence de types): les variables n'ont pas
|
|
de type fixé
|
|
- pas de déclaration des variables (une variable est créée au moyen de la première
|
|
affectation)
|
|
|
|
.. todo:: créer une variable
|
|
|
|
>>> a = 3
|
|
>>> a
|
|
3
|
|
|
|
.. todo::
|
|
|
|
- ouvrir l'interpréteur python
|
|
- dans la console créer un objet de type integer, float, string, liste, dictionnaire
|
|
- vérifier les types à l'aide de la fonction
|
|
- vérifier que en python tout est objet
|
|
- type de base et types conteneurs
|
|
- types mutables et types immutables
|
|
|
|
>>> a = 2
|
|
>>> b = 3
|
|
>>> b = 5
|
|
>>> a
|
|
2
|
|
>>> b
|
|
5
|
|
|
|
>>> l = ['a', 'b', 'c', 'd']
|
|
>>> p = [l, 'e']
|
|
>>> p
|
|
[['a', 'b', 'c', 'd'], 'e']
|
|
>>> l = ['i', 'j']
|
|
>>> p
|
|
[['a', 'b', 'c', 'd'], 'e']
|
|
>>> l
|
|
['i', 'j']
|
|
|
|
.. todo:: jouer avec les types
|
|
|
|
- l'interpréteur python comme calculette, les optérations numériques
|
|
|
|
>>> x = 1
|
|
>>> y =2
|
|
>>> x > y
|
|
False
|
|
>>> x == y
|
|
False
|
|
>>> x != y
|
|
True
|
|
|
|
- l'interpréteur pour manipuler les strings
|
|
|
|
>>> s = "bla bla"
|
|
'bla bla'
|
|
>>> s = 'bla bla'
|
|
'bla bla'
|
|
>>> s = " 'bli bli' "
|
|
>>> s
|
|
" 'bli bli' "
|
|
>>> s = """ sdfsdf "bla bla" sdfsdf"""
|
|
>>> s
|
|
' sdfsdf "bla bla" sdfsdf'
|
|
>>>
|
|
>>> s = "bla bla"
|
|
>>> m = "hu hu"
|
|
>>> s + m
|
|
'bla blahu hu'
|
|
>>> m * 3
|
|
'hu huhu huhu hu'
|
|
>>>
|
|
>>> len(m)
|
|
5
|
|
>>>
|
|
>>> m[3]
|
|
'h'
|
|
>>> m[3:5]
|
|
'hu'
|
|
>>>
|
|
|
|
>>> s = "ssdfsdf {0} sdfsdfsdf {1}".format("blah", "blih")
|
|
|
|
>>> s= 'a'
|
|
>>> dir(s)
|
|
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
|
|
>>> t = "abc"
|
|
>>> t.startswith("a")
|
|
True
|
|
>>> l = ['a', 'b', 'c']
|
|
>>> "-".join(l)
|
|
'a-b-c'
|
|
>>>
|
|
|
|
.. todo:: lower(), upper(), strip(), title()
|
|
|
|
.. todo: recherche et remplacement dans une string
|
|
|
|
index(), find(), replace()
|
|
|
|
- le module :mod:`regexp`
|
|
|
|
.. module:: regexp
|
|
:synopsis: expression régulières
|
|
|
|
>>> import re
|
|
>>> s = "sdf dfdfdf blah bla df"
|
|
>>> re.findall(r'\w*', s)
|
|
['sdf', '', 'dfdfdf', '', 'blah', '', 'bla', '', 'df', '']
|
|
>>> re.findall(r'df*', s)
|
|
['df', 'df', 'df', 'df', 'df']
|
|
>>>
|
|
|
|
- enlever les accents
|
|
|
|
>>> import unicodedata
|
|
>>> s = u"un été même pas chaud"
|
|
>>> import unicodedata as U
|
|
>>> s2 = ''.join(U.normalize('NFD', x)[0] for x in s)
|
|
>>> s2
|
|
u'un ete meme pas chaud'
|
|
>>>
|
|
|
|
- enlever la ponctuation
|
|
|
|
>>> import re
|
|
>>> import string
|
|
>>> rgx = re.compile('[%s]' % string.punctuation)
|
|
>>> string.punctuation
|
|
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
|
|
|
|
- l'encodage (unicode):
|
|
|
|
>>> u = u"éèà bla"
|
|
>>> u
|
|
u'\xe9\xe8\xe0 bla'
|
|
>>> u.encode("utf-8")
|
|
'\xc3\xa9\xc3\xa8\xc3\xa0 bla'
|
|
>>> print u.encode("utf-8")
|
|
éèà bla
|
|
>>>
|
|
|
|
manips importantes de traitement unicode (si on n'est pas en python 3)
|
|
|
|
>>> u = u"ésdsfè"
|
|
>>> u
|
|
u'\xe9sdsf\xe8'
|
|
>>> print u
|
|
ésdsfè
|
|
>>> str(u)
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in <module>
|
|
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0:
|
|
ordinal not in range(128)
|
|
>>> u.decode("utf-8")
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in <module>
|
|
File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
|
|
return codecs.utf_8_decode(input, errors, True)
|
|
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0:
|
|
ordinal not in range(128)
|
|
>>> u.encode("utf-8")
|
|
'\xc3\xa9sdsf\xc3\xa8'
|
|
>>> s = u.encode("utf-8")
|
|
>>> type(s)
|
|
<type 'str'>
|
|
>>>
|
|
|
|
# il faut utiliser .encode(), et pas .decode()...
|
|
|
|
if type(s) == unicode #types.UnicodeType:
|
|
bla bla
|
|
|
|
if type(s) == str:
|
|
rien à faire
|
|
|
|
- tuples, listes, dictionnaires
|
|
|
|
>>> t = (1,2,3)
|
|
>>> l = [1,2,3]
|
|
>>> d = {'a': 2, 'b':3, 'c':4}
|
|
>>>
|
|
>>> l = ['e','p','q','t']
|
|
>>> l.pop()
|
|
't'
|
|
>>> l
|
|
['e', 'p', 'q']
|
|
>>> l
|
|
['e', 'p', 'q']
|
|
>>> l.pop(1)
|
|
'p'
|
|
>>> l
|
|
['e', 'q']
|
|
>>>
|
|
|
|
|
|
|
|
.. important:: utiliser get plutôt que l'accès par items lorsque l'on n'est pas sûr
|
|
|
|
::
|
|
|
|
>>> d = {}
|
|
>>> d.get('toto')
|
|
>>> d['toto'] ='titi'
|
|
>>> d.get('toto')
|
|
'titi'
|
|
>>> print d.get('toto')
|
|
titi
|
|
>>> print d.get('to')
|
|
None
|
|
>>> d['tot']
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in <module>
|
|
KeyError: 'tot'
|
|
>>>
|
|
KeyboardInterrupt
|
|
>>>
|
|
|
|
>>> x=dict(a=23,b=45,c=67,d=89)
|
|
>>> x
|
|
{'a': 23, 'c': 67, 'b': 45, 'd': 89}
|
|
>>> y=dict.fromkeys(range(4), 'ho')
|
|
>>> y
|
|
{0: 'ho', 1: 'ho', 2: 'ho', 3: 'ho'}
|
|
|
|
# and a new method to fetch-and-remove an item, by key:
|
|
|
|
>>> x.pop('c')
|
|
67
|
|
>>> x
|
|
{'a': 23, 'b': 45, 'd': 89}
|
|
>>> x.pop('z')
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in ?
|
|
KeyError: 'z'
|
|
>>> x.pop('z', 55)
|
|
55
|
|
|
|
>>> for x in enumerate('ciao'): print x
|
|
...
|
|
(0, 'c')
|
|
(1, 'i')
|
|
(2, 'a')
|
|
(3, 'o')
|
|
>>>
|
|
|
|
|
|
.. module:: collections
|
|
:synopsis: autres types de données
|
|
|
|
- le module :mod:`collections` :
|
|
|
|
- `OrderedDict`, `defaultdict`
|
|
|
|
remarques sur les tuples
|
|
|
|
>>> 1,
|
|
(1,)
|
|
>>> (1,)
|
|
(1,)
|
|
>>> (1)
|
|
1
|
|
>>> ()
|
|
()
|
|
>>> tuple()
|
|
()
|
|
>>> value = 1,
|
|
>>> value
|
|
(1,)
|
|
|
|
.. todo:: addition de listes, append, tranches, tri de listes
|
|
|
|
::
|
|
|
|
def remove_duplicates(lst):
|
|
...
|
|
|
|
l = [4, 7, 30, "hello", 7, "world", 30, 7]
|
|
remove_duplicates(l)
|
|
assert l == [4, 7, 30, "hello", "world"]
|
|
|
|
.. todo:: defaultdict, get (avec une valeur par défaut)
|
|
|
|
- tri de liste personnalisé :
|
|
|
|
.. literalinclude:: snippets/sorter.py
|
|
|
|
>>> 'a' in d
|
|
True
|
|
>>> t[1]
|
|
2
|
|
>>>
|
|
>>> for i in l:
|
|
... print i
|
|
...
|
|
1
|
|
2
|
|
3
|
|
>>>
|
|
>>> for i in d:
|
|
... print i
|
|
...
|
|
a
|
|
c
|
|
b
|
|
>>>
|
|
>>> for key, value in d.items():
|
|
... print key, " : ", value
|
|
...
|
|
a : 2
|
|
c : 4
|
|
b : 3
|
|
>>>
|
|
|
|
.. todo:: l'interpréteur python pour l'introspection des objets
|
|
|
|
en python, **pas besoin de déclaration de type**. Qu'est-ce que ça veut dire ?
|
|
|
|
>>> type(1)
|
|
<type 'int'>
|
|
>>>
|
|
>>> dir(3)
|
|
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__',
|
|
'__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__',
|
|
'__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__',
|
|
'__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__',
|
|
'__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__',
|
|
'__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__',
|
|
'__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__',
|
|
'__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__',
|
|
'__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__',
|
|
'__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__',
|
|
'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
|
|
>>>
|
|
>>> type(3)
|
|
<type 'int'>
|
|
>>>
|
|
|
|
- Le type set
|
|
|
|
Set
|
|
|
|
collection non ordonnées d'éléments uniques
|
|
|
|
|
|
- le type set immutable et le type set mutable.
|
|
- un ensemble peut être étendu ou bien seulement englobé
|
|
|
|
::
|
|
|
|
Manipulations non supportées
|
|
|
|
>>> e["a"]
|
|
Traceback (most recent call last):
|
|
TypeError: unsubscriptable object
|
|
>>> e.append("a")
|
|
Traceback (most recent call last):
|
|
AttributeError: 'Set' object has no attribute 'append'
|
|
|
|
Création
|
|
|
|
Ensemble vide :
|
|
|
|
::
|
|
|
|
>>> e = set()
|
|
>>> e
|
|
Set([])
|
|
>>> e = set("toto")
|
|
>>> e
|
|
Set(['t', 'o'])
|
|
>>> d = {"a":1,"b":2}
|
|
>>> f = set(d)
|
|
>>> f
|
|
Set(['a', 'b'])
|
|
|
|
Appartenance et définition en extension
|
|
|
|
::
|
|
|
|
Set(['a', 'b'])
|
|
>>> "a" in i
|
|
True
|
|
>>> len(h)
|
|
4
|
|
>>> for u in h:
|
|
... print u
|
|
...
|
|
a
|
|
b
|
|
t
|
|
o
|
|
>>> e.add("a")
|
|
>>> e
|
|
Set(['a'])
|
|
>>> for i in range(5):
|
|
... e.add(i)
|
|
...
|
|
>>> e
|
|
Set(['a', 0, 2, 3, 4, 1])
|
|
Set(['a'])
|
|
>>> e.add("b", "c")
|
|
Traceback (most recent call last):
|
|
TypeError: add() takes exactly 2 arguments (3 given)
|
|
>>> for i in range(5):
|
|
... e.add(i)
|
|
...
|
|
>>> e
|
|
# Suppression :
|
|
>>> f = e.copy()
|
|
>>> f
|
|
Set(['a', 0, 2, 3, 4, 1])
|
|
>>> f.remove(0)
|
|
|
|
Opérations sur les ensembles
|
|
|
|
::
|
|
|
|
>>> v = sets.Set()
|
|
|
|
>>> e.issubset(f)
|
|
False
|
|
>>> f.issubset(e)
|
|
True
|
|
>>> e.issuperset(f)
|
|
True
|
|
>>> f < e
|
|
True
|
|
>>> f > e
|
|
False
|
|
>>> e
|
|
Set(['a', 0, 2, 3, 4, 1, ImmutableSet(['p'])])
|
|
>>> e.copy()
|
|
Set(['a', 0, 2, 3, 4, 1, ImmutableSet(['p'])])
|
|
>>> e.remove(3)
|
|
>>> e
|
|
Set(['a', 0, 2, 4, 1, ImmutableSet(['p'])])
|
|
>>> 0 in e
|
|
True
|
|
>>> e.pop()
|
|
'a'
|
|
>>> e
|
|
Set([0, 2, 4, 1, ImmutableSet(['p'])])
|
|
>>> e.pop()
|
|
0
|
|
>>> e.discard(4)
|
|
>>> e
|
|
Set([2, 1, ImmutableSet(['p'])])
|
|
>>> e.discard("p")
|
|
>>> e
|
|
Set([2, 1, ImmutableSet(['p'])])
|
|
>>> e.discard(sets.Set("p"))
|
|
>>> e
|
|
Set([2, 1])
|
|
>>>
|
|
>>> e -= f
|
|
>>> e
|
|
Set([])
|
|
>>> f
|
|
Set(['a', 2, 3, 4, 1])
|
|
>>>
|
|
>>> e.clear()
|
|
>>> e
|
|
Set([])
|
|
>>>
|
|
# copy
|
|
>>> h == e
|
|
False
|
|
>>> h != e
|
|
True
|
|
>>> u = h.copy()
|
|
>>> u
|
|
Set(['a', 'b', 't', 'o'])
|
|
|
|
Opérations ensemblistes
|
|
|
|
::
|
|
|
|
#Pas d'opération "+" :
|
|
>>> h = e + f
|
|
Traceback (most recent call last):
|
|
TypeError: unsupported operand type(s) for +: 'Set' and 'Set'
|
|
#La réunion :
|
|
>>> g = e or f
|
|
>>> g
|
|
Set(['t', 'o'])
|
|
autre notation :
|
|
>>> h | e
|
|
Set(['a', 'b', 't', 'o'])
|
|
>>> h & e
|
|
Set(['t', 'o'])
|
|
>>>
|
|
Le complémentaire :
|
|
>>> h = e ^ f
|
|
>>> h
|
|
Set(['a', 'b', 't', 'o'])
|
|
La différence :
|
|
>>> i = h - e
|
|
>>> i
|
|
L'intersection, la réunion, le complémentaire :
|
|
>>> f
|
|
Set(['a', 2, 3, 4, 1])
|
|
>>> f & e
|
|
Set(['a', 1, 2, 3, 4])
|
|
>>> f | e
|
|
Set(['a', 1, 2, 3, 4, 0])
|
|
>>> f ^ e
|
|
Set([0])
|
|
|
|
différence entre type et isinstance
|
|
------------------------------------
|
|
|
|
`type()` ne gère pas l'héritage alors que `isinstance()` si:
|
|
|
|
>>> class MyClass(object):
|
|
def __init__(self):
|
|
pass
|
|
>>> a = MyClass()
|
|
>>> type(a) == MyClass
|
|
True
|
|
>>> type(a) == object
|
|
False
|
|
>>> isinstance(a, MyClass)
|
|
True
|
|
>>> isinstance(a, object)
|
|
True
|
|
>>>
|
|
|
|
Dans la **PEP 8**, Guido demande explicitement d'utiliser isinstance et non type
|
|
|
|
.. note::
|
|
|
|
citation :
|
|
|
|
Object type comparisons should always use isinstance() instead
|
|
of comparing types directly.
|
|
|
|
Yes: if isinstance(obj, int):
|
|
|
|
No: if type(obj) is int:
|
|
|
|
|
|
inférence de type
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. todo:: coercion, typage dynamique, inférence de type
|
|
|
|
exemple::
|
|
|
|
def addition_forte(x, y):
|
|
return int(x) + int(y)
|
|
|
|
def addition_faible(x, y):
|
|
return x + y
|
|
|
|
dans `addition_faible`, il n'y a pas de casting de type, on n'essaye pas
|
|
de transformer ça en un type donné, c'est-à-dire que si `x` et `y` sont
|
|
compatible, ça marche. Le typage est fort, on demande des types
|
|
|
|
>>> addition_faible("1", 4)
|
|
TypeError: cannot concatenate 'str' and 'int' objects
|
|
|
|
>>> addition_forte("1", 4)
|
|
TypeError: cannot concatenate 'str' and 'int' objects
|
|
|
|
>>> addition_faible("a", "b")
|
|
5
|
|
|
|
Remarquons que `addition_faible` renvoie forcément un type `int` tandis
|
|
que `addition_forte` peut renvoyer un autre type, ceci est dû au
|
|
polymorphisme paramétrique.
|
|
|
|
.. todo:: en python un type et une classe, c'est la même chose
|
|
|
|
.. todo:: "duck typing" en python
|
|
|
|
- le typage
|
|
|
|
- typage fort
|
|
|
|
- statique : déclaration ou bien inférence (déduction) lisible dans le source
|
|
(exemple : java)
|
|
|
|
- typage dynamique : une variable est typée en fonction de son contenu
|
|
|
|
- typage faible :
|
|
|
|
- une donnée n'aura pas spécialement de type : les nombres, les chaînes de
|
|
caractères, les booléens, etc. seront tous des scalaires et ne seront
|
|
différenciés que par leur valeur et par le contexte de leur utilisation
|