您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
此存儲庫已封存,您能瀏覽檔案及複製此存儲庫,但不能推送、建立問題及拉取請求。

python-09.md 7.8 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. % Programmation avec Python (chapitre 9)
  2. % Dimitri Merejkowsky
  3. \center \huge Formats et chaînes de caractères
  4. # Formater des chaînes de caractères
  5. Problème:
  6. \vfill
  7. ```python
  8. >>> nom = "Ford"
  9. >>> résultat = 42
  10. >>> message = "Bonjour, " + nom + ". "
  11. >>> message += "La réponse est: " + str(résultat) + "."
  12. >>> message
  13. 'Bonjour, Ford. La réponse est: 42.'
  14. ```
  15. \vfill
  16. Ce n'est pas très lisible ...
  17. 3 solutions différentes en Python
  18. # Solution 1: À l'ancienne
  19. * Avec `%`
  20. * Compatible avec les très vieux Pythons
  21. * Compatibles avec d'autres langage (`printf` en C par example)
  22. # Example 1
  23. ```python
  24. name = "John"
  25. print("Bonjour %s!" % name) # 's' comme string
  26. age = 42
  27. print("Vous avez %i ans" % 42) # 'i' comme integer
  28. ```
  29. # Attention aux types:
  30. ```python
  31. >>> print("Bonjour %i!" % name)
  32. TypeError: %i format: a number is required, not str
  33. ```
  34. # On peut en mettre plusieurs
  35. Avec un tuple:
  36. ```python
  37. print("Bonjour %s, vous avez %i" % (name, age))
  38. ```
  39. \vfill
  40. Avec un dictionnaire:
  41. ```python
  42. data = {"name": "John", "age": 42}
  43. print("Bonjour %(name)s, vous avez %(age)i ans" % data)
  44. ```
  45. # Solution 2: format()
  46. Des `{}` comme "placeholders" et une *méthode* sur les strings:
  47. ```python
  48. >>> nom = "Ford"
  49. >>> résultat = 42
  50. >>> template = "Bonjour, {}. La réponse est: {}"
  51. >>> message = template.format(nom, résultat)
  52. >>> message
  53. 'Bonjour, Ford. La réponse est: 42.'
  54. ```
  55. * Pas de types!
  56. # format() - à plusieurs
  57. On peut aussi nommer les remplacements:
  58. ```python
  59. template = "Bonjour, {nom}. La réponse est: {résultat}"
  60. template.format(nom="Ford", résultat=42)
  61. ```
  62. # format() - à plusieurs
  63. On peut les ordonner:
  64. ```python
  65. template = "Bonjour {1}. La réponse est {0}"
  66. template.format(reponse, name)
  67. ```
  68. * Pas possible avec `%`!
  69. # Solution 3: f-strings
  70. * La meilleure de toutes :)
  71. * Plus succint que `format()`
  72. * Plus performant que `%` et `.format()`
  73. * Mais pas avant Python 3.6
  74. # Principe
  75. On peut mettre du *code* dans `{}` avec la lettre `f` devant la chaîne:
  76. ```python
  77. name = "Patrick"
  78. score = 42
  79. text = f"Bonjour {name}. Votre score est: {score}"
  80. ```
  81. \vfill
  82. Mais aussi:
  83. ```python
  84. text = f"2 + 2 égale { 2 + 2 }"
  85. ```
  86. # Conclusion
  87. Je vous ai présenté `%` et `format()` parce que vous risquez d'en voir.
  88. Mais si vous avez le choix, utilisez des `f-strings`!
  89. # Spécifications de formats
  90. * Permet des opérations pendant la conversion en texte
  91. * Fonctionne avec les 3 solutions
  92. # Tronquer
  93. ```python
  94. >>> pi = 3.14159265359
  95. >>> truncated = "%.2f" % pi
  96. 3.14
  97. ```
  98. Le texte dans les accolades après le `:` est un mini-langage de spécification de format.
  99. `.2` veut dire: 2 chiffres après la virgule maximum.
  100. # Alignements et paddings
  101. On peut aussi faire des alignements et du "padding":
  102. \vfill
  103. ```python
  104. template = "{name:>10}: {score:03}"
  105. print(template.format(name="Alice", score=42))
  106. print(template.format(name="Bob", score=5))
  107. ```
  108. ```
  109. Alice: 042
  110. Bob: 005
  111. ```
  112. * `>10` : aligné à gauche, taille minimum 10
  113. * `03`: rajouter jusqu'à 2 zéros à gauche pour que la taille fasse 3
  114. # Documentation
  115. Documentation ici:
  116. htps://docs.python.org/fr/3/library/string.html#format-specification-mini-language
  117. #
  118. \center \huge Rappels sur les classes
  119. # Classes
  120. ```python
  121. class Car:
  122. total_number_of_cars = 0
  123. def __init__(self, color="black"):
  124. self.color = color
  125. Car.total_number_of_cars += 1
  126. def drive(self):
  127. print("vroom")
  128. @classmethod
  129. def print_number_of_cars(cls):
  130. print(cls.total_number_of_cars,
  131. "cars have been made")
  132. ```
  133. # Composition
  134. ```python
  135. class Authorization:
  136. def __init__(self, credentials_file):
  137. ...
  138. self.password = ...
  139. class Client:
  140. url = "https://exmple.com"
  141. def __init__(self, auth)
  142. self.auth = auth
  143. def make_request(self):
  144. password = self.auth.get_password()
  145. requests.get(url, password=password)
  146. ```
  147. # Héritage - partage des attributs et méthodes
  148. ```python
  149. class A:
  150. def method_in_a(self):
  151. self.attribute_in_a = 42
  152. class B(A):
  153. def method_in_b(self):
  154. self.method_in_a() # ok
  155. self.attribute_in_a # ok
  156. ```
  157. # Héritage - ordre de résolution des méthodes
  158. ```python
  159. class A:
  160. def method_in_a(self):
  161. pass
  162. class B(A):
  163. def method_in_b(self):
  164. pass
  165. >>> a = A()
  166. >>> a.method_in_a() # ok
  167. >>> a.method_in_b() # error
  168. >>> b = B()
  169. >>> b.method_in_b() # ok
  170. >>> b.method_in_a() # ok
  171. ```
  172. # Héritage - ordre de résolution des méthodes
  173. ```python
  174. class A:
  175. def method_in_a(self):
  176. pass
  177. class B(A):
  178. def method_in_b(self):
  179. pass
  180. >>> a = A()
  181. >>> a.method_in_a() # ok
  182. >>> a.method_in_b() # error
  183. >>> b = B()
  184. >>> b.method_in_b() # ok
  185. >>> b.method_in_a() # ok
  186. ```
  187. # Héritage: surcharge
  188. ```python
  189. class A:
  190. def method(self):
  191. print("A!")
  192. class B(A):
  193. def method(self):
  194. print("B!")
  195. >>> a = A()
  196. >>> a.method() # ok
  197. 'A!'
  198. >>> b = B()
  199. >>> b.method()
  200. 'B!'
  201. ```
  202. # Héritage - super()
  203. ```python
  204. class A:
  205. def method(self):
  206. print("A!")
  207. class B(A):
  208. def method(self):
  209. super().method()
  210. print("B!")
  211. >>> a = A()
  212. >>> a.method() # ok
  213. 'A!'
  214. >>> b = B()
  215. >>> b.method()
  216. 'A!'
  217. 'B!'
  218. ```
  219. # Héritage - super() et \_\_init\_\_
  220. ```python
  221. # All animals have a species
  222. class Animal:
  223. def __init__(self, species):
  224. self.species = species
  225. # Pets are animals with a name
  226. class Pet(Animal):
  227. def __init__(self, species, name):
  228. super().__init__(species) # <- à ne pas oublier
  229. self.name = name
  230. # All dogs are pets
  231. class Dog(Pet):
  232. def __init__(self, name):
  233. super().init("dog", name)
  234. ```
  235. #
  236. \center \huge Interfaces et classes abstraites
  237. # Example
  238. Imaginons un jeu où il faut retrouver le nom d'un super-héros à partir
  239. de sa description.
  240. On a une classe `MarvelClient` qui permet de lister les personnages et leurs
  241. descriptions et une class `Game` pour la logique du jeu
  242. # Implémentation - MarvelClient
  243. ```python
  244. class MarvelClient:
  245. url = "https://marvel.com/api"
  246. def __init__(self, credentials_file):
  247. # réupére les clés depuis un fichier
  248. def get_all_characters(self):
  249. # appelle l'api marvel pour récupérer
  250. # tous les personnages
  251. def get_description(self, character_name)
  252. # appelle l'api marvel pour récupérer
  253. # une description
  254. ```
  255. # Implémentation - Game
  256. ```python
  257. import random
  258. class Game:
  259. def __init__(self, marvel_client)
  260. self.auth = marvel_client
  261. def play(self):
  262. characters = self.marvel_client.get_all_characters()
  263. name_to_guess = random.choice(characters)
  264. description = self.marvel_client.get_description(
  265. name_to_guess)
  266. while not self.won():
  267. ...
  268. ```
  269. # Contrats implicites - 1
  270. Il y a un *contrat implicite* entre `Game` et `MarvelClient`.
  271. Dans `play` on appelle `self.marvel_client.get_all_characters()` donc la méthode
  272. `get_all_characters()` doit:
  273. * exister
  274. * ne prendre aucun agrument
  275. * retourner une liste de noms
  276. # Contrats implicites - 2
  277. Pareil avec `get_description()`. La méthode doit:
  278. * exister
  279. * prendre un nom en unique argument
  280. * retourner une description
  281. # Une force et une faiblesse
  282. On peut passer à `Client.__init__()` n'importe qu'elle classe pourvu qu'elle ait
  283. les bonnes méthodes!
  284. On appelle ça "duck typing"
  285. # duck typing
  286. Définition traditionnelle (pas exacte à mon sens):
  287. * Si ça marche comme un canard et que ça fait coin-coin comme un canard alors c'est un canard.
  288. \vfill
  289. Meilleure définition:
  290. * Tu peux passer remplacer le canard par une vache. Tant que la vache a un bec et fait coin-coin, c'est bon!
  291. # En image
  292. ![canard vache](img/canard-vache.jpg)
  293. # Exmaple utile
  294. ```python
  295. class FakeCLient():
  296. def get_all_characters(self):
  297. return ["Spider-Man", "Batman", "Superman"]
  298. def get_description(self, name):
  299. if name == "Spider-Man":
  300. ...
  301. ...
  302. fake_client = FakeMarvelClient()
  303. game = Game(fake_client)
  304. game.play()
  305. # Tout marche!
  306. ```