web-dev-qa-db-fra.com

python a-t-il un "use strict;" et "use warnings;" like in perl?

J'apprends Perl et python ... en même temps, pas par ma conception mais cela doit être fait.

Question:

Dans un script Perl que j'utilise (voir ci-dessous) en tête de mon txt.

#!/usr/bin/env Perl

use strict;
use warnings;

Y a-t-il quelque chose que je devrais faire sur la routine pour mes scripts python?

51
jon_shep

Pour fournir une réponse qui évite peut-être un peu le bruit des commentaires ici, je vais essayer une autre.

Les deux pragmata de votre question initiale s'étendent vraiment à:

use strict "vars";
use strict "refs";
use strict "subs";
use warnings;

Pour répondre chacun à son tour:

  • L'effet de use strict "vars" doit provoquer une erreur au moment de la compilation pour faire référence à une variable sans d'abord déclarer qu'elle existe (comme c'est le cas par défaut dans les langages plus statiques tels que C, C++ et Java). Parce que Python n'a pas de syntaxe spécifique pour déclarer qu'une variable existe, elle n'a pas d'équivalent. L'affectation à un nom dans Python le crée toujours s'il ne l'a pas fait) Cette fonctionnalité de strict n'a pas Python équivalent et la sécurité qu'il offre ne peut pas être recréée.

Par exemple:

$ Perl -c -e 'use strict "vars"; $foo = 1'
Global symbol "$foo" requires explicit package name at -e line 1.
-e had compilation errors.

$ Perl -c -e 'no strict "vars"; $foo = 1'
-e syntax OK
  • L'effet de use strict "refs" est d'interdire l'utilisation de chaînes simples contenant le nom d'une variable (existante ou nouvelle) comme référence à la variable elle-même. Python ne fait pas cela donc n'a pas besoin de le désactiver.

Par exemple:

$ Perl -e 'use strict "refs"; ${"message"} = "hello"; print $message'
Can't use string ("message") as a SCALAR ref while "strict refs" in use at -e line 1.

$ Perl -e 'no strict "refs"; ${"message"} = "hello"; print $message'
hello
  • L'effet de use strict "subs" doit provoquer une compilation lors de toute tentative d'appel d'une fonction dont on sait qu'elle n'existe pas. Python n'effectue aucune vérification de ce type et n'a aucun moyen d'activer une telle fonctionnalité.

Par exemple:

$ Perl -c -e 'use strict "subs"; foo'
Bareword "foo" not allowed while "strict subs" in use at -e line 1.
-e had compilation errors.

$ Perl -c -e 'no strict "subs"; foo'
-e syntax OK
  • L'effet de use warnings est d'activer plus d'avertissements lors de la compilation et de l'exécution de diverses catégories de comportements qui étaient par défaut dans les versions antérieures, peuvent parfois être souhaités ou ce qui n'a jamais été une bonne idée mais n'est pas strictement une erreur. Par exemple, l'utilisation de valeurs non initialisées en tant que nombres devrait généralement donner un avertissement, mais ce n'était pas le cas à l'origine.

Par exemple:

$ Perl -e 'use warnings; my $u; print 2 + $u'
Use of uninitialized value $u in addition (+) at -e line 1.
2

$ Perl -e 'no warnings; my $u; print 2 + $u'
2

Finalement; certains commentaires ont été faits que Python a des fonctionnalités similaires dans __future__. Cependant, cela ne doit pas être considéré comme similaire aux pragmata de Perl, car la plupart de ces derniers ont une portée lexicale et peuvent être activés ou désactivés dans de petites étendues selon les besoins; où est Python __future__ n'est activé que pour un fichier source entier.

Par exemple.

use strict;
use warnings;

my $total;

$total += count_things($_) for @list;

{
   no warnings 'uninitialized';
   printf "The total is %d\n", $total;
}

Un exemple quelque peu artificiel, mais celui-ci montre l'utilisation de no warnings 'uninitialized' pour désactiver l'avertissement concernant l'utilisation d'une valeur non initialisée simplement dans l'instruction printf, tout en conservant les autres avertissements activés partout ailleurs.


En résumé, alors: Python n'a pas de use strict ou tout équivalent équivalent, car les fonctions de sécurité qu'il fournit sont obligatoires ou non disponibles dans la langue Python, et n'ont pas de use warnings. Les fonctionnalités qu'il fournit ne sont activées qu'au niveau du fichier et ne peuvent pas être activées ou désactivées de manière sélective par portée.


Edit: En fait, j'ai maintenant été informé que Python possède des indicateurs d'avertissement contrôlables, qui peuvent être activés et désactivés selon les besoins.

52
LeoNerd

Comme d'autres utilisateurs l'ont signalé, Python n'a pas de pragma strict. Et cela, à mon avis, est l'une de ses plus grandes lacunes. De plus, c'est l'une des raisons pour lesquelles, pour les projets de programmation sérieux, je utilisez toujours Perl.

Il y aura sans aucun doute Python dévots qui prennent ombrage avec cette déclaration. J'ai entendu certains dire qu'ils n'ont pas besoin de stricte. Je trouve que ceux qui disent cela ne savent généralement pas ce qui est strict vous achète. Considérez le bloc de code suivant en Python:

def Main():
    print(GetPrice(100,"Alaska"))
    print(GetPrice(100,"Florida"))
    print(GetPrice(100,"Michigan"))
    print(GetPrice(100,"Wisconsin"))

def GetPrice(UnitPrice,State):
    StateSalesTaxRate = 0
    if State == "Alabama": StateSalesTaxRate = 0.04
    if State == "Alaska": StateSalesTaxRate = 0
    if State == "Arizona": StateSalesTaxRate = 0.056
    if State == "Arkansas": StateSalesTaxRate = 0.065
    if State == "California": StateSalesTaxRate = 0.075
    if State == "Colorado": StateSalesTaxRate = 0.029
    if State == "Connecticut": StateSalesTaxRate = 0.0635
    if State == "Delaware": StateSalesTaxRate = 0
    if State == "Florida": StateSalesTaxRate = 0.06
    if State == "Georgia": StateSalesTaxRate = 0.04
    if State == "Guam": StateSalesTaxRate = 0.04
    if State == "Hawaii": StateSalesTaxRate = 0.04
    if State == "Idaho": StateSalesTaxRate = 0.06
    if State == "Illinois": StateSalesTaxRate = 0.0625
    if State == "Indiana": StateSalesTaxRate = 0.07
    if State == "Iowa": StateSalesTaxRate = 0.06
    if State == "Kansas": StateSalesTaxRate = 0.0615
    if State == "Kentucky": StateSalesTaxRate = 0.06
    if State == "Louisiana": StateSalesTaxRate = 0.04
    if State == "Maine": StateSalesTaxRate = 0.055
    if State == "Maryland": StateSalesTaxRate = 0.06
    if State == "Massachusetts": StateSalesTaxRate = 0.0625
    if State == "Michigan": StateSalesTexRate = 0.06
    if State == "Minnesota": StateSalesTaxRate = 0.06875
    if State == "Mississippi": StateSalesTaxRate = 0.07
    if State == "Missouri": StateSalesTaxRate = 0.04225
    if State == "Montana": StateSalesTaxRate = 0
    if State == "Nebraska": StateSalesTaxRate = 0.055
    if State == "Nevada": StateSalesTaxRate = 0.0685
    if State == "New Hampshire": StateSalesTaxRate = 0
    if State == "New Jersey": StateSalesTaxRate = 0.07
    if State == "New Mexico": StateSalesTaxRate = 0.05125
    if State == "New York": StateSalesTaxRate = 0.04
    if State == "North Carolina": StateSalesTaxRate = 0.0475
    if State == "North Dakota": StateSalesTaxRate = 0.05
    if State == "Ohio": StateSalesTaxRate = 0.0575
    if State == "Oklahoma": StateSalesTaxRate = 0.045
    if State == "Oregon": StateSalesTaxRate = 0
    if State == "Pennsylvania": StateSalesTaxRate = 0.06
    if State == "Puerto Rico": StateSalesTaxRate = 0.105
    if State == "Rhode Island": StateSalesTaxRate = 0.07
    if State == "South Carolina": StateSalesTaxRate = 0.06
    if State == "South Dakota": StateSalesTaxRate = 0.04
    if State == "Tennessee": StateSalesTaxRate = 0.07
    if State == "Texas": StateSalesTaxRate = 0.0625
    if State == "Utah": StateSalesTaxRate = 0.0595
    if State == "Vermont": StateSalesTaxRate = 0.06
    if State == "Virginia": StateSalesTaxRate = 0.053
    if State == "Washington": StateSalesTaxRate = 0.065
    if State == "West Virginia": StateSalesTaxRate = 0.06
    if State == "Wisconsin": StateSalesTaxRate = 0.05
    if State == "Wyoming": StateSalesTaxRate = 0.04
    return(UnitPrice*(1+StateSalesTaxRate))

if __== '__main__': Main()

Ce code calcule le coût des achats, y compris la taxe de vente. Certes, il existe des moyens plus efficaces de le faire, mais ce n'est qu'une illustration.

Alors, voyez-vous quelque chose de mal avec le code? Non? Essayez de l'exécuter. Lorsque vous obtenez:

100
106.0
100
105.0

Vous ne voyez toujours pas de problème? Vous avez alors un problème plus grave que vous ne le pensez. Voici le code équivalent rendu en Perl:

use strict;

sub Main
{
    print GetPrice(100,"Alaska"), "\n";
    print GetPrice(100,"Florida"), "\n";
    print GetPrice(100,"Michigan"), "\n";
    print GetPrice(100,"Wisconsin"), "\n";    
}

sub GetPrice
{
    my($UnitPrice,$State) = @_;
    my $StateSalesTaxRate = 0;
    $StateSalesTaxRate = 0.04 if $State eq "Alabama";
    $StateSalesTaxRate = 0 if $State eq "Alaska";
    $StateSalesTaxRate = 0.056 if $State eq "Arizona";
    $StateSalesTaxRate = 0.065 if $State eq "Arkansas";
    $StateSalesTaxRate = 0.075 if $State eq "California";
    $StateSalesTaxRate = 0.029 if $State eq "Colorado";
    $StateSalesTaxRate = 0.0635 if $State eq "Connecticut";
    $StateSalesTaxRate = 0 if $State eq "Delaware";
    $StateSalesTaxRate = 0.06 if $State eq "Florida";
    $StateSalesTaxRate = 0.04 if $State eq "Georgia";
    $StateSalesTaxRate = 0.04 if $State eq "Guam";
    $StateSalesTaxRate = 0.04 if $State eq "Hawaii";
    $StateSalesTaxRate = 0.06 if $State eq "Idaho";
    $StateSalesTaxRate = 0.0625 if $State eq "Illinois";
    $StateSalesTaxRate = 0.07 if $State eq "Indiana";
    $StateSalesTaxRate = 0.06 if $State eq "Iowa";
    $StateSalesTaxRate = 0.0615 if $State eq "Kansas";
    $StateSalesTaxRate = 0.06 if $State eq "Kentucky";
    $StateSalesTaxRate = 0.04 if $State eq "Louisiana";
    $StateSalesTaxRate = 0.055 if $State eq "Maine";
    $StateSalesTaxRate = 0.06 if $State eq "Maryland";
    $StateSalesTaxRate = 0.0625 if $State eq "Massachusetts";
    $StateSalesTexRate = 0.06 if $State eq "Michigan";
    $StateSalesTaxRate = 0.06875 if $State eq "Minnesota";
    $StateSalesTaxRate = 0.07 if $State eq "Mississippi";
    $StateSalesTaxRate = 0.04225 if $State eq "Missouri";
    $StateSalesTaxRate = 0 if $State eq "Montana";
    $StateSalesTaxRate = 0.055 if $State eq "Nebraska";
    $StateSalesTaxRate = 0.0685 if $State eq "Nevada";
    $StateSalesTaxRate = 0 if $State eq "New Hampshire";
    $StateSalesTaxRate = 0.07 if $State eq "New Jersey";
    $StateSalesTaxRate = 0.05125 if $State eq "New Mexico";
    $StateSalesTaxRate = 0.04 if $State eq "New York";
    $StateSalesTaxRate = 0.0475 if $State eq "North Carolina";
    $StateSalesTaxRate = 0.05 if $State eq "North Dakota";
    $StateSalesTaxRate = 0.0575 if $State eq "Ohio";
    $StateSalesTaxRate = 0.045 if $State eq "Oklahoma";
    $StateSalesTaxRate = 0 if $State eq "Oregon";
    $StateSalesTaxRate = 0.06 if $State eq "Pennsylvania";
    $StateSalesTaxRate = 0.105 if $State eq "Puerto Rico";
    $StateSalesTaxRate = 0.07 if $State eq "Rhode Island";
    $StateSalesTaxRate = 0.06 if $State eq "South Carolina";
    $StateSalesTaxRate = 0.04 if $State eq "South Dakota";
    $StateSalesTaxRate = 0.07 if $State eq "Tennessee";
    $StateSalesTaxRate = 0.0625 if $State eq "Texas";
    $StateSalesTaxRate = 0.0595 if $State eq "Utah";
    $StateSalesTaxRate = 0.06 if $State eq "Vermont";
    $StateSalesTaxRate = 0.053 if $State eq "Virginia";
    $StateSalesTaxRate = 0.065 if $State eq "Washington";
    $StateSalesTaxRate = 0.06 if $State eq "West Virginia";
    $StateSalesTaxRate = 0.05 if $State eq "Wisconsin";
    $StateSalesTaxRate = 0.04 if $State eq "Wyoming";
    return($UnitPrice*(1+$StateSalesTaxRate));
}

Main();

Sans le pragma strict de Perl activé, vous obtenez même la sortie identique:

100
106.0
100
105.0

Mais avec strict activé, vous obtenez le message d'erreur suivant lorsque vous exécutez ce script Perl:

Global symbol "$StateSalesTexRate" requires explicit package name at line 37.
Execution aborted due to compilation errors. 

Le problème dans les deux exemples est qu'il y a une faute de frappe dans l'une des lignes de calcul. J'ai "StateSalesTexRate" au lieu de "StateSalesTaxRate" pour la ligne de calcul de la taxe de vente pour l'État du Michigan. Perl trouve et écrase explicitement ce bogue. Pendant ce temps, Python tourne la tête et regarde dans l'autre sens.

Ceci est une grosse affaire. Imaginez que ce logiciel soit utilisé par votre entreprise en ligne pour calculer combien vous facturez la carte de crédit d'un client. Combien de temps cela prendra-t-il avant de réaliser que les clients du Michigan obtiennent un laissez-passer sur la taxe de vente? Lorsque vous le faites, retournez-vous au client et dites "Désolé, nous avons besoin de plus d'argent de votre part" ou mangez-vous la perte vous-même?

Bien sûr, toute entreprise utilisant ce type d'algorithme de codage pour calculer la taxe de vente a probablement de plus gros problèmes. Mais vous pouvez clairement voir par cet exemple ce que fait le pragma strict en Perl et pourquoi moi et d'autres pensons que cela devrait être une caractéristique essentielle de tout langage de script.

Il y a beaucoup de choses que j'aime vraiment à propos de Python. Je comprends pourquoi certaines personnes préfèrent Python à Perl. Mais il y a quelques choses que je déteste vraiment à propos de Python. En voici une.

28
Rodney Kadura

Pour exécuter Python avec des avertissements activés:

python -W all file.py

En réponse à:

Y a-t-il quelque chose que je devrais faire sur la routine pour mes scripts python?

Je pense que c'est généralement une bonne idée de s'assurer que votre code est conforme à PEP 8 . Comme mentionné dans une autre réponse, vous pouvez le faire par programme:

pip install pep8 && pep8 file.py
8
Jian

LeoNerd fournit une excellente explication de la raison pour laquelle il n'y a pas d'utilisation stricte ou d'avertissement d'utilisation en Python.

En réponse à:

Y a-t-il quelque chose que je devrais faire sur la routine pour mes scripts python?

Vous pouvez être intéressé par l'exécution de votre code via un analyseur de code statique comme pylint et/ou une vérification de formatage de code telle que pep8.

Ils peuvent aider à trouver des problèmes potentiels et à signaler des avertissements. Ils ont également beaucoup à dire sur le formatage de votre code, qui peut vous intéresser ou non.

Voici une justification décente de leur utilisation. Et les questions Stackoverflow connexes ici et ici .

5
Sean

Il n'y a pas vraiment d'équivalent. La conception de Python a évolué au fil du temps, et de nombreuses modifications ont été apportées (en particulier dans 3.x) pour s'assurer que les paramètres par défaut du langage correspondent à ce que veut un développeur par défaut. Il est très rare qu'une fonctionnalité existe mais soit un indicateur optionnel.

Cela revient probablement à Le Zen de Python 'Il devrait y avoir une - et de préférence une seule - manière évidente de le faire.' La conception de Python est axée sur la lisibilité, et avoir de nombreuses façons de faire les choses ou de changer la façon dont le langage fonctionne rend le code plus difficile à lire.

Je dirais que le plus proche est celui des importations en provenance de __future__ dans les anciennes versions de Python pour introduire des correctifs/nouvelles fonctionnalités des versions plus récentes dans les versions plus anciennes (comme la division allant de l'entier à la division flottante par défaut). Ceci est similaire dans le sentiment qu'il améliore le comportement par défaut pour être plus sensible dans le cas standard.

Edit: Il me semble avoir attiré la colère des utilisateurs de Perl qui voient ce post comme une attaque contre Perl - il n'a jamais été conçu comme tel. Perl est un beau langage, mon message d'origine vient d'utiliser une mauvaise formulation et n'était pas clair dans son explication. J'ai essayé de clarifier.

0
Gareth Latty