Accessing the name that an object being created is assigned to

泪湿孤枕 提交于 2019-11-29 02:24:28
tln

The AST can't give you that answer. Try using frame.f_lasti and then peeking into the bytecode. If the next line isn't a STORE_FAST, you've got interior calls or something else going on other than the simple assignment you're looking for.

def f():
  f = sys._getframe()
  i = f.f_lasti + 3   # capture current point of execution, advance to expected store
  print dis.disco(f.f_code, i)

I don't know of how much help this is, but have you considered using the call to locals()? It returns a dict that contains the name and value of all the local variables.

For example:

s = ''
locals()
>>> {'__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 's': '', '__name__': '__main__', '__doc__': None}
t = s  # I think this is what is of most importance to you
locals()
>>> {'__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 's': '', 't': '', '__name__': '__main__', '__doc__': None}

So you could traverse this dictionary and check which variables have (as their value) an object of the type that you are looking for.

Like I said, I don't know of how much help this answer is, but if you need clarification on anything, then do leave a comment and I will try to respond as best as I can.

I don't do any error checking here because (1) this is just for debugging/profiling/hacking (2) this exact process was 'just' completed or the code wouldn't be running. Is there a problem with this?

Yes:

  1. Start a program

  2. Wait unit it imports a particular module foo.py

  3. Edit foo.py

Now code that's loaded in a Python process doesn't match code found on disk.

Yet another reason why disassembling the bytecode may be a better technique.

Here's how it's done. Much thanks to the anonymous clue giver. Much luck in your quest to rack up rep for your alt account.

import inspect
import opcode


def get_name(f):
    """Gets the name that the return value of a function is
    assigned to. 

    This could be modified for classes as well. This is a
    basic version for illustration that only prints out
    the assignment instead of trying to do anything with it.
    A more flexible way would be to pass it a callback for when
    it identified an assignment.

    It does nothing for assignment to attributes. The solution
    for that isn't much more complicated though. If the
    instruction after the function call is a a `LOAD_GLOBAL`,
    `LOAD_FAST` or `LOAD_DEREF`, then it should be followed by
    a chain of `LOAD_ATTR`'s. The last one is the attribute
    assigned to.
    """

    def inner(*args, **kwargs):
        name = None

        frame = inspect.currentframe().f_back
        i = frame.f_lasti + 3

        # get the name if it exists
        code = frame.f_code
        instr = ord(code.co_code[i])
        arg = ord(code.co_code[i+1]) # no extended arg here.
        if instr == opcode.opmap['STORE_FAST']:
            name = code.co_varnames[arg]
        elif instr in (opcode.opmap['STORE_GLOBAL'],
                       opcode.opmap['STORE_NAME']):
            name = code.co_names[arg]
        elif instr == opcode.opmap['STORE_DEREF']:
            try:
                name = code.co_cellvars[arg]
            except IndexError:
                name = code.co_freevars[arg - len(code.co_cellvars)]
        ret = f(*args, **kwargs)
        print opcode.opname[instr]
        if name:
            print "{0} = {1}".format(name, ret)
        return ret

    return inner


@get_name
def square(x):
    return x**2

def test_local():
    x = square(2)

def test_deref():
    x = square(2)
    def closure():
        y = x
    return closure

x = square(2)
test_local()
test_deref()()

It shouldn't be too hard to figure out assignments of the for list_[i] = foo() either, including the value of i by using frame.f_locals. The tricky ones are going to be literals and when it's passed as an argument. Both of those cases should be pretty challenging.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!