Search This Blog

Showing posts with label introspection. Show all posts
Showing posts with label introspection. Show all posts

Saturday, April 27, 2013

Custom magic function in IPython session

I needed some additional functionality when running my interactive ipython session. As ipython session is easily extendable with a help of custom python base functions I decided to write one as an example.

The function searches for the last outputed list object and creates variables for easy access (latest version can be found on github). Instead of typing l[_index_] you can simple tame l__index_. See the example below.
 
~/.config/ipython/profile_default/startup# cat rl.py

def object_name(obj, ret=None):
    g=globals()
    ret=[]
    obj_id=id(obj)
    for i in g.keys() :
        if id(g[i]) == obj_id :
            print i, g[i]
            ret.append(i)
    return ret


def rl (mylist=None, prefix=None, limit=7):
    prefix = prefix if prefix else "l"
    limit = limit if limit else 7

    aux=list(Out.keys()) # we want to make a copy
    aux.sort()
    aux.reverse()
    last_index = aux[0]

    if mylist == None :
        mylist = Out[last_index]
        mylist_name=In[last_index]

        if type(mylist) is not  list :
            for i in aux :
                # print i, Out[i],
                if type(Out[i]) is list :
                    mylist = Out[i]
                    mylist_name=In[i]
                    print("using last list object: %s" % mylist_name)
                    break
    else :
        mylist_name = filter( lambda x: not x.startswith("_"), object_name(l))

    if type(mylist) is not  list :
        print("can't find any list or specified object is not a list")
        return

    glo=globals()

    for k, val in enumerate(mylist) :
        if k <= limit :
            name=prefix+str(k)
            glo[name]=val
            print("created variable %s = %s" % (name, val) )
        else :
            print("list %s has %d elements but only 7 was printed" % ( mylist_name, len(mylist) ) )
            break

def rla (**kargs) :
  rl(prefix="a", **kargs)

def rlb (**kargs) :
  rl(prefix="b", **kargs)

print
print("auxiliary functions `rl` `rla` and `rlb` have been defined")

Example how this works
 
$ ipython='ipython  --colors Linux --autocall=2

In [17]: l=[1,2,3,1,2,3,1,2,3,1,2,3]

# instead of typing l[0] or l[1] etc we can now use this variables
In [18]: rl
-------> rl()
created variable l0 = 1
created variable l1 = 2
created variable l2 = 3
created variable l3 = 1
created variable l4 = 2
created variable l5 = 3
created variable l6 = 1
created variable l7 = 2
list l has 24 elements but only 7 was printed

In [2]: a=l    

In [6]: a
Out[6]: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

In [7]: rl(a)
__ [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
_ [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
a [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
_6 [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
_4 [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
l [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
created variable l0 = 1
created variable l1 = 2
created variable l2 = 3
created variable l3 = 1
created variable l4 = 2
created variable l5 = 3
created variable l6 = 1
created variable l7 = 2
list ['a', 'l'] has 12 elements but only 7 was printed

In [10]: a
Out[10]: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

In [11]: rlb
-------> rlb()
created variable b0 = 1
created variable b1 = 2
created variable b2 = 3
created variable b3 = 1
created variable b4 = 2
created variable b5 = 3
created variable b6 = 1
created variable b7 = 2
list a has 12 elements but only 7 was printed

References
  1. https://github.com/rtomaszewski/dotfiles
  2. http://rtomaszewski.blogspot.co.uk/2013/04/how-to-find-list-variable-name.html
  3. http://en.wikipedia.org/wiki/Reflection_(computer_science)
  4. http://en.wikipedia.org/wiki/Type_introspection

How to find list variable name

I've found an interesting limitation or maybe this is my lack of knowledge about python. I was trying to write a function that takes a list as an argument and prints on stdout  the name of the list and its value. Unfortunately this wasn't possible as there isn't an available function neither from python builtin set or from the list object itself that retrieves the name of a list variable.
 
def example(mylist):
    try:
        print("The argument name %s and value %s" % (mylist.name, mylist))
    except Exception, e:
        print e
    try:
        print("The argument name %s and value %s" % (mylist.__name__, mylist))
    except Exception, e:
        print e    

Trying to run this generate these exceptions:
 
mylist=[1,2]
example(mylist)
'list' object has no attribute 'name'
'list' object has no attribute '__name__'

To solve this problem I write this little auxiliary function that iterates over all global symbols and try to find the variable name base on the value. Unfortunately it isn't perfect as list can have multiple references that share the save value so our function will return all variable names instead of only one.
 
def object_name(obj, ret=None):
    g=globals()
    ret=[]
    obj_id=id(obj)
    for i in g.keys() :
        if id(g[i]) == obj_id :
            print i, g[i]
            ret.append(i)
    return ret

# an example from ipython showing how the code works 
In [47]: l=[1,2,3]
In [48]: a=l 
In [49]: object_name(l)
l [1, 2, 3]
a [1, 2, 3]
Out[49]: ['l', 'a']

References
  1. http://bytes.com/topic/python/answers/854009-how-get-name-list