Is there an equivalent in Python from Fortran "implicit none"?

Fortran has an Implicit none statement that generates a compilation error when a local variable is not declared but used. I understand that Python is a dynamically typed language, and the scope of a variable can be determined at runtime.

But I would like to avoid some unforeseen errors that occur when I forget to initialize a local variable, but use it in the main code. For example, the variable x in the following code is global, although I did not assume that:

 def test(): y=x+2 # intended this x to be a local variable but forgot # x was not initialized print y x=3 test() 

So my question is: is there a way to guarantee that all the variables used in test() are local to it and that there are no side effects. I am using Python 2.7.x. If there is a local variable, an error is printed.

+8
python fortran
source share
8 answers

So, my question is: is there a way to ensure that all variables in test () are local to it and that there are no side effects.

There is a method to verify that global global objects are not available.

Here, the decorator that scans the function does the operations for LOAD_GLOBAL.

 import dis, sys, re, StringIO def check_external(func): 'Validate that a function does not have global lookups' saved_stdout = sys.stdout sys.stdout = f = StringIO.StringIO() try: dis.dis(func) result = f.getvalue() finally: sys.stdout = saved_stdout externals = re.findall('^.*LOAD_GLOBAL.*$', result, re.MULTILINE) if externals: raise RuntimeError('Found globals: %r', externals) return func @check_external def test(): y=x+2 # intended this x to be a local variable but forgot # x was not initialized print y 

To make this practical, you will need a list of stops of acceptable global references (i.e. modules). This technique can be extended to cover other opcodes such as STORE_GLOBAL and DELETE_GLOBAL.

All that said, I see no direct way to detect side effects.

+7
source share

In this sense, you do not mean None . The assignment will create a new variable, so a typo may introduce a new name in your scope.

One way to get the effect you want is to use the following ugly hack:

 def no_globals(func): if func.func_code.co_names: raise TypeError( 'Function "%s" uses the following globals: %s' % (func.__name__, ', '.join(func.func_code.co_names))) return func 

So, when you declare your test -with function with no_globals wrapper, you get an error, for example:

 >>> @no_globals ... def test(): ... y = x + 2 # intended this x to be a local variable but forgot ... # x was not initialized ... print y ... Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 5, in no_globals TypeError: Function "test" uses the following globals: x >>> >>> x = 3 >>> test() Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'test' is not defined 
+3
source share

Just avoid using global scope variables. And if you need to, attach their names to something that you will never use in the local variable name.

0
source share

In Python, this is pretty simple legal. In fact, this is the power of language! This (flaw) error is the reason you can do something like this:

 def function1(): # stuff here function2() def function2(): pass 

While in C you need to "forward the declaration" function2 .

There are static syntax checks (e.g. flake8 ) for Python that do a lot of work to catch errors and bad style, but this is not an error, and it is not caught by such a check. Otherwise, something like this would be an error:

 FILENAME = '/path/to/file' HOSTNAME = 'example.com' def main(): with open(FILENAME) as f: f.write(HOSTNAME) 

Or, something more substantial like this would be a mistake:

 import sys def main(): sys.stdout.write('blah') 

The best you can do is use another naming convention (like ALL_CAPS) to declare level-level variables. Also, make it a habit to put all your code in a function (without logic at the module level) to prevent variables from leaking into the global namespace.

0
source share

If you were really worried about this, you can try the following:

 def test(): try: x except: pass else: return y = x+2 print y 

But I would recommend just being careful when writing a function that you are not trying to reference things before assigning them. If possible, try testing each function separately using various carefully defined inputs and intended outputs. There are many testing kits and strategies , not to mention a simple assert .

0
source share

Is there a way to ensure that all the variables used in test () are local to it and that there are no side effects.

Not. The language does not offer such features.

There is a built-in function locals() . Therefore, you can write:

 y = locals()['x'] + 2 

but I can’t imagine anyone considering this an improvement.

0
source share

To make sure that the correct variable is used, you need to limit the scope of the search. Inside the function, Python will look for the arguments defined in the string, and then args and kwargs . After that, he will look outside the function. This can cause annoying errors if the function depends on a global variable that changes elsewhere.

To avoid accidentally using a global variable, you can define a function with a keyword argument for the variables that you intend to use:

 def test(x=None): y=x+2 # intended this x to be a local variable but forgot # x was not initialized print y x=3 test() 

I assume that you do not want to do this for many variables. However, this will stop the function from using global variables.

Actually, even if you want to use a global variable in a function , I think it's best to make it explicit:

 x = 2 def test(x=x): y=x+2 # intended this x to be a local variable but forgot # x was not initialized print y x=3 test() 

In this example, x = 2 will be used for the function, regardless of what happens to the global value of x after that. Inside the function x , the value it had at compile time is fixed.

I started passing global variables as keyword arguments after you burned a couple of times. I think this is usually considered good practice?

0
source share

The proposed solutions are interesting, especially the one that uses dis.dis , but you really think in the wrong direction. You do not want to write such cumbersome code.

  • Are you afraid that you will reach global by chance? Then do not write down the globals. The goal of global globals is basically to be achieved. (in the comment I read, you have 50 global areas, which seems to me that you have some design errors).

  • If you still need to have global variables, then either use a naming convention (it is recommended to use UPPER_CASE for constants that may cover your cases).

  • If the naming convention is also not an option, just put the functions that you do not want to use any global in a separate module, and do not define global values ​​there. For example, define pure_funcs and inside this module, write your "pure" functions and import this module. Since python has lexical scope, functions can only have reachability variables defined in the outer areas of the module they were written (and, of course, locales or built-in modules). Something like that:

     # Define no globals here, just the functions (which are globals btw) def pure1(arg1, arg2): print x # This will raise an error, no way you can mix things up. 
0
source share

All Articles