如何确保变量进入本地范围?

时间:2017-05-19 12:35:04

标签: python local-variables

我有一种情况,我想将所有局部变量传递给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)

2 个答案:

答案 0 :(得分:0)

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

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

这是一条不好的路线,但之前我回答过类似的问题,您无法以locals的方式编辑globals

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

答案 1 :(得分:0)

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

我必须告诉你,这样做有风险,应该避免吗?也动态创建变量。你应该使用字典来做这些事情。 除非你完全清楚自己在做什么,否则以这种方式与翻译混淆是不明智的。 我甚至不确定向你展示如何通过解释器堆栈进行挖掘是否在道德上是正确的。 :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()