Éléments de syntaxe Python

Les variables ne sont pas typées

In [1]:
x = 13
x
Out[1]:
13
In [2]:
x = "toto"
x
Out[2]:
'toto'
In [3]:
type(x)
Out[3]:
<type 'str'>
In [4]:
x = 10

Le bloc if

Pas d'accolades { en Python : c'est l'indentation (espaceement à gauche) qui délimite les blocs. La convention veut que chaque nouveau bloc imbriqué ajoute 4 espaces d'indentation.

In [5]:
if x <= 14:
    print "Hello"
    x += 5
    print x
elif x == 15:
    print x
else:
    print x - 20
Hello
15

Une condition plus complexe avec des connecteurs logiques et des multi-comparaisons

In [6]:
if x is not None and 5 < x < 100 and (True or False):
    print "Oui"
Oui

Boucle while

In [7]:
x = 75
while x < 100:
    x += 1
    print x
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

Les variables de la boucle while ne sont pas locales à la boucle

In [8]:
x
Out[8]:
100

Listes et boucle for

In [9]:
L = [1, 2, 10, 15]
for a in L:
    b = a + 10
    print b
11
12
20
25

Encore une preuve du fait que les variables des boucles ne sont pas locales

In [10]:
a, b
Out[10]:
(15, 25)

On peut imbrique les blocs, bien sûr

In [11]:
for x in L:
    if x > 10:
        print x - 10
    else:
        print x
1
2
10
5

Fonctions

In [12]:
def tot(a, b):
    c = a + b
    return c
In [13]:
x = tot(14, 5)
In [14]:
x
Out[14]:
19

Les variables d'une fonction sont (généralement) locales à la fonction

In [15]:
c
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-15-2cd6ee2c70b0> in <module>()
----> 1 c

NameError: name 'c' is not defined

Puisque l'opérateur + est polymorphique (il fonctionne sur plusieurs types), la fonction tot l'est aussi

In [16]:
tot(5.2, 4.1)
Out[16]:
9.30000000000000
In [17]:
tot("Hello ", 'world')
Out[17]:
'Hello world'

Mais cela ne veut pas dire qu'on peut additionner tout et n'importe quoi: les conversions de type ne sont pas implicite en Python (mais elle le sont parfois en Sage)

In [18]:
tot("Hello", 13)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-18-37d325c0ab11> in <module>()
----> 1 tot("Hello", Integer(13))

<ipython-input-12-957743e6310d> in tot(a, b)
      1 def tot(a, b):
----> 2     c = a + b
      3     return c

/local/SageMath-8.0/src/sage/rings/integer.pyx in sage.rings.integer.Integer.__add__ (/local/SageMath-8.0/src/build/cythonized/sage/rings/integer.c:10936)()
   1604             return y
   1605 
-> 1606         return coercion_model.bin_op(left, right, operator.add)
   1607 
   1608     cpdef _add_(self, right):

/local/SageMath-8.0/src/sage/structure/coerce.pyx in sage.structure.coerce.CoercionModel_cache_maps.bin_op (/local/SageMath-8.0/src/build/cythonized/sage/structure/coerce.c:10448)()
   1102         # We should really include the underlying error.
   1103         # This causes so much headache.
-> 1104         raise bin_op_exception(op, x, y)
   1105 
   1106     cpdef canonical_coercion(self, x, y):

TypeError: unsupported operand parent(s) for +: '<type 'str'>' and 'Integer Ring'
In [19]:
tot("Hello", str(13))
Out[19]:
'Hello13'
In [20]:
tot("Hello", '13')
Out[20]:
'Hello13'

Plus sur les listes

In [21]:
A = [1, 2, 3] + [100, 11, 5]
In [22]:
A
Out[22]:
[1, 2, 3, 100, 11, 5]
In [23]:
A[3]
Out[23]:
100
In [24]:
A.index(100)
Out[24]:
3
In [25]:
A[3]
Out[25]:
100
In [26]:
A.append(354)
In [27]:
A
Out[27]:
[1, 2, 3, 100, 11, 5, 354]
In [28]:
A[2:4]
Out[28]:
[3, 100]
In [29]:
A[1:5:2]
Out[29]:
[2, 100]
In [30]:
A[-1]
Out[30]:
354
In [31]:
A[:-2]
Out[31]:
[1, 2, 3, 100, 11]

Classes

La méthode spéciale __init__ est le constructeur de la classe

In [32]:
class Point():
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def montrer(self):
        print "(" + str(self.x) + "," + str(self.y) + ")" 

Le constructeur est appelé implicitement à la création d'un objet

In [33]:
p = Point(10, 15)
In [34]:
p.x
Out[34]:
10
In [35]:
p.y
Out[35]:
15
In [36]:
p.montrer()
(10,15)

Les champs des classes sont dynamiques: on peut en ajouter à souhait

In [37]:
p.c = 56
In [38]:
p.c
Out[38]:
56
In [39]:
p.montrer()
(10,15)
In [40]:
p
Out[40]:
<__main__.Point instance at 0x7f2cab07f5a8>

On peut ajouter aussi des méthodes à une classe déjà définie

In [41]:
def affichage(self):
    print "Dans __repr__"
    # L'opérateur % sur les chaines de caractères est simlaire au printf en C
    return "(%d, %d)" % (self.x, self.y)
Point.__repr__ = affichage
In [42]:
p = Point(10, 15)

La méthode spéciale __repr__ modifie la façon dont les objets s'affichent

In [43]:
p
Dans __repr__
Out[43]:
(10, 15)

Exercice 6.1

In [44]:
def euclidepol (A,B):
    A0 = A; A1 = B
    S0 = 1; S1 = 0
    T0 = 0; T1 = 1
    while A1 != 0:
        Q = A0//A1
        U = A1; A1 = A0 - Q*A1; A0 = U
        U = S1; S1 = S0 - Q*S1; S0 = U
        U = T1; T1 = T0 - Q*T1; T0 = U
    return (A0,S0,T0)
In [45]:
A.<X> = QQ[]
In [46]:
a, b = X^2-1, (X-1)^2
g, u, v = euclidepol(a, b)
In [47]:
g
Out[47]:
2*X - 2
In [48]:
u, v
Out[48]:
(1, -1)
In [49]:
u*a + v*b == g
Out[49]:
True

Exercice 6.2

In [50]:
def irreducible(k, n):
    A.<x> = k[]
    p = x^n
    while not p.is_irreducible():
        p = A.random_element(n)
    return p.monic()
In [51]:
irreducible(QQ, 3)
Out[51]:
x^3 - 3/2*x^2 - 45/2*x + 3/4
In [52]:
irreducible(GF(7), 100)
Out[52]:
x^100 + 3*x^99 + 6*x^98 + 4*x^97 + 5*x^96 + 2*x^95 + x^94 + 6*x^93 + 2*x^92 + 2*x^91 + 2*x^90 + 2*x^89 + x^88 + 2*x^87 + x^86 + x^85 + 4*x^84 + x^83 + 3*x^82 + 6*x^81 + 3*x^80 + 2*x^79 + 4*x^78 + 5*x^77 + x^76 + 6*x^75 + 5*x^74 + 5*x^73 + x^72 + 2*x^71 + 6*x^70 + 3*x^69 + 4*x^68 + 3*x^67 + 3*x^66 + 5*x^64 + 4*x^62 + 4*x^61 + 2*x^60 + 4*x^59 + 5*x^57 + 5*x^56 + 2*x^55 + 4*x^54 + 2*x^53 + 2*x^52 + 2*x^51 + 2*x^50 + 6*x^49 + 5*x^48 + x^47 + 5*x^46 + 5*x^44 + 3*x^43 + 3*x^42 + 3*x^41 + 4*x^39 + 2*x^38 + 3*x^36 + 6*x^35 + 3*x^34 + 6*x^33 + 4*x^32 + 5*x^31 + x^30 + 2*x^29 + 4*x^28 + 5*x^27 + 2*x^26 + 2*x^25 + 3*x^24 + 3*x^23 + 2*x^22 + 3*x^21 + 4*x^20 + 2*x^19 + 2*x^18 + 5*x^16 + 5*x^15 + 2*x^14 + 3*x^13 + 5*x^12 + 4*x^11 + 2*x^9 + 4*x^8 + 6*x^7 + 2*x^6 + 6*x^4 + 5*x^3 + 2*x^2 + 6*x + 6

Exercice 6.3

In [53]:
def lexico_irred(p, n):
    A.<x> = GF(p)[]
    P = x^n
    while not P.is_irreducible():
        # print P
        for i in range(n):
            if P[i] != p-1:
                P += x^i
                break
        for j in range(i):
            P -= P[j] * x^j
    return P
In [54]:
lexico_irred(3, 10)
Out[54]:
x^10 + 2*x^2 + 1
In [55]:
lexico_irred(101, 21)
Out[55]:
x^21 + 2*x + 1