杰瑞科技汇

Python getargspec如何获取函数参数信息?

Of course. Let's dive deep into inspect.getargspec.

Python getargspec如何获取函数参数信息?-图1
(图片来源网络,侵删)

TL;DR: The Short Answer

inspect.getargspec(func) is a deprecated function from Python's inspect module. It was used to get the signature of a function, including its arguments, defaults, and variable-length arguments (*args, **kwargs).

You should not use it in new code. It has been removed in Python 3.11 and raises a DeprecationWarning in earlier versions.

The modern replacement is inspect.signature(func).


The Detailed Explanation: getargspec

Even though it's deprecated, understanding getargspec is useful for reading older Python code (2.x and early 3.x).

Python getargspec如何获取函数参数信息?-图2
(图片来源网络,侵删)

What Did It Do?

getargspec parsed a function's definition and returned a named tuple with four key attributes:

  1. args: A list of the parameter names (e.g., ['a', 'b', 'c']).
  2. varargs: The name of the *args parameter, or None if it doesn't exist.
  3. keywords: The name of the **kwargs parameter, or None if it doesn't exist.
  4. defaults: A tuple of default argument values for the trailing parameters, or None if there are no defaults.

How It Worked: Examples

Let's look at some examples to see what getargspec returned.

Example 1: A Simple Function

import inspect
def simple_func(a, b, c=10):
    return a + b + c
spec = inspect.getargspec(simple_func)
print(f"args: {spec.args}")
print(f"varargs: {spec.varargs}")
print(f"keywords: {spec.keywords}")
print(f"defaults: {spec.defaults}")

Output (in Python 3.10 or earlier):

Python getargspec如何获取函数参数信息?-图3
(图片来源网络,侵删)
args: ['a', 'b', 'c']
varargs: None
keywords: None
defaults: (10,)

Analysis:

  • args: The function has three named parameters: a, b, and c.
  • varargs: No *args, so it's None.
  • keywords: No **kwargs, so it's None.
  • defaults: Only c has a default value, which is 10.

*Example 2: A Function with `argsandkwargs`

import inspect
def complex_func(a, b, *args, **kwargs):
    print(f"a: {a}, b: {b}")
    print(f"args: {args}")
    print(f"kwargs: {kwargs}")
spec = inspect.getargspec(complex_func)
print(f"args: {spec.args}")
print(f"varargs: {spec.varargs}")
print(f"keywords: {spec.keywords}")
print(f"defaults: {spec.defaults}")

Output (in Python 3.10 or earlier):

args: ['a', 'b']
varargs: args
keywords: kwargs
defaults: None

Analysis:

  • args: The positional parameters before *args are a and b.
  • varargs: The name of the *args parameter is args.
  • keywords: The name of the **kwargs parameter is kwargs.
  • defaults: No parameters have default values, so it's None.

Why Was getargspec Deprecated?

The primary reason for deprecation is Python 3's new function signature features, which getargspec could not handle.

  1. Keyword-Only Arguments: In Python 3, you can force a parameter to be a keyword-only argument by placing it after or *args. getargspec could not distinguish between a regular positional argument and a keyword-only one.

    def func_with_keyword_only(a, b, *, c, d=20):
        pass

    getargspec would incorrectly report ['a', 'b', 'c', 'd'] as all being positional arguments.

  2. Positional-Only Arguments: In Python 3.8+, you can use the character to define positional-only arguments. getargspec is completely blind to this syntax.

    def func_with_positional_only(a, b, /, c, d=30):
        pass

    getargspec would not know that a and b are positional-only.

  3. Annotations: Python 3 allows type hints (e.g., def func(a: int) -> str:). getargspec ignores these.

The new inspect.signature was designed to handle all these modern features correctly and robustly.


The Modern Replacement: inspect.signature()

This is the function you should use today. It returns a Signature object that is much more powerful and informative.

How to Use inspect.signature()

Let's repeat the previous examples using inspect.signature.

Example 1: Simple Function

import inspect
def simple_func(a, b, c=10):
    return a + b + c
sig = inspect.signature(simple_func)
print(sig)

Output:

(a, b, c=10)

This is a clean, human-readable representation. To get the details, you can iterate over the parameters.

for name, param in sig.parameters.items():
    print(f"Parameter: {name}")
    print(f"  Kind: {param.kind}") # POSITIONAL_OR_KEYWORD, KEYWORD_ONLY, etc.
    print(f"  Default: {param.default if param.default is param.empty else param.default}")
    print(f"  Annotation: {param.annotation if param.annotation is param.empty else param.annotation}")
    print("-" * 20)

Output:

Parameter: a
  Kind: POSITIONAL_OR_KEYWORD
  Default: <class 'inspect.Parameter.empty'>
  Annotation: <class 'inspect.Parameter.empty'>
--------------------
Parameter: b
  Kind: POSITIONAL_OR_KEYWORD
  Default: <class 'inspect.Parameter.empty'>
  Annotation: <class 'inspect.Parameter.empty'>
--------------------
Parameter: c
  Kind: POSITIONAL_OR_KEYWORD
  Default: 10
  Annotation: <class 'inspect.Parameter.empty'>
--------------------

*Example 2: Function with `argsandkwargs`

import inspect
def complex_func(a, b, *args, **kwargs):
    pass
sig = inspect.signature(complex_func)
print(sig)

Output:

(a, b, *args, **kwargs)

Example 3: Handling Keyword-Only Arguments (The getargspec Weakness)

import inspect
def func_with_keyword_only(a, b, *, c, d=20):
    pass
sig = inspect.signature(func_with_keyword_only)
print(sig)

Output:

(a, b, *, c, d=20)

Notice the in the output. This clearly shows that c and d are keyword-only arguments. getargspec could not provide this information.

Summary: getargspec vs. signature

Feature inspect.getargspec(func) (Deprecated) inspect.signature(func) (Modern)
Availability Python 2.1 - 3.10 (Removed in 3.11) Python 3.3+
Return Type ArgSpec named tuple Signature object
*Handles `args`** Yes (varargs attribute) Yes (*param_name in string)
Handles `kwargs`** Yes (keywords attribute) Yes (**param_name in string)
Handles Keyword-Only No (Major weakness) Yes (Clear separator)
Handles Positional-Only No (Major weakness) Yes (Clear separator)
Handles Type Hints No Yes (param.annotation attribute)
Default Values Tuple of defaults (defaults) param.default for each parameter
Recommendation AVOID for new code. Use only for legacy code. USE THIS for all new code.

Final Code Example: Migration

Here is how you would conceptually migrate logic from getargspec to signature.

Old Way (getargspec)

import inspect
# This function has defaults and *args
def old_style_func(x, y=5, *items):
    pass
spec = inspect.getargspec(old_style_func)
if spec.defaults:
    num_defaults = len(spec.defaults)
    required_args = spec.args[:-num_defaults]
    optional_args = spec.args[-num_defaults:]
else:
    required_args = spec.args
    optional_args = []
print(f"Required Args: {required_args}")
print(f"Optional Args: {optional_args}")
print(f"Varargs: {spec.varargs}")

New Way (signature)

import inspect
def old_style_func(x, y=5, *items):
    pass
sig = inspect.signature(old_style_func)
required_args = []
optional_args = []
varargs_name = None
for name, param in sig.parameters.items():
    if param.kind == param.POSITIONAL_OR_KEYWORD:
        if param.default is param.empty:
            required_args.append(name)
        else:
            optional_args.append(name)
    elif param.kind == param.VAR_POSITIONAL: # This is *args
        varargs_name = name
print(f"Required Args: {required_args}")
print(f"Optional Args: {optional_args}")
print(f"Varargs: {varargs_name}")

The new way is more verbose but far more accurate and robust, especially as function signatures become more complex with modern Python features.

分享:
扫描分享到社交APP
上一篇
下一篇