In fact, python is a real dynamic language. The variable name in the Code is not "declared" or "defined, the language itself does not provide any special syntax for declaring or defining variables (except global ). For programmers, This is a benefit and a danger, such as the following code:
Count = Total = 1
Delta = 0.7
While total <1000:
Total + = delta * (count * count + Delta * delta)
Dalta = delta * 1.1
Count * = dalta
Print total
The dalta behind the code is the result of Delta spelling errors. The program can run correctly or use the pychecker tool to check, but its output is obviously far from the expected correct result. Many people think that strict in Perl or option explicit in Visual Basic can help programmers reduce the chance of similar errors (although I don't think so), but in Python, because there is no syntax to explicitly define or declare the variable name, this kind of force check seems difficult to start-some solutions can be found online, but it is complicated, or use _ slots __, decorator is not easy to use to solve some problems.
The abstract syntax tree provided by parser or compiler package can be used to solve this problem easily. I roughly wrote a piece of code named strict. py. To change your program to the "Security Code" that forces the declaration of variables, we only need to follow strict. PY requirements, use _ Decl _ = "name1 name2... "In this way, you can declare the variable name before using the simple syntax. For example, you can add:
_ Decl _ = "delta total count"
Then use strict. py to check the Code Section (assuming the file name is test. py ):
Python strict. py test. py
We can see in the running results:
File 'test. py', line 6: Name 'dalta 'is not declared.
You can easily find out the variable name dalta, Which is misspelled, because the name dalta is not "declared" in advance ".
Strict. PY can also check the local name (_ Decl _ = "... "Such declaration statements can be used in any position in the Code), can recognize from... import, global, or function parameter table. Code like the following:
_ Decl _ = 'name1 name2 name3'
Name1 = 1
Name2 = 'jack'
Name3 = name1 + 3
Def Foo ():
Global name1
_ Decl _ = 'local _ name1 local_name2'
Name1 + = 4
Local_name1 = 1.2
Local_name2 = 'Mike'
Undeclared = 9
Strict. py can quickly find out where undeclared is the "undeclared" name.
Strict. PY only checks the names (L-value) that serve as the target of the value assignment. For reading a name, call a function name through obj. when the ATTR syntax accesses attributes or members of an object, strict. PY does not need to be considered-If undefined names appear in these cases, an error will be reported during compilation or running of the program, without causing potential risks.
I only tested strict. py in the python 2.4.3 environment and did not perform more complex tests. This code must have many improvements. First, list the strict. py code below:
Strict. py
------------------------------------------------------
Import sys
Import Compiler
Declaration_flag = "_ Decl __"
Def find_undeclared_names (AST, frames, is_decl ):
Next_frames = Frames
Def add_name (name ):
Frames [-1] [name] = true
Def find_name (name ):
Return frames [-1]. has_key (name)
Def get_alias (name_pair ):
If name_pair [1] is none:
Return name_pair [0]
Else:
Return name_pair [1]
If ast. _ class _. _ name _ = "assname ":
If not is_decl [0] and AST. Name = declaration_flag:
Is_decl [0] = true
Elif not find_name (AST. Name ):
Yield ast. Name, AST. lineno
Elif ast. _ class _. _ name _ = "Global ":
Map (add_name, AST. Names)
Elif ast. _ class _. _ name _ = "from ":
If (AST. Names [0] [0] = "*"):
MoD = _ import _ (AST. modname)
Map (add_name, filter (lambda X: Not X. startswith ('_'), Dir (MOD )))
Else:
Map (add_name, map (get_alias, AST. Names ))
Elif ast. _ class _. _ name _ = "const ":
If is_decl [0] and AST. value. _ class _. _ name _ = "str ":
Map (add_name, AST. value. Split ())
Is_decl [0] = false
Elif ast. _ class _. _ name _ = "function ":
Next_frames = frames + [dict (MAP (lambda X: (x, true), AST. argnames)]
Elif ast. _ class _. _ name _ = "class ":
Next_frames = frames + [{}]
For childnode in AST. getchildnodes ():
For X in find_undeclared_names (childnode, next_frames, is_decl ):
Yield x
If _ name _ = "_ main __":
If Len (SYS. argv )! = 2:
Print "Usage: Python strict. py <Python-source-File>"
Else:
For name, line_no in/
Find_undeclared_names (compiler. parsefile (SYS. argv [1]),
[{}],
[False]):
Print "File '% s', line % d: name' % s' is not declared." %/
(SYS. argv [1], line_no, name)