修改函数参数

时间:2017-07-14 20:21:15

标签: python function arguments

很抱歉,如果这是一个愚蠢的问题,但我已经找了一段时间而没有真正找到答案。

如果我正在编写python函数,例如:

def function(in1, in2):
    in1=in1+1
    in2=in2+1

如何更改这些更改?

我知道他们为什么不这样做,这已经在许多答案中得到解决,但我找不到如何让他们这样做的问题的答案。如果没有返回值或创建某种类,那么函数是否真的无法在全局意义上对其参数进行操作?

我也希望这些变量本身不是全局的,因为我希望能够做到这一点:

a=1
b=2
c=3
d=4
function(a,b)
function(c,d)

这只是一厢情愿的想法吗?

3 个答案:

答案 0 :(得分:10)

可以这样做,但我警告你 - 它不会很漂亮!你可以做的是捕获你的函数中的调用者框架,然后拿起调用行,解析它并提取传递的参数,然后将它们与你的函数签名进行比较并创建一个参数图,然后调用你的函数和你的函数完成比较本地堆栈中的更改并使用映射的更改更新调用方框架。如果你想看看它有多么愚蠢,这里有一个演示:

# HERE BE DRAGONS
# No, really, here be dragons, this is strictly for demonstration purposes!!!
# Whenever you use this in code a sweet little pixie is brutally killed!

import ast
import inspect
import sys

def here_be_dragons(funct):  # create a decorator so we can, hm, enhance 'any' function
    def wrapper(*args, **kwargs):
        caller = inspect.getouterframes(inspect.currentframe())[1]  # pick up the caller
        parsed = ast.parse(caller[4][0], mode="single")  # parse the calling line
        arg_map = {}  # a map for our tracked args to establish global <=> local link
        for node in ast.walk(parsed):  # traverse the parsed code...
            # and look for a call to our wrapped function
            if isinstance(node, ast.Call) and node.func.id == funct.__name__:
                # loop through all positional arguments of the wrapped function
                for pos, var in enumerate(funct.func_code.co_varnames):
                    try:  # and try to find them in the captured call
                        if isinstance(node.args[pos], ast.Name):  # named argument!
                            arg_map[var] = node.args[pos].id  # add to our map
                    except IndexError:
                        break  # no more passed arguments
                break  # no need for further walking through the ast tree
        def trace(frame, evt, arg):  # a function to capture the wrapped locals
            if evt == "return":  # we're only interested in our function return
                for arg in arg_map:  # time to update our caller frame
                    caller[0].f_locals[arg_map[arg]] = frame.f_locals.get(arg, None)
        profile = sys.getprofile()  # in case something else is doing profiling
        sys.setprofile(trace)  # turn on profiling of the wrapped function
        try:
            return funct(*args, **kwargs)
        finally:
            sys.setprofile(profile)  # reset our profiling
    return wrapper

现在你可以轻松地装饰你的功能,使它能够执行这种不敬虔的讽刺:

# Zap, there goes a pixie... Poor, poor, pixie. It will be missed.
@here_be_dragons
def your_function(in1, in2):
    in1 = in1 + 1
    in2 = in2 + 1

现在,示范:

a = 1
b = 2
c = 3
d = 4
# Now is the time to play and sing along: Queen - A Kind Of Magic...
your_function(a, b)  # bam, two pixies down... don't you have mercy?
your_function(c, d)  # now you're turning into a serial pixie killer...

print(a, b, c, d)  # Woooo! You made it! At the expense of only three pixie lives. Savage!
# prints: (2, 3, 4, 5)

这显然只适用于具有位置参数的非嵌套函数,并且只有当您传递简单的本地参数时,才可以自由地处理关键字参数,不同堆栈,返回/包装/链接调用的漏洞,和其他恶作剧,如果这是你想要的。

或者,您知道,您可以使用为此发明的结构,如全局变量,类,甚至是封闭的可变对象。并停止谋杀小精灵。

答案 1 :(得分:3)

如果您想要修改变量的值,可以使用代码

def func(a,b):
    int1 = a + 2
    int2 = b + 3
    return int1,int2

a = 2
b = 3
a,b = func(a,b)

这允许您使用该函数实际更改ab变量的值。

答案 2 :(得分:1)

你可以这样做:

def function(in1, in2):
   return  in1 + 1 , in2 + 1

a, b = function(a,b)
c, d = function(c,d)

python函数已关闭 - &gt;当函数(a,b)被调用时,a和b被重新赋值给本地(函数)引用/指针in1和in2,它们在函数外部是不可访问的。提供对那些没有使用全局变量的新值的引用,你需要通过返回传递回来。

当您将数组或非基本对象传递给函数时,您可以修改对象的属性,并使这些修改对于该对象的外部其他引用可见,因为该对象本身包含指向这些值的指针,使其他任何指向该对象的指针都可见。