简体   繁体   中英

Get function signature and parameters from within current function in Python

I'm trying to get all function parameters and their values from within the current function in Python and almost have it working except for one thing: I don't know how to call it from inside the function without explicitly giving it the name of the object.

For example: the code below works for the case of the function being a class method ("my_func_in_class", but I don't know what to pass into the inspect.signature() call for the "my_func" function that is not part of a class without mentioning the function by name.

This isn't critical to solving my problem at hand but I'd still like to know how to make it work

import inspect
import sys

def my_func(a, b, c=None):

    this_func = inspect.currentframe()
    func_name = inspect.getframeinfo(this_func).function
    print(f"Function Name {func_name}")

    (sig, local_vars) = inspect.signature(my_func), locals()

    args = {}
    for a in sig.parameters.keys():
        args[a] = local_vars[a]

    return args

class MyClass(object):

    def __init__(self):
        pass

    def my_func_in_class(self, a, b, c=None):

        this_func = inspect.currentframe()
        func_name = inspect.getframeinfo(this_func).function
        print(f"Function Name {func_name}")
        (sig, local_vars) = inspect.signature(getattr(self, func_name)), locals()

        args = {}
        for a in sig.parameters.keys():
            args[a] = local_vars[a]

        return args

if __name__ == "__main__":

    class1 = MyClass()
    args1 = my_func(1, 2)
    args2 = class1.my_func_in_class(10, 20, c=30)

    print(f"args1:")
    for (k, v) in args1.items():
        print(f"{k}: {v}")

    print(f"\nargs2")
    for (k, v) in args2.items():
        print(f"{k}: {v}")
python ./get_func_args.py
Function Name my_func
Function Name my_func_in_class
args1:
a: 1
b: 2
c: None

args2
a: 10
b: 20
c: 30

But:

def my_func(a, b, c=None):

    this_func = inspect.currentframe()
    func_name = inspect.getframeinfo(this_func).function
    print(f"Function Name {func_name}")

    (sig, local_vars) = inspect.signature(this_func), locals()

returns the error:

Function Name my_func
Traceback (most recent call last):
  File "./get_func_args.py", line 41, in <module>
    args1 = my_func(1, 2)
  File "./get_func_args.py", line 12, in my_func
    (sig, local_vars) = inspect.signature(this_func), locals()
  File "/home/mlissa2/cmm/python/miniconda3/lib/python3.6/inspect.py", line 3065, in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
  File "/home/mlissa2/cmm/python/miniconda3/lib/python3.6/inspect.py", line 2815, in from_callable
    follow_wrapper_chains=follow_wrapped)
  File "/home/mlissa2/cmm/python/miniconda3/lib/python3.6/inspect.py", line 2193, in _signature_from_callable
    raise TypeError('{!r} is not a callable object'.format(obj))
TypeError: <frame object at 0x7ff7dcc92048> is not a callable object

So I'm very close but don't have the final step in place.

If your only concern is to get arguments information from the signature of the function along with their values, then you don't need to use inspect.signature() . You can use the following approach.

def my_func(a, b, c=None):
    # get arg-values without reference to callable
    cframe = inspect.currentframe()
    args_info = inspect.getargvalues(cframe)

    # Collecting args-values of my_func in a dictionary
    this_func_argvals = {arg: args_info.locals.get(arg) for arg in args_info.args}
    return this_func_argvals

That's it.

However, if you must insist on getting the signature too for whatnot than use the following approach.

The reason you were able to get my_func_in_class reference in your class method was because your class provided access to its namespace, so getting attribute from that namespace was easy. In order to get reference of my_func we need to access namespace of the immediate outer stack of my_func . From there we can get my_func reference. Here's how to do that:

def some_fun(a, b, c=None):
    # Get Stacks. We only need FrameInfo for current frame and immediate outer frame
    stacks = inspect.stack()

    # Get my_func's name (str) from current frame
    this_func_name = stacks[0].function

    # Get immediate outer frame
    outer_frame = stacks[1].frame

    # From outer frame's locals, get reference to my_fun using its name as key
    this_func_reference = outer_frame.f_locals.get(this_func_name)

    # Voila!
    sigs = inspect.signature(this_func_reference)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM