修改函数参数 [英] Modifying function arguments

查看:20
本文介绍了修改函数参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Sorry if this is a dumb question, but I've looked for a while and not really found the answer.

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

If I'm writing a python function, for example:

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

如何使这些更改坚持下去?

How do I make these changes stick?

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

I know why they dont, this has been addressed in many answers, but I couldn't find an answer to the question of how to actually make them do so. Without returning values or making some sort of class, is there really no way for a function to operate on its arguments in a global sense?

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

I also want these variables to not be global themselves, as in I want to be able to do this:

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

这只是一厢情愿吗?

推荐答案

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

It can be done but I'm warning you - it won't be pretty! What you can do is to capture the caller frame in your function, then pick up the call line, parse it and extract the arguments passed, then compare them with your function signature and create an argument map, then call your function and once your function finishes compare the changes in the local stack and update the caller frame with the mapped changes. If you want to see how silly it can get, here's a demonstration:

# 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

现在您可以轻松地装饰您的函数,使其能够执行这种不敬虔的讽刺:

And now you can easily decorate your function to enable it to perform this ungodly travesty:

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

显然,这仅适用于具有位置参数的非嵌套函数,并且仅当您传递简单的本地参数时,才可以随意进入处理关键字参数、不同堆栈、返回/包装/链接调用的兔子洞,和其他恶作剧,如果那是你喜欢的.

This, obviously, works only for non-nested functions with positional arguments, and only if you pass simple local arguments, feel free to go down the rabbit hole of handling keyword arguments, different stacks, returned/wrapped/chained calls, and other shenanigans if that's what you fancy.

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

Or, you know, you can use structures invented for this, like globals, classes, or even enclosed mutable objects. And stop murdering pixies.

这篇关于修改函数参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆