formations/python/python2/formation/type.txt

662 lines
13 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']
>>>
unicode
------------
En python 2.X : deux types : `str` et `unicode` (en python 3 ces types sont unifiés)
on peut facilement tomber sur des erreurs unicode::
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0:
ordinal not in range(128)
- l'encodage (unicode):
on part d'un objet unicode :
>>> u = u"éèà bla"
>>> u
u'\xe9\xe8\xe0 bla'
on le transforme en string utf-8 :
>>> u.encode("utf-8")
'\xc3\xa9\xc3\xa8\xc3\xa0 bla'
>>> print u.encode("utf-8")
éèà bla
>>>
on peut partir d'une string en utf-8, puis::
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.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
manipulations diverses :
- 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
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
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']
>>>
exercice
-------------
écrire la string "1-2-3-4-5-6-7-8-9" programmatiquement
>>> [str(i) for i in l]
['1', '2', '3', '4', '5', '6', '7', '8', '9']
>>> l2 = []
>>> for i in l:
... l2.append(str(i))
...
>>> l2
['1', '2', '3', '4', '5', '6', '7', '8', '9']
>>>
>>> l = range(1,9)
>>> l2 = [str(i) for i in l]
>>> "-".join(l2)
'1-2-3-4-5-6-7-8'
>>> s= "-"
>>> l2.extend(range(20))
>>> l2
['1', '2', 'sdfsdf', '3', '4', '5', '6', '7', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> l + l2
[1, 2, 3, 4, 5, 6, 7, 8, '1', '2', 'sdfsdf', '3', '4', '5', '6', '7', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> l.extend(l2)
KeyboardInterrupt
>>> l = []
>>> l = list()
>>> list
<type 'list'>
>>> list()
[]
>>> list(range(2))
[0, 1]
>>> tuple
<type 'tuple'>
>>> t = (1,2,3)
>>> t
(1, 2, 3)
>>> list(t)
[1, 2, 3]
>>> t
(1, 2, 3)
>>> type(t)
<type 'tuple'>
>>>
.. 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 &lt; e
True
>>> f &gt; 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