Implementing "nargin" and "nargout"


def f2(*args):
    nargin = len(args)
    nargout = _get_nargout()
    return 2

In[90]: dis.disassemble(f2.func_code)
  2           0 LOAD_GLOBAL              0 (len)
              3 LOAD_FAST                0 (args)
              6 CALL_FUNCTION            1
              9 STORE_FAST               1 (nargin)

  3          12 LOAD_GLOBAL              1 (_get_nargout)
             15 CALL_FUNCTION            0
             18 STORE_FAST               2 (nargout)

  4          21 LOAD_CONST               1 (2)
             24 RETURN_VALUE

In [89]: f2.func_code.co_consts
Out[89]: (None, 2)

In [91]: f2.func_code.co_names
Out[91]: ('len',)

In [92]: f2.func_code.co_varnames
Out[92]: ('args', 'nargin', 'nargout')

Generating new code object

From http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/277940

Get the code object,

Then we need to insert 2 extra variables and a litlle bit of code, like in the lines 2 and 3 of the function f2:

    from opcode import opmap, HAVE_ARGUMENT, EXTENDED_ARG
LOAD_GLOBAL = opmap['LOAD_GLOBAL']
LOAD_CONST = opmap['LOAD_CONST']
    CALL_FUNCTION = opmap['CALL_FUNCTION']
    LOAD_FAST = opmap['LOAD_FAST']
    STORE_FAST = opmap['STORE_FAST']

Once everything is ready, recreate the codeobject and then the function

    codestr = ''.join(map(chr, newcode))
codeobj = type(co)(co.co_argcount, co.co_nlocals, co.co_stacksize,
co.co_flags, codestr, tuple(newconsts), co.co_names,
co.co_varnames, co.co_filename, co.co_name,
co.co_firstlineno, co.co_lnotab, co.co_freevars,
co.co_cellvars)
    return type(f)(codeobj, f.func_globals, f.func_name, f.func_defaults,
f.func_closure)

Actually, it seems that this will be very easy to do with 'byteplay' module (http://code.google.com/p/byteplay/) described best at http://wiki.python.org/moin/ByteplayDoc .

from byteplay import *
c = Code.from_code(f.func_code)
c.code[:0] = [(LOAD_GLOBAL,'len'),(LOAD_FAST,'args'),(CALL_FUNCTION,1),(STORE_FAST,'nargin'),(LOAD_GLOBAL,'_get_nargout'),(CALL_FUNCTION,0),(STORE_FAST,'nargout')]
# the nargout is store by STORE_FAST, replace LOAD_GLOBAL with LOAD_FAST
f.func_code = c.to_code()

Comments