How to get the formal args of a function object?

K

kj

Suppose that f is an object whose type is 'function'.

Is there a way to find out f's list of formal arguments?

The reason for this is that I'm trying to write a decorator and
I'd like the wrapper to be able to check the number of arguments
passed. Specifically, I'd like the wrapper to look as shown below:

def _wrap(f):
def wrapper(self, *params):
n_expected = len(f.FORMAL_ARGS)
n_received = len(params)
if n_received is not n_expected:
raise RuntimeError("Wrong number of arguments passed "
"to %s" % f.__name__)
return self.send_jsonrpc_request(f.__name__, params)
return wrapper

....but I'm missing something like the hypothetical attribute
FORMAL_ARGS above.

TIA!

Kynn
 
C

Chris Rebert

Suppose that f is an object whose type is 'function'.

Is there a way to find out f's list of formal arguments?

The reason for this is that I'm trying to write a decorator and
I'd like the wrapper to be able to check the number of arguments
passed.  Specifically, I'd like the wrapper to look as shown below:

def _wrap(f):
   def wrapper(self, *params):
       n_expected = len(f.FORMAL_ARGS)
       n_received = len(params)
       if n_received is not n_expected:
           raise RuntimeError("Wrong number of arguments passed "
                              "to %s" % f.__name__)
       return self.send_jsonrpc_request(f.__name__, params)
   return wrapper

...but I'm missing something like the hypothetical attribute
FORMAL_ARGS above.

Take a look at inspect.getargspec(func):
http://docs.python.org/library/inspect.html#inspect.getargspec

Cheers,
Chris
--
http://blog.rebertia.com

P.S. Have you considered making your address obfuscation just slightly
less of a pain in the ass? It's particularly annoying compared to
others'.
 
J

Jeff McNeil

You can pull it out of f.func_code.co_varnames, but I don't believe
that's a very good approach. I tend to veer away from code objects
myself.

If you know how many arguments are passed into the wrapped function
when it's defined, you can write a function that returns your
decorator. As an example...

def validate_params(c):
def the_decorator(f):
def wrapper(*args):
if len(args) != c:
raise Exception("Bad things, Man.")
return f(*args)
return wrapper
return the_decorator

@validate_params(2)
def add(a,b):
return a+b

add(1,2)
add(1,2,3)

$ ./test.py
Traceback (most recent call last):
File "test.py", line 16, in <module>
add(1,2,3)
File "test.py", line 5, in wrapper
raise Exception("Bad things, Man.")
Exception: Bad things, Man.

Jeff
 
N

norseman

kj said:
Suppose that f is an object whose type is 'function'.

Is there a way to find out f's list of formal arguments?

The reason for this is that I'm trying to write a decorator and
I'd like the wrapper to be able to check the number of arguments
passed. Specifically, I'd like the wrapper to look as shown below:

def _wrap(f):
def wrapper(self, *params):
n_expected = len(f.FORMAL_ARGS)
n_received = len(params)
if n_received is not n_expected:
raise RuntimeError("Wrong number of arguments passed "
"to %s" % f.__name__)
return self.send_jsonrpc_request(f.__name__, params)
return wrapper

...but I'm missing something like the hypothetical attribute
FORMAL_ARGS above.

TIA!

Kynn
========================================
I've never tried that approach. But the attempt brings back memories.

Mind you I was using a compiler, not an interpreter.

Language was assembly

it outlines like this:

1st time called:

compile actual code # boo-koo bytes
if token count test OK
compile the call to the code # just the call (1 or 2 words)
else
print current program address
compile in a string denoting error "ERROR-ERROR"
to force a quit (crash)


2nd time and on

do not compile actual code # Zero bytes
if token count test OK
compile the call to the code # just the call (1 or 2 words)
else
print current program address
compile in a string denoting error "ERROR-ERROR"
to force a quit (crash)

Helps to print the assembly 'prn' file and look for your error flag
BEFORE trying to run program. :)

compiler token stack (storage) delta before/after packet loaded is
tested with size expected and compiler directives adjusted accordingly.

I have no idea how to do this with an interpreter. Maybe someone who
reads this can figure it out. If so - I want a copy!!!! (Please.)

Even:
def funct_foo(t1,t2,t3):
call_token_check(3) will not tell the incoming number
they are on a stack or something
somewhere else in memory.
With an interpreter this becomes an expensive overhead. Mine was only
costly at compile time. Not at run time. And it shortened the code and
the development time.



Steve
 
N

norseman

Scott said:
kj said:
Suppose that f is an object whose type is 'function'.

Is there a way to find out f's list of formal arguments?

The reason for this is that I'm trying to write a decorator and
I'd like the wrapper to be able to check the number of arguments
passed....but I'm missing something like the hypothetical attribute
FORMAL_ARGS above.

I can write a wrapper now:

def tracer(function):
def internal(*args, **kwargs):
print('calling %s(%s)' % (function.__name__,
', '.join([repr(arg) for arg in args] +
['%s=%r' % ka for ka in sorted(kwargs)])))
result = function(*args, **kwargs)
print('=> %r' % result)
return internal

and call like so:
tracer(math.sin)(3.1415 / 6)

calling sin(0.5235833333333334)
=> 0.49998662654663256

What would your missing something be for tracer(math.sin)?

--Scott David Daniels
(e-mail address removed)
=========================
Scott;
I'm lost with this.

If you use the same and add that it prints both the first_token/second
and the first_token multiplied by second and pass it (pi, 6, 7) what
happens then?

ie - function mysin only expects pi and 6 and is to print both pi/6 and
pi*6. The 7 is an error, not supposed to be there.



Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top