.. 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 "", line 1, in 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) >>> 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 >>> list() [] >>> list(range(2)) [0, 1] >>> tuple >>> t = (1,2,3) >>> t (1, 2, 3) >>> list(t) [1, 2, 3] >>> t (1, 2, 3) >>> type(t) >>> .. 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 "", line 1, in 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 "", 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) >>> >>> 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) >>> - 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