修改函数参数

2024-03-28 18:33:14 发布

您现在位置:Python中文网/ 问答频道 /正文

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

如果我正在编写一个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)

这只是一厢情愿吗?


Tags: 函数答案参数deffunction全局意义返回值
3条回答

如果你想修改变量的值,你可以让你的代码

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

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

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

这是可以做到的,但我警告你-这不会很好!您可以做的是捕获函数中的调用方框架,然后提取调用行,解析它并提取传递的参数,然后将它们与函数签名进行比较并创建参数映射,然后调用函数,并且在函数完成本地堆栈中的更改后,将其与映射的调用方框架进行比较并更新变化。如果你想看看它有多傻,这里有一个演示:

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

显然,这只适用于带有位置参数的非嵌套函数,并且只有当您传递简单的本地参数时,才可以随意进入处理关键字参数、不同堆栈、返回/包装/链接调用和其他诡计(如果您喜欢的话)的兔子洞。

或者,您知道,您可以使用为此而发明的结构,比如全局变量、类,甚至是封闭的可变对象。别再杀小精灵了。

你可以:

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

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

python函数是关闭的->;调用函数(a,b)s时,a和b被重新分配到本地(函数)引用/指针in1和in2,这些引用/指针在函数外部不可访问。使用globals提供对这些新值的引用,而不使用globals,则需要将其传递回return。

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

相关问题 更多 >