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

Python 如何确保变量进入局部范围?,python,local-variables,Python,Local Variables,我有一种情况,我想在Python中将所有局部变量传递给一个函数。但是,由于某些原因,在更新局部变量时,该变量不在范围内。这是PyCharm解释器的问题,还是我在这里遗漏了基本原理 下面是我目前正在做的一些伪代码: def someFunction(): # Create local variable my_local_variable = 'Hello World' # Create a dictionary of all local variables my_

我有一种情况,我想在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
访问变量


这是一条不好的路线,但我以前回答过一个类似的问题,你不能像编辑全球数据一样编辑本地数据:

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()
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)
这将导致:

{'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
将打印:

Hello World
Hello World
如果您不想污染
全局
范围(您不应该这样做),您可以在函数末尾删除它们:

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

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

我必须告诉你这样做是有风险的,应该避免吗?也可以动态创建变量。你应该用字典来解释这些东西。 以这种方式和翻译打交道是不明智的,除非你非常清楚自己在做什么。 我甚至不确定向你们展示如何挖掘解释器堆栈在道德上是否正确不知何故,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()



locals()
:注意:不应修改本词典的内容;更改可能不会影响解释器使用的局部变量和自由变量的值。同意。。。但是,在作用域中获取变量的“更好”方法是什么?为什么不简单地
args['my\u local\u variable']
?这是一个简单的例子。在我的真实代码中,我事先不知道变量名。。。因为这是动态代码。我更喜欢尝试将作用域中的所有变量传递给函数。如果您甚至不知道变量名称,那么您绝对不应该玩弄局部变量。改为检查
dict
的内容。


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()