0

If I have a function f(x) and variable var of any type and scope is there any way to modify var inside call to f(var)?

Meaning that function f does some magic stuff to get reference to original (passed) var (like reference/pointer in C++) and modifies that original var, for any type of var (even int/float/str/bytes).

Wrapping var into dict or list or any other class is not allowed. Because it is known that dict/list are passed by reference.

Returning new value from a function to re-assign variable is not allowed too.

Modifying scope of original variable (like making it global) is not allowed too.

In fact any change to function's caller's code is not allowed.

This variable can be of any imaginary type and scope, no assumptions should be done about them.

So that next code should work (such code can be placed both inside another wrapping function or globally, should not matter):

def test():
    def magic_inplace_add(x, val):
        # ...
    var = 111
    magic_inplace_add(var, 222) # modifies int var by adding 222
    print(var) # prints 333

test()

If needed to solve the task this function can do any complex manipulations like using inspect module.

Basically, I need somehow to break a convention about simple types being passed by value, even if to achieve this in some non-simple/cryptic way.

I'm pretty sure this task can be solved by tools from standard reverse-engineering modules like inspect / ast / dis.

Just to clarify my need for this task - right now for this task I'm not trying to code nicely using tidy Python style and methods, you can imagine that this task in future is a kind of interview question for companies specializing in reverse-engineering / antiviruses / code security / compilers implementation. Also tasks like this are interesting in exploring all hidden possibilities of languages like Python.

21
  • 1
    use global variables Commented Oct 4, 2020 at 11:23
  • 1
    @rcvaram In fact it is not allowed to change function-calling code in any way. Commented Oct 4, 2020 at 11:25
  • 1
    Do you have a real need to break the basic Python rule that immutable variables can't be modified this way? Commented Oct 4, 2020 at 11:34
  • 1
    "it is known that dict / list are passed by reference" it is not known, because that is false. Python never passes anything by reference Commented Oct 4, 2020 at 11:36
  • 2
    @Arty that isn't answering my question at all. What you are asking is not fully specified, you keep making false statements about Python's semantics to try to explain what you want to do, and that makes it even more confusing. If you want to do something very hacky, then you need to be able to explain exactly what it is you are trying to do. Commented Oct 4, 2020 at 11:46

2 Answers 2

2

For module scope variables.

import inspect
import re

def magic_inplace_add(var, val):
    '''
        Illustation of updating reference to var when function is called at module level (i.e. not nested)
    '''
    # Use inspect to get funcstion call syntax
    previous_frame = inspect.currentframe().f_back
    (filename, line_number, 
     function_name, lines, index) = inspect.getframeinfo(previous_frame)
    # lines contains call syntax
    # i.e. ['magic_inplace_add(x, 222)\n']
    args = re.findall("\w+", lines[0]) # get arguments of calling syntax i.e.  ('magic_inplace_add', 'x', 222)
    
    # Update variable in context of previous frame
    # i.e. args[1] == 'x' in example
    if args[1] in previous_frame.f_globals:
        # update variable from global
        previous_frame.f_globals.update({args[1]:var + val})
    elif args[1] in previous_frame.f_locals:
        # for nested function variable would be in f_locals
        # but this doesn't work in Python 3 this f_locals is a copy of actual locals in calling frame
        # see Martijn Pieters answer at
        # https://stackoverflow.com/questions/36678241/how-can-i-force-update-the-python-locals-dictionary-of-a-different-stack-frame
        previous_frame.f_locals.update({args[1]:var + val})  # this is what would be used for nested functions
     

Example

x = 111 # x module scope
y = 222 # y module scope
z = 333 # z module scope
magic_inplace_add(x, 222)
magic_inplace_add(y, 222)
magic_inplace_add(z, 222)
print(x)  # Output: 333
print(y)  # Output: 444
print(z)  # Output: 555
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! UpVoted. At least works for me when testing code is in global scope. But strange, but when testing code is within a function it doesn't work, locals dict is not changed, although magic func is at module level, see example online here
@Arty--not strange--that's the comment I made about not working when the function is nested (i.e. within another function). The issue is the elif branch that updates locals updates a copy of locals rather than the actual locals in Python 3 as the link I provided attests.
@DarryIG I thought that what you meant by saying that func should be in module/global scope, but as in my link to code in previous comment - it appears to be that variables should be also at module/global scope? So both function and variable should be all at global scope - is that right pre-requisite for working of your code? But still is very nice that at least one working solution has been posted, I up-voted your solution!
@DarryIG BTW, what's the reason that Python doesn't allow to modify locals of previous frame? Is it for security reasons to protect from doing things like we intended to do or some other reason?
@Arty--seems this could have been made to work in Python 2 but a Python 3 performance optimization changed the behaviour i.e. Change the value of a local variable where variable name will be expressed as a string.
-1

as @rcvaram suggested use global variables, like this

def magic_inplace_add(x, val):
    global var
    var = 333
global var
var = 111
magic_inplace_add(var, 222) # modifies int var by adding 222
print(var)

1 Comment

I told in my question that it is not allowed to change type or scope of a variable. In fact it is not allowed to do any modifications to function's caller's code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.