Does python have a “use strict;” and “use warnings;” like in perl?

旧时模样 提交于 2019-12-02 21:01:55
LeoNerd

To provide an answer that perhaps avoids a little of the commentary noise here, I'll try another one.

The two pragmata in your original question really expand to:

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

To answer each in turn:

  • The effect of use strict "vars" is to cause a compile-time error to refer to a variable without first declaring that it exists (such as is the default in more static languages such as C, C++ and Java). Because Python does not have specific syntax to declare that a variable exists, it has no equivalent. Assigning to a name in Python always creates it if it didn't exist first. This feature of strict has no Python equivalent and the safety it provides cannot be recreated.

Eg:

$ 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
  • The effect of use strict "refs" is to disallow the use of plain strings containing the name of an (existing or new) variable as a reference to the variable itself. Python does not do this so has no need to disable it.

Eg:

$ 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
  • The effect of use strict "subs" is to cause a compile-time any attempt to call a function that is known not to exist. Python does not perform any such checking, and has no way to enable such a feature.

Eg:

$ 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
  • The effect of use warnings is to enable more warnings at both compile- and runtime of various categories of behaviour that was default in earlier versions, may at times be desired, or which has never been a good idea but isn't strictly an error. For example, the use of uninitialised values as numbers ought usually to give a warning, but originally it did not do so.

Eg:

$ 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

Finally; some comments have been made that Python has similar functionality in __future__. However, this should not be considered similar to Perl's pragmata, as most of the latter are lexically-scoped, and can be enabled or disabled within small scopes as required; where's Python's __future__ is only enabled for an entire source file.

Eg.

use strict;
use warnings;

my $total;

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

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

A somewhat-contrived example, but this one demonstrates the use of no warnings 'uninitialized' to disable the warning about using an uninitialised value simply within the printf statement, while still keeping the other warnings enabled everywhere else.


In summary then: Python does not have a use strict or any near-equivalent as any of the safety features it provides are either mandatory or not available in the Python language, and does not have a use warnings. Those features it does provide are enabled only at the file-level and cannot be selectively enabled or disabled per scope.


Edit: Actually I have now been informed that Python does have some controllable warning flags, that can be enabled and disabled as required.

As other users have posted, Python has no strict pragma. And this, in my opinion is one of its biggest deficiencies. Moreover, it is one of the reasons that, for serious programming projects, I still use Perl.

There will no doubt be Python devotees that take umbrage with this statement. I have heard some say that they don't need strict. I find that those that say this typically don't know what strict buys you. Consider the following code block in 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 __name__ == '__main__': Main()

This code computes the cost for purchases including sales tax. Granted there are more efficient ways to do this, but it is only an illustration.

So, do you see anything wrong with the code? No? Try running it. When you do you get:

100
106.0
100
105.0

Still don't see an problem? Then you've got a bigger problem than you know. Here is the equivalent code rendered in 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();

Without Perl's strict pragma enabled, you even get the identical output:

100
106.0
100
105.0

But with strict turned on, you get the following error message when you run this Perl script:

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

The problem in both examples is that there is a typo in one of the computation lines. I have "StateSalesTexRate" instead of "StateSalesTaxRate" for the line computing sales tax for the state of Michigan. Perl finds and squashes this bug explicitly. Meanwhile, Python turns its head and looks the other way.

This is a big deal. Imagine this software is being used by your online business to calculate how much you charge a customer's credit card. How long will it take before you realize Michigan customers are getting a pass on sales tax? When you do, do you go back to the customer and say "Sorry, we need more money from you" or do you eat the loss yourself?

Of course any company using this type of coding algorithm to compute sales tax probably has bigger problems. But you can clearly see by this example what the strict pragma in Perl does and why I and others believe it should be an essential feature of any scripting language.

There are lots of things that I really like about Python. I get why some people prefer Python to Perl. But there are a few things that I truly detest about Python. This is one.

To run Python with warnings turned on:

python -W all file.py

In response to:

Is there something I should be doing on routine for my python scripts?

I think it's generally a good idea to make sure your code is compliant with PEP 8. As alluded to in another answer, you can do this programatically:

pip install pep8 && pep8 file.py
Sean

LeoNerd's provides a great explanation as to why there is no 'use strict' or 'use warnings' in Python.

In answer to:

Is there something I should be doing on routine for my python scripts?

You may be interested in running your code through a static code analyser like pylint, and/or a code formatting check such as pep8.

They can help to find potential problems, and flag warnings. They also have a lot to say about the formatting of your code, which you may or may not be interested in.

Here is a decent rationale for their use. And related Stackoverflow questions here and here.

There isn't really any equivalent. Python's design has evolved over time, and many changes have been made (particularly in 3.x) to make sure that the defaults in the language are what a developer wants by default. It's very rare for a feature to exist but be an optional flag.

This probably comes down to The Zen of Python's 'There should be one-- and preferably only one --obvious way to do it.' Python's design is focussed around readability, and having many ways of doing things or changing the way the language works makes code harder to read.

The closest, I would argue, is imports from __future__ in older versions of Python to introduce some fixes/new features from newer versions into older versions (such as division going from integer to float division by default). This is similar in the sense that it is improving the default behaviour to be more sensible in the standard case.

Edit: I seem to have attracted ire from perl users who see this post as an attack on Perl - it was never intended as such. Perl is a fine language, my original post just used poor wording and wasn't clear in it's explanation. I have attempted to clarify.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!