module faq.faq_python

Short summary

module teachpyx.faq.faq_python

Quelques questions d’ordre général autour du langage Python.

source on GitHub

Functions

function

truncated documentation

difference_div

entier_grande_taille

enumerate_regex_search

Cette fonction itère sur les différentes occurences d’une expression régulière.

get_day_name

returns the day name for a give date

get_month_name

returns the month name for a give date

information_about_package

calls pip show to retrieve information about packages

list_of_installed_packages

calls pip list to retrieve the list of packages

property_example

python_path

same_variable

Cette fonction dit si les deux objets sont en fait le même objet (True) ou non (False) s’ils sont différents (même s’ils …

sortable_class

stringio

returns a StringIO object on a text

Documentation

Quelques questions d’ordre général autour du langage Python.

source on GitHub

teachpyx.faq.faq_python.difference_div()[source]

Quelle est la différence entre / et // - division ?

Le résultat de la division avec l’opérateur / est toujours réel : la division de deux entiers 1/2 donne 0.5. Le résultat de la division avec l’opérateur // est toujours entier. Il correspond au quotient de la division.

div1 = 1/2
div2 = 4/2
div3 = 1//2
div4 = 1.0//2.0
print(div1,div2,div3,div4) # affiche (0.5, 2.0, 0, 0)

Le reste d’une division entière est obtenue avec l’opérateur %.

print ( 5 % 2 )  # affiche 1

C’est uniquement vrai pour les version Python 3.x. Pour les versions 2.x, les opérateurs / et // avaient des comportements différents (voir What’s New In Python 3.0).

source on GitHub

teachpyx.faq.faq_python.entier_grande_taille()[source]

Quel est l’entier le plus grand ?

La version 3 du langage Python a supprimé la constante sys.maxint qui définissait l’entier le plus grand (voir What’s New In Python 3.0). De ce fait la fonction getrandbit retourne un entier aussi grand que l’on veut.

import random,sys
x = random.getrandbits(2048)
print(type(x),x)

Qui affiche

<class 'int'> 2882159224557107513165483098383814837021447484558010147211921304219017212673656549681269862792029...

Les calculs en nombre réels se font toujours avec huit octets de précision. Au delà, il faut utiliser la librairie gmpy2. Il est également recommandé d’utiliser cette librairie pour les grands nombres entiers (entre 20 et 40 chiffres). La librairie est plus rapide que l’implémentation du langage Python (voir Overview of gmpy2).

Tabulations ou espace ?

Il est préférable de ne pas utiliser les tabulations et de les remplacer par des espaces. Lorsqu’on passe d’un Editeur à un autre, les espaces ne bougent pas. Les tabulations sont plus ou moins grandes visuellement. L’essentiel est de ne pas mélanger. Dans SciTE, il faut aller dans le menu Options / Change Indentation Settings… Tous les éditeurs ont une option similaire.

source on GitHub

Cette fonction itère sur les différentes occurences d’une expression régulière.

Paramètres
  • exp – expression régulière

  • text – text à parser

Renvoie

itérateur

Comment itérer sur les résultats d’une expression régulière ?

On utilise la méthode finditer.

found = exp.search(text)
for m in exp.finditer(text):
    # ...

Voir également Petites subtilités avec les expressions régulières en Python.

source on GitHub

teachpyx.faq.faq_python.get_day_name(date)[source]

returns the day name for a give date

Paramètres

date – datatime

Renvoie

month name

Récupérer le nom du jour à partir d’une date

import datetime
dt = datetime.datetime(2016, 1, 1)
print(dt.strftime("%A"))

source on GitHub

teachpyx.faq.faq_python.get_month_name(date)[source]

returns the month name for a give date

Paramètres

date – datatime

Renvoie

month name

Récupérer le nom du mois à partir d’une date

import datetime
dt = datetime.datetime(2016, 1, 1)
print(dt.strftime("%B"))

source on GitHub

teachpyx.faq.faq_python.information_about_package(name)[source]

calls pip show to retrieve information about packages

Récupérer la liste des modules installés

Le module pip permet d’installer de nouveaux modules mais aussi d’obtenir la liste des packages installés

pip list

On peut également l’obtenir depuis l’interpréteur python

import pip
pip.main(["list"])

Pourquoi l’installation de pandas (ou numpy) ne marche pas sous Windows avec pip ?

Python est un langage très lent et c’est pourquoi la plupart des modules de calculs numériques incluent des parties implémentées en langage C++. numpy, pandas, matplotlib, scipy, scikit-learn, …

Sous Linux, le compilateur est intégré au système et l’installation de ces modules via l’instruction pip install <module> met implicitement le compilateur à contribution. Sous Windows, il n’existe pas de compilateur C++ par défaut à moins de l’installer. Il faut faire attention alors d’utiliser exactement le même que celui utilisé pour compiler Python (voir Compiling Python on Windows).

C’est pour cela qu’on préfère utiliser des distributions comme Anaconda qui propose par défaut une version de Python accompagnée des modules les plus utilisés. Elle propose également une façon simple d’installer des modules précompilés avec l’instruction

conda install <module_compile>

L’autre option est d’utilser le site Unofficial Windows Binaries for Python Extension Packages qui propose des versions compilées sous Windows d’un grand nombre de modules. Il faut télécharger le fichier .whl puis l’installer avec l’instruction pip install <fichier.whl>. La différence entre les deux ooptions tient aux environnements virtuels, voir Python virtual environments.

source on GitHub

teachpyx.faq.faq_python.list_of_installed_packages()[source]

calls pip list to retrieve the list of packages

Obtenir des informations sur les packages installés

Le module pip retourne des informations sur n’importe quel module installé, sa version, sa license

pip show pandas

On peut également l’obtenir depuis l’interpréteur python

import pip
pip.main(["show", "pandas"])

Exemple

Name: pandas
Version: 0.16.0
Summary: Powerful data structures for data analysis, time series,and statistics
Home-page: http://pandas.pydata.org
Author: The PyData Development Team
Author-email: pydata@googlegroups.com
License: BSD
Location: c:\python35_x64\lib\site-packages
Requires: python-dateutil, pytz, numpy

On utilise également pip freeze pour répliquer l’environnement dans lequel on a développé un programme. pip freeze produit la liste des modules avec la version utilisée

docutils==0.11
Jinja2==2.7.2
MarkupSafe==0.19
Pygments==1.6
Sphinx==1.2.2

Ce qu’on utilise pour répliquer l’environnement de la manière suivante

pip freeze > requirements.txt
pip install -r requirements.txt

Cette façon de faire fonctionne très bien sous Linux mais n’est pas encore opérationnelle sous Windows à moins d’installer le compilateur C++ utilisée pour compiler Python.

source on GitHub

teachpyx.faq.faq_python.property_example()[source]

property

Une property est une écriture qui sert à transformer l’appel d’une méthode de classe en un attribut.

class ClasseAvecProperty:

    def __init__(self,x,y):
        self._x, self._y = x,y

    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

    @property
    def norm2(self):
        return self._y**2 + self._x**2

c = ClasseAvecProperty(1,2)
print(c.x)
print(c.y)

x est définit comme une méthode mais elle retourne simplement l’attribut _x. De cette façon, il est impossible de changer x en écrivant:

c.x = 5

Cela déclenche l’erreur:

Traceback (most recent call last):
  File "faq_python.py", line 455, in <module>
    c.x = 5
AttributeError: can't set attribute

On fait cela parce que l’écriture est plus courte et que cela évite certaines erreurs.

source on GitHub

teachpyx.faq.faq_python.python_path()[source]

Comment éviter sys.path.append… quand on développe un module ?

Lorsqu’on développe un module, on ne veut pas l’installer. On ne veut pas qu’il soit présent dans le répertoire site-packages de la distribution de Python car cela introduit deux versions : celle qu’on développe et celle qu’on a installer. Avant, je faisais cela pour créer un petit programme utilisant mon propre module (et on en trouve quelque trace dans mon code) :

import sys
sys.path.append("c:/moncode/monmodule/src")
import monmodule

Quand je récupère un programme utilisant ce module, il me faudrait ajouter ces petites lignes à chaque fois et c’est barbant. Pour éviter cela, il est possible de dire à l’interpréteur Python d’aller chercher ailleurs pour trouver des modules en ajoutant le chemin à la variable d’environnement PYTHONPATH. Sous Windows :

set PYTHON_PATH=%PYTHON_PATH%;c:\moncode\monmodule\src

source on GitHub

teachpyx.faq.faq_python.same_variable(a, b)[source]

Cette fonction dit si les deux objets sont en fait le même objet (True) ou non (False) s’ils sont différents (même s’ils contiennent la même information).

Paramètres
  • a – n’importe quel objet

  • b – n’importe quel objet

Renvoie

True ou False

Qu’est-ce qu’un type immuable ou immutable ?

Une variable de type immuable ne peut être modifiée. Cela concerne principalement :

  • int, float, str, tuple

Si une variable est de type immuable, lorsqu’on effectue une opération, on créé implicitement une copie de l’objet.

Les dictionnaires et les listes sont modifiables (ou mutable). Pour une variable de ce type, lorsqu’on écrit a = b, a et b désigne le même objet même si ce sont deux noms différentes. C’est le même emplacement mémoire accessible paur deux moyens (deux identifiants).

Par exemple

a  = (2,3)
b  = a
a += (4,5)
print( a == b ) # --> False
print(a,b)      # --> (2, 3, 4, 5) (2, 3)

a  = [2,3]
b  = a
a += [4,5]
print( a == b ) # --> True
print(a,b)      # --> [2, 3, 4, 5] [2, 3, 4, 5]

Dans le premier cas, le type (tuple) est _immutable_, l’opérateur += cache implicitement une copie. Dans le second cas, le type (list) est _mutable_, l’opérateur += évite la copie car la variable peut être modifiée. Même si b=a est exécutée avant l’instruction suivante, elle n’a pas pour effet de conserver l’état de a avant l’ajout d’élément. Un autre exemple

a  = [1, 2]
b  = a
a [0] = -1
print(a)        # --> [-1, 2]
print(b)        # --> [-1, 2]

Pour copier une liste, il faut expliciter la demander

a  = [1, 2]
b  = list(a)
a [0] = -1
print(a)        # --> [-1, 2]
print(b)        # --> [1, 2]

La page Immutable Sequence Types détaille un peu plus le type qui sont mutable et ceux qui sont immutable. Parmi les types standards :

Une instance de classe est mutable. Il est possible de la rendre immutable par quelques astuces :

Enfin, pour les objects qui s’imbriquent les uns dans les autres, une liste de listes, une classe qui incluent des dictionnaires et des listes, on distingue une copie simple d’une copie intégrale (deepcopy). Dans le cas d’une liste de listes, la copie simple recopie uniquement la première liste

import copy
l1 = [ [0,1], [2,3] ]
l2 = copy.copy(l1)
l1 [0][0] = '##'
print(l1,l2)        # --> [['##', 1], [2, 3]] [['##', 1], [2, 3]]

l1 [0] = [10,10]
print(l1,l2)        # --> [[10, 10], [2, 3]] [['##', 1], [2, 3]]

La copie intégrale recopie également les objets inclus

import copy
l1 = [ [0,1], [2,3] ]
l2 = copy.deepcopy(l1)
l1 [0][0] = '##'
print(l1,l2)        # --> [['##', 1], [2, 3]] [[0, 1], [2, 3]]

Les deux fonctions s’appliquent à tout object Python : module copy.

source on GitHub

teachpyx.faq.faq_python.sortable_class(cl)[source]

Classe sortable

Il faut prononcer sortable à l’anglaise. Comment rendre une classe sortable ? Pour faire simple, on veut écrire

l = [ o1, o2 ]
l.sort()

o1 et o2 sont des objets d’une classe que vous avez définie

class MaClasse:

    ...

Pour que cela fonctionne, il suffit juste de surcharger l’opérateur < ou plus exactement __lt__. Par exemple

class MaClasse:

    def __lt__(self, autre_instance):
        if self.jenesaispas < autre.jenesaispas:
            return True
        elif self.jenesaispas > autre.jenesaispas:
            return False:
        else:
            if self.jenesaispas2 < autre.jenesaispas2:
                return True
            else:
                return False

source on GitHub

teachpyx.faq.faq_python.stringio(text)[source]

returns a StringIO object on a text

param text

any text

return

StringIO object

A quoi sert un ``StringIO`` ?

La plupart du temps, lorsqu’on récupère des données, elles sont sur le disque dur de votre ordinateur dans un fichier texte. Lorsqu’on souhaite automatiser un processur qu’on répète souvent avec ce fichier, on écrit une fonction qui prend le nom du fichier en entrée.

def processus_quotidien(nom_fichier) :
    # on compte les lignes
    nb = 0
    with open(nom_fichier,"r") as f :
        for line in f :
            nb += 1
    return nb

Et puis un jour, les données ne sont plus dans un fichier mais sur Internet. Le plus simple dans ce cas est de recopier ces données sur disque dur et d’appeler la même fonction. Simple. Un autre les données qu’on doit télécharger font plusieurs gigaoctets. Tout télécharger prend du temps pour finir pour s’apercevoir qu’elles sont corrompues. On a perdu plusieurs heures pour rien. On aurait bien voulu que la fonction processus_quotidien commence à traiter les données dès le début du téléchargement.

Pour cela, on a inventé la notion de stream ou flux qui sert d’interface entre la fonction qui traite les données et la source des données. Le flux lire les données depuis n’importe quel source (fichier, internet, mémoire), la fonction qui les traite n’a pas besoin d’en connaître la provenance.

StringIO est un flux qui considère la mémoire comme source de données.

def processus_quotidien(data_stream):
    # on compte toujours les lignes
    nb = 0
    for line in data_stream :
        nb += 1
    return nb

La fonction processus_quotidien fonctionne pour des données en mémoire et sur un fichier.

fichier = __file__
f = open(fichier,"r")
nb = processus_quotidien(f)
print(nb)

text = "ligne1
ligne2 »

st = io.StringIO(text) nb = processus_quotidien(st) print(nb)

source on GitHub