Lorsque vous codez dans d'autres langues, vous créez parfois une étendue de bloc, comme ceci:
statement
...
statement
{
statement
...
statement
}
statement
...
statement
Un des objectifs (parmi tant d'autres) est d'améliorer la lisibilité du code: montrer que certaines instructions forment une unité logique ou que certaines variables locales ne sont utilisées que dans ce bloc.
Existe-t-il une manière idiomatique de faire la même chose en Python?
One purpose (of many) is to improve code readability
- Le code Python, écrit correctement (c'est-à-dire suivant le zen de python ) n'aurait pas besoin d'une telle garniture pour être lisible. En fait, c'est l'une des (nombreuses) choses que j'aime chez Python.__exit__
etwith
déclaration, en changeant leglobals()
mais j'ai échoué.Réponses:
Non, il n'y a pas de prise en charge du langage pour créer une étendue de bloc.
Les constructions suivantes créent la portée:
la source
La manière idiomatique en Python est de garder vos fonctions courtes. Si vous pensez que vous en avez besoin, refactorisez votre code! :)
Python crée une nouvelle portée pour chaque module, classe, fonction, expression de générateur, compréhension de dict, compréhension d'ensemble et en Python 3.x également pour chaque compréhension de liste. En dehors de cela, il n'y a pas de portées imbriquées à l'intérieur des fonctions.
la source
Vous pouvez faire quelque chose de similaire à une portée de bloc C ++ en Python en déclarant une fonction dans votre fonction, puis en l'appelant immédiatement. Par exemple:
Si vous ne savez pas pourquoi vous voudrez peut-être faire cela, cette vidéo pourrait vous convaincre.
Le principe de base est de tout définir aussi étroitement que possible sans introduire de `` garbage '' (types / fonctions supplémentaires) dans une portée plus large que ce qui est absolument nécessaire - Rien d'autre ne veut utiliser la
do_first_thing()
méthode par exemple, elle ne doit donc pas être étendue en dehors du fonction d'appel.la source
Je suis d'accord qu'il n'y a pas de portée de blocage. Mais un endroit dans python 3 le fait SEMBLER comme s'il avait une portée de bloc.
qu'est-il arrivé qui a donné ce regard? Cela fonctionnait correctement dans python 2. mais pour arrêter les fuites de variables dans python 3, ils ont fait cette astuce et ce changement donne l'impression qu'il a une portée de bloc ici.
Laisse-moi expliquer.
Selon l'idée de portée, lorsque nous introduisons des variables avec les mêmes noms dans la même portée, sa valeur doit être modifiée.
c'est ce qui se passe dans python 2
Mais dans python 3, même si la variable avec le même nom est introduite, elle ne remplace pas, la compréhension de la liste agit comme un bac à sable pour une raison quelconque et semble créer une nouvelle portée.
et cette réponse va à l'encontre de la déclaration de answerer @ Thomas Le seul moyen de créer une portée est des fonctions, des classes ou des modules parce que cela ressemble à un autre endroit pour créer une nouvelle portée.
la source
Les modules (et packages) sont un excellent moyen pythonique de diviser votre programme en espaces de noms séparés, ce qui semble être un objectif implicite de cette question. En effet, alors que j'apprenais les bases de Python, je me sentais frustré par l'absence de fonctionnalité de portée de bloc. Cependant, une fois que j'ai compris les modules Python, je pourrais réaliser plus élégamment mes objectifs précédents sans avoir besoin d'une portée de bloc.
En tant que motivation et pour orienter les gens vers la bonne direction, je pense qu'il est utile de donner des exemples explicites de certaines des constructions de portée de Python. J'explique d'abord ma tentative infructueuse d'utiliser des classes Python pour implémenter la portée de bloc. Ensuite, j'explique comment j'ai réalisé quelque chose de plus utile en utilisant les modules Python. À la fin, je décris une application pratique des packages au chargement et au filtrage des données.
Tentative de portée de bloc avec des classes
Pendant quelques instants, j'ai pensé que j'avais atteint la portée du bloc en collant du code à l'intérieur d'une déclaration de classe:
Malheureusement, cela se décompose lorsqu'une fonction est définie:
C'est parce que les fonctions définies dans une classe utilisent une portée globale. Le moyen le plus simple (mais pas le seul) de résoudre ce problème est de spécifier explicitement la classe:
Ce n'est pas si élégant car il faut écrire les fonctions différemment selon qu'elles sont ou non contenues dans une classe.
De meilleurs résultats avec les modules Python
Les modules sont très similaires aux classes statiques, mais les modules sont beaucoup plus propres d'après mon expérience. Pour faire de même avec les modules, je crée un fichier appelé
my_module.py
dans le répertoire de travail courant avec le contenu suivant:Ensuite, dans mon fichier principal ou session interactive (par exemple Jupyter), je fais
Comme explication, chaque fichier Python définit un module qui a son propre espace de noms global. L'importation d'un module vous permet d'accéder aux variables de cet espace de noms avec la
.
syntaxe.Si vous travaillez avec des modules dans une session interactive, vous pouvez exécuter ces deux lignes au début
et les modules seront automatiquement rechargés lorsque leurs fichiers correspondants seront modifiés.
Packages de chargement et de filtrage des données
L'idée de packages est une légère extension du concept de modules. Un package est un répertoire contenant un
__init__.py
fichier (éventuellement vide) , qui est exécuté lors de l'importation. Les modules / packages de ce répertoire sont accessibles avec la.
syntaxe.Pour l'analyse des données, j'ai souvent besoin de lire un gros fichier de données, puis d'appliquer de manière interactive divers filtres. La lecture d'un fichier prend plusieurs minutes, donc je ne veux le faire qu'une seule fois. Sur la base de ce que j'ai appris à l'école sur la programmation orientée objet, j'avais l'habitude de penser qu'il fallait écrire le code de filtrage et de chargement en tant que méthodes dans une classe. Un inconvénient majeur de cette approche est que si je redéfinis ensuite mes filtres, la définition de ma classe change, donc je dois recharger toute la classe, y compris les données.
Aujourd'hui, avec Python, je définis un package appelé
my_data
qui contient des sous-modules nommésload
etfilter
. À l'intérieur defilter.py
je peux faire une importation relative:Si je modifie
filter.py
, puisautoreload
détectera les changements. Il ne se recharge pasload.py
, donc je n'ai pas besoin de recharger mes données. De cette façon, je peux prototyper mon code de filtrage dans un bloc-notes Jupyter, l'envelopper en tant que fonction, puis couper-coller de mon bloc-notes directement dansfilter.py
. Comprendre cela a révolutionné mon flux de travail et m'a converti de sceptique à un croyant au «Zen of Python».la source