inspecting a callable for the arguments it accepts

Cameron Simpson cs at cskk.id.au
Tue Nov 14 19:08:33 EST 2017


On 15Nov2017 09:12, Chris Angelico <rosuav at gmail.com> wrote:
>On Wed, Nov 15, 2017 at 8:05 AM, Cameron Simpson <cs at cskk.id.au> wrote:
>> I know that this isn't generally solvable, but I'm wondering if it is
>> partially solvable.
>>
>> I have a task manager which accepts callables, usually functions or
>> generators, and calls them on data items as needed. For reasons which,
>> frankly, suggest user interface ergonomics failure to me it happens that
>> inappropriate functions get submtted to this system. For example, functions
>> accepting no arguments but which are handed one by the system.
>>
>> I would like to inspect submitted functions' signatures for suitability at
>> submission time, without calling the function. For example to see if this
>> function accepts exactly one argument, or to see if it is a generator, etc.
>>
>> Is this possible, even in a limited way?
>
>Yes, it is. Sometimes in a very limited way, other times fairly well.
>(NOTE: I'm using CPython for this. Other interpreters may differ
>wildly.)

I'm using CPython too.

>First off, you can look at the function's attributes to see
>some of the info you want:
>
>>>> def wants_one_arg(x): pass
>...
>>>> wants_one_arg.__code__.co_argcount
>1
>>>> wants_one_arg.__code__.co_varnames
>('x',)
>
>co_varnames has the names of all local variables, and the first N of
>those are the arguments. You aren't matching on the argument names,
>but they might help you make more readable error messages.
>
>As to recognizing generators, every function has a set of flags which
>will tell you whether it yields or just returns:
>
>>>> def fun(): pass
>...
>>>> def gen(): yield 1
>...
>>>> fun.__code__.co_flags
>67
>>>> gen.__code__.co_flags
>99
>
>That's the raw info. For human-friendly functions that look at this
>info, check out the inspect module:
>
>>>> inspect.isgeneratorfunction(fun)
>False
>>>> inspect.isgeneratorfunction(gen)
>True
>>>> inspect.signature(wants_one_arg)
><Signature (x)>
>
>Poke around with its functions and you should be able to find most of
>what you want, I think.

Thank you, looks like just what I need.

Cheers,
Cameron Simpson <cs at cskk.id.au> (formerly cs at zip.com.au)



More information about the Python-list mailing list