Modifying function arguments

后端 未结 3 1261
鱼传尺愫
鱼传尺愫 2020-11-30 14:29

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

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

def f         


        
相关标签:
3条回答
  • 2020-11-30 14:54

    you can do:

    def function(in1, in2):
       return  in1 + 1 , in2 + 1
    
    a, b = function(a,b)
    c, d = function(c,d)
    

    python functions are closed -> when function(a,b) s called, a and b get reassigned to a local (to the function) references/pointers in1 and in2, which are not accessible outside of the function. provide references to those new values w/o using globals, you will need to pass that back through return.

    When you pass an array or non primitive object into a function, you can modify the object's attributes and have those modifications be visible to other references for that object outside, because the object itself contain the pointers to those values, making the visible to anything else holding a pointer to that object.

    0 讨论(0)
  • 2020-11-30 14:57

    If you are looking to modify the value of the variables you could have your code be

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

    This allows you to actually change the values of the a and b variables with the function.

    0 讨论(0)
  • 2020-11-30 15:07

    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
    

    And now, demonstration:

    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.

    0 讨论(0)
提交回复
热议问题