I've been using Python for some years and think I know the basics of Python. One thing that happened today helped me learn more about Python and write an article to record it.
My colleague asked me to help you look at the following code section, the specific content and function name can not be too concerned about, naming made some special treatment, but does not affect the code logic and the meaning to be expressed.
When node_type is fb in the for loop, the FBX object is returned as a global variable DUT (the content of node_name is the string dut), and then print dut, with an error.
def setup_module(module): with step('Set_setup'): function_1_run(topo_info) function_2_run(topo_info) function_3_run(topo_info, set_resource, 'device_config') for node in topo_info.nodes: if node.type == 'fb': globals()[node.name] = FBX(node.manage_ip,'admin','111111') print node.name print globals()[node.name] print dut else: globals()[node.name] = Device() globals()[node.name].node_info = node if not get_config_file(topo_info, set_resource, 'device_config'): test = dut print test with cli_ctx(dut) as dut: dut.cli.cmd_list = \ [ 'configure', 'interface fastEthernet 2', 'ip address 192.168.1.5/24' ] dut.cli.exec_cmd() log.info('cli_ctx 1 end') export_firebox_topo(topo_info, set_resource, 'device_config')
The error message is as follows:
==================================== ERRORS ==================================== ___________________ ERROR at setup of some_module_1 ___________________ module = <module 'some_name_python' from '/path/to/file/some_name_python.py'> def setup_module(module): with step('Set_setup'): function_1_run(topo_info) function_2_run(topo_info) function_3_run(topo_info, set_resource, 'device_config') for node in topo_info.nodes: if node.type == 'fb': globals()[node.name] = FBX(node.manage_ip,'admin','111111') print node.name print globals()[node.name] > print dut E UnboundLocalError: local variable 'dut' referenced before assignment some_name_python.py:54: UnboundLocalError ========================== 1 error in 155.62 seconds ===========================
Colleagues mentioned that if you remove the block with cli_ctx as dut, the code will execute normally.
My first reaction here was a problem with the scope of the variable, but I couldn't tell you what it was. So I suggested that my colleague change the code of the context manager to with cli_ctx as d to try again if there was a problem, and I continued searching the Internet for relevant reasons, and then combined the results with theory to analyze the cause of the problem.
Fortunately, after the code was modified, it worked fine, and I found articles explaining the problem. My first impression was that it was really a variable scoping problem. During the code execution, print dut actually accessed the Local variable, not the global variable dut we expected.
Referring to Python's official documentation and searches, the specific reasons are summarized below.
- When searching for a variable, start with the local scope. If the variable is not found in the local scope, it will be found in the global variable, and if the exception thrown Unbound-LocalError cannot be found.
- If an internal function has a variable with the same name or a global variable that references an external function and modifies the variable, python considers it a local variable.An error occurred because the definition of a variable is outside the code block and there is no definition or assignment of a variable in the current code block.
- In our code, the global variable dut was created, but because context manager cli_ctx assigns the variable dut in the function code block, dut becomes a local variable instead of a global variable in the function block.
- The assignment of a variable = is an obvious statement, and the other not so obvious assignments are assignments in the for loop, assignments in the except statement, and vars in with...as...{var}.
Big pit, the foundation is not strong enough or not.
Reference
Python 2.7.13 Documentation - Language Reference - 4. Execution Model
Stackoverflow - Short Description of the Scoping Rules?