开发者

What is the best way to define local variables dynamically in a method

开发者 https://www.devze.com 2023-02-25 06:13 出处:网络
When I call a functio开发者_StackOverflown, I would like to be able to define dynamic variable names in the function, like so...

When I call a functio开发者_StackOverflown, I would like to be able to define dynamic variable names in the function, like so...

def build_ports(portlist):
    for idx, portname in enumerate(portlist):
        chassis, slot, port = portname.split('/') 
        vartxt = "p%i" % idx
        locals()[vartxt] = Port()  # Class defining a port object
        locals()[vartxt].port_method1(chassis, slot, port)
        if idx > 5:
            locals()[vartxt].port_method2()  # Only call this object method, if idx > 5

But we all know that locals() is read-only, unlike globals()... so the interpreter barfs when it sees locals()[vartxt]...

Is there any way to define dynamic variables in a method without polluting the global namespace (or worse, using a global variable in a method, when it was never defined in that method)?


Use lists instead of this insanity called variable variables.

def build_ports(portlist)
    ports = []
    for idx, portname in enumerate(portlist):
        ports.append(Port())
        ports[-1].port_method1()
        if idx > 5:
            ports[-1].port_method2()

Instead of using ports[-1], you might instead scrap the unused portname iteration variable and create a local portname = Port(), use that to call the methods and then append it to ports at the end. What is portlist anyway?


No, this is not possible. If you look at how Python stores local variables, you can see why.

Global variables are stored in a hash table, which is dynamically-sized, and the names are compiled into hash keys (in Python parlance, interned strings). This makes global lookups comparatively "slow", but since one needs to find globals by name from other compilation units (modules), it's required:

# a.py
x = 3

# b.py
import a
a.x = 4 # b needs to know how to find the same x!

Local variables are stored in a fixed-size array and the names are compiled into array indices.

This can be seen when you look at the bytecode, which has LOAD_FAST and STORE_FAST for locals but LOAD_GLOBAL and STORE_GLOBAL for globals. It also leaks through in the different exceptions you get. Globals trickle up and generate a NameError when not found, but undefined locals are detected by an empty slot, giving an UnboundLocalError.

def foo():
    a
    a = 1
foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in foo
UnboundLocalError: local variable 'a' referenced before assignment

def foo():
    a = 1
foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in foo
NameError: global name 'a' is not defined

Because the array is fixed-size, and the size is computed while compiling the function, you cannot create any additional locals.

If you need more "locals", you'll need to store the values as named attributes of an object or in a dictionary; obviously that will also negate the speed benefits.


Check out exec.

Edit: Yes, I meant exec.

0

精彩评论

暂无评论...
验证码 换一张
取 消