Can I get a list of the variables that reference an other in Python 2.7?
Question: Imagine I have:

    
    
    X = [0,1]
    Y = X
    Z = Y
    

Is there a function like referenced_by(X) that returns something like `['Y',
'Z']`? And a function like points_to(Y) that returns `'X'`?

I know there is `is` to test whether to objects are the same, I just would
like a quick way to get the names though.


Answer: Yes, and no. You can get a list of _global_ variables:

    
    
    for name, val in globals().items():
        if val is obj:
            yield name
    

You can also get a list of _local_ variables:

    
    
    for name, val in locals().items():
        if val is obj:
            yield name
    

However, you will with this miss all variables in other contexts than local to
your function or global to the module. You can find variables in calling
contexts with frame-magic, but you won't be able to find anything that is
global to other modules, for example.

What you would use this for, I don't know.

You will also not find any attributes that reference the object, but
attributes aren't variables so maybe that's OK.

You can get all objects that reference your object though. And that will
include the globals and locals for all the functions. But you can't get the
name of the variables in that case. You can do

    
    
    >>> import gc
    >>> gc.get_referrers(obj)
    

To get a list of all objects referencing the object `obj`. Once again this is
pretty useless. :-)

If you want the names you can look up the keys in the cases that the referrer
is a dictionary or a stack frame:

    
    
    import gc
    import types
    
    def find_ref_names(obj):
        for ref in gc.get_referrers(obj):
            if isinstance(ref, types.FrameType):
                look_in = [ref.f_locals, ref.f_globals]
            elif isinstance(ref, dict):
                look_in = [ref]
            else:
                continue
            for d in look_in:
                for k, v in d.items():
                    if v is obj:
                        yield k
    
    
    def main():
        a = "heybaberiba"
        b = a
        c = b
    
        print list(find_ref_names(b))
    
    if __name__ == '__main__':
        main()
    

This will print:

    
    
    ['a', 'c', 'b', 'obj']
    

But as you don't know which context the variables `a`, `b`, `c` and `obj` is
defined in, it's yet again pretty useless. As an example move the definition
of a to the module-level and you get this result:

    
    
    ['c', 'b', 'a', 'obj', 'a', 'a']
    

Where one of these `a` is the global one, and others are copies into local
contexts.

As for your second question:

> And a function like points_to(Y) that returns 'X'?

That's the same function. Both `X` and `Y` are just names pointing to the same
object, in this case a list. `X` is no different from `Y`, and `Y` does not
point to `X`. `Y` points to `[0,1]` and so does `X`.

