如何确保变量进入局部范围?



我有一个情况,我想将所有局部变量传递给 Python 中的函数。但是,由于某种原因,在更新局部变量时,该变量不在范围内。这是 PyCharm 解释器的问题,还是我在这里缺少基础知识?

这是我目前正在做的一些伪代码:

def someFunction():
# Create local variable
my_local_variable = 'Hello World'
# Create a dictionary of all local variables
my_local_vars = dict(locals())
# Call my function with the dictionary
myOtherFunction(**my_local_vars)
def myOtherFunction(**args):
locals().update(args)
print(my_local_variable)

有什么想法吗?

编辑:由于存在关于为什么我需要该功能的问题,因此这是一个更大的问题:

我有一个代码生成器,需要生成等效的开关功能。他们这样做的方式是使用字典实现一个开关,如下所示:

def GeneratedFunction(self):
# Variable I want in scope
(my_local_variable) = Some_other_function()
# Begin Switch Statement: switch_SwitchDictionary_user_choice
switch_SwitchDictionary_user_choice = {}
switch_SwitchDictionary_user_choice["Choice 1"] = self.SwitchConnector_user_choice_is__Choice_1_
switch_SwitchConnector_user_choice["default"] = self.SwitchConnector_user_choice_is__default_
_localvars = dict(locals())
del _localvars['self']
if not (user_choice in switch_SwitchConnector_user_choice):
(returnVals) = switch_SwitchConnector_user_choice["default"](**_localvars)
else:
(returnVals) = switch_SwitchConnector_user_choice[user_choice](**_localvars)
locals().update(returnVals)

在继续之前,请注意以下事项:

建议以您想要的方式编辑局部变量,您应该谨慎行事,适当地重构代码将是一个更好的选择,以便您可以使用另一种技术(例如字典)或直接从args访问变量。


这是一条糟糕的路线,但我之前回答过类似的问题,您不能像globals那样编辑locals

def someFunction():
my_local_variable = 'Hello World'
my_local_vars = locals()
myOtherFunction(my_local_vars)
def myOtherFunction(args):
for arg in args:
locals()[arg] = args[arg]
print(locals())
someFunction()

这将导致:

{'arg': 'my_local_variable', 'args': {'my_local_variable': 'Hello World'}, 'my_local_variable': 'Hello World'}
Traceback (most recent call last):
File "python", line 12, in <module>
File "python", line 4, in someFunction
File "python", line 10, in myOtherFunction
NameError: name 'my_local_variable' is not defined

表明您确实可以编辑locals,但之后该变量将不可用,但这确实适用于globals

def someFunction():
my_local_variable = 'Hello World'
my_local_vars = locals()
myOtherFunction(my_local_vars)
def myOtherFunction(args):
for arg in args:
globals()[arg] = args[arg]
print(my_local_variable)
someFunction()
print(my_local_variable)

这将打印:

Hello World
Hello World

如果你不想污染global范围(你不应该),你可以在函数结束时删除它们:

def someFunction():
my_local_variable = 'Hello World'
my_local_vars = locals()
myOtherFunction(my_local_vars)
def myOtherFunction(args):
for arg in args:
globals()[arg] = args[arg]
print(my_local_variable)
...
# Do stuff
...
for arg in args:
del globals()[arg]
someFunction()
print(my_local_variable)

指纹:

Hello World
Traceback (most recent call last):
File "python", line 19, in <module>
NameError: name 'my_local_variable' is not defined

首选替代方案,包括使用字典代替或嵌套函数:

def someFunction():
def myOtherFunction():
print(my_local_variable)
my_local_variable = 'Hello World'
myOtherFunction()
someFunction()

您必须将切换器封装在一个对象中,并将局部变量发送或捕获到该对象的容器中。 这是最安全的方法,不会意外搞砸任何东西。 然后,您只有一个包含切换器对象的全局变量,并使用它来安全,安全地进行切换检查和填充。 您甚至可以为不同的情况使用不同的切换台,如果需要,您也可以在本地使用它们。

我必须告诉你,无论如何这样做是有风险的,应该避免吗?也可以动态创建变量。你应该为这些东西使用字典。 以这种方式弄乱口译员是不明智的,除非你非常清楚自己在做什么。 我什至不确定向您展示如何挖掘解释器堆栈在道德上是否正确。 :D 感觉不知何故违反了信任。:D


from thread import get_ident
import sys
class switcher:
def __init__ (self, vrs={}):
self.vrs = vrs.copy() # Copy them for security
self.__call__ = self.vrs.get
self.clear = self.vrs.clear
self.__getitem__ = self.vrs.__getitem__
self.__delitem__ = self.vrs.__delitem__
self.keys = self.vrs.keys
def fill (self, **kwargs):
"""
Manually fill the switcher().
If the switcher() is not new and you wish to use only here specified cases, use switcher.clear before fill().
"""
self.vrs.update(kwargs)
def autofill (self, clr=0):
"""
This method fills the switch flags with local variables defined in a scope from which it was called.
Variables inserted will be only those defined before calling switcher.autofill()
If you want to use only cases specified in these variables, set clr to True or
use switcher.clear() before calling this function.
Note: Variables containing switcher() instances won't be copied.
"""
if clr: self.clear()
tid = get_ident() # Thread safe
# Get interpreter frame from which autofill() was called:
lastfrm = sys._current_frames()[tid].f_back
# Snatch locals() in there and populate self.vrs:
for x in lastfrm.f_locals:
# Prevent adding ourselves to switches.
# If user insists uponit let him/her use switcher.fill() first.
if isinstance(lastfrm.f_locals[x], switcher):
continue
self.vrs[x] = lastfrm.f_locals[x]
def transfer (self, namespace=None):
"""
This method transfers variables saved in the switcher()'s container into the namespace dictionary.
Meant to use as this:
switcher.transfer(locals())
or
switcher.transfer(globals())
If namespace dictionary is not given or is None (default), variables will be transfered to a scope from which switcher.transfer() was called.
Be careful with this method. Overwriting variables with a same name from another scope may be disasterous.
Use switcher.keys() to check the names and del switcher[""] before calling this method to prevent overwriting existing variables.
"""
if not namespace:
tid = get_ident() # Thread safe
# Get interpreter frame from which transfer() was called:
lastfrm = sys._current_frames()[tid].f_back
# Snatch locals() in there
namespace = lastfrm.f_locals
for x in self.vrs:
namespace[x] = self.vrs[x]
# Usage:
switch = switcher()
def somefunc (somearg=1234, otherarg=False):
blablavar = "blabla"
def funcyfunc (arg=None):
print "Some switch option"
if arg: print arg
switch.autofill(True)
otherfunc()
def otherfunc ():
if switch("otherarg"):
print "yeeeey!!!!"
switch("funcyfunc")(12345)
print switch["blablavar"]
print switch("somearg")
somefunc()
somefunc(otherarg=True)
switch.transfer()
funcyfunc("I just got inserted into the global scope!!!! Finally free!")
As switcher() creates an object you can pass its pointer around instead of making it global:
def funcone ():
abc = 123
cde = 456
sw = switcher()
sw.autofill()
functwo(sw)
def functwo (switch):
print switch.keys()

最新更新