Làm cách nào tôi có thể đọc chữ ký của hàm bao gồm các giá trị đối số mặc định?


129

Đưa ra một đối tượng hàm, làm thế nào tôi có thể có được chữ ký của nó? Ví dụ: cho:

def myMethod(firt, second, third='something'):
    pass

Tôi muốn nhận được "myMethod(firt, second, third='something')".


3
Bạn có thể vui lòng giải thích về câu hỏi cụ thể của bạn và có thể đưa ra một ví dụ với kết quả mong đợi?
jhwist

Có lẽ anh ta đang tìm kiếm chức năng trong các thư viện Python hoặc bên thứ ba sẽ trả về chữ ký của phương thức (tên và loại tham số và giá trị trả về) được đặt tên của phương thức.
Michael Petrotta

1
Chữ ký như thế nào để gọi nó và như vậy? Hãy thử help(yourmethod)ví dụhelp(map)
Nick T

Câu trả lời:


187
import inspect

def foo(a, b, x='blah'):
    pass

print(inspect.getargspec(foo))
# ArgSpec(args=['a', 'b', 'x'], varargs=None, keywords=None, defaults=('blah',))

Tuy nhiên, lưu ý rằng inspect.getargspec()không được dùng kể từ Python 3.0.

Python 3.0--3.4 khuyến nghị inspect.getfullargspec().

Python 3.5+ khuyến nghị inspect.signature().


AttributionError: đối tượng 'mô-đun' không có thuộc tính 'getargspec'
Spì

3
@Spi, bạn đang gọi inspect.getargspectrên một mô-đun, không phải là một chức năng.
Mike Graham

Cảm ơn, sự cố xảy ra với Eclipse không thấy mô-đun kiểm tra
Spì

Nếu một hàm có chú thích đối số hoặc chỉ đối số từ khóa (= nếu bạn đang sử dụng Python 3), bạn phải gọi getfullargspecthay thế. ( ValueError: Function has keyword-only arguments or annotations, use getfullargspec() API which can support them)
badp

2
@darth_coder: Trong Python2, getargspectăng TypeErrornếu đầu vào không được nhận dạng là hàm Python - nghĩa là, một hàm được triển khai trong Python. Trong CPython, Exception.__init__được thực hiện trong C, do đó TypeError. Bạn sẽ phải kiểm tra mã nguồn để hiểu chữ ký cuộc gọi. Trong Python3, getargspecđược triển khai khác nhau và inspect.getargspec(Exception.__init__)trả về một ArgSpecthể hiện.
unutbu

44

Có thể cho rằng cách dễ nhất để tìm chữ ký cho hàm là help(function):

>>> def function(arg1, arg2="foo", *args, **kwargs): pass
>>> help(function)
Help on function function in module __main__:

function(arg1, arg2='foo', *args, **kwargs)

Ngoài ra, trong Python 3, một phương thức đã được thêm vào inspectmô-đun được gọi signature, được thiết kế để thể hiện chữ ký của một đối tượng có thể gọi được và chú thích trả về của nó :

>>> from inspect import signature
>>> def foo(a, *, b:int, **kwargs):
...     pass

>>> sig = signature(foo)

>>> str(sig)
'(a, *, b:int, **kwargs)'

>>> str(sig.parameters['b'])
'b:int'

>>> sig.parameters['b'].annotation
<class 'int'>

3
inspect.signaturecũng có sẵn cho Python 2 thông qua funcsigsdự án backport: pypi.python.org/pypi/funcsigs
ncoghlan

14
#! /usr/bin/env python

import inspect
from collections import namedtuple

DefaultArgSpec = namedtuple('DefaultArgSpec', 'has_default default_value')

def _get_default_arg(args, defaults, arg_index):
    """ Method that determines if an argument has default value or not,
    and if yes what is the default value for the argument

    :param args: array of arguments, eg: ['first_arg', 'second_arg', 'third_arg']
    :param defaults: array of default values, eg: (42, 'something')
    :param arg_index: index of the argument in the argument array for which,
    this function checks if a default value exists or not. And if default value
    exists it would return the default value. Example argument: 1
    :return: Tuple of whether there is a default or not, and if yes the default
    value, eg: for index 2 i.e. for "second_arg" this function returns (True, 42)
    """
    if not defaults:
        return DefaultArgSpec(False, None)

    args_with_no_defaults = len(args) - len(defaults)

    if arg_index < args_with_no_defaults:
        return DefaultArgSpec(False, None)
    else:
        value = defaults[arg_index - args_with_no_defaults]
        if (type(value) is str):
            value = '"%s"' % value
        return DefaultArgSpec(True, value)

def get_method_sig(method):
    """ Given a function, it returns a string that pretty much looks how the
    function signature would be written in python.

    :param method: a python method
    :return: A string similar describing the pythong method signature.
    eg: "my_method(first_argArg, second_arg=42, third_arg='something')"
    """

    # The return value of ArgSpec is a bit weird, as the list of arguments and
    # list of defaults are returned in separate array.
    # eg: ArgSpec(args=['first_arg', 'second_arg', 'third_arg'],
    # varargs=None, keywords=None, defaults=(42, 'something'))
    argspec = inspect.getargspec(method)
    arg_index=0
    args = []

    # Use the args and defaults array returned by argspec and find out
    # which arguments has default
    for arg in argspec.args:
        default_arg = _get_default_arg(argspec.args, argspec.defaults, arg_index)
        if default_arg.has_default:
            args.append("%s=%s" % (arg, default_arg.default_value))
        else:
            args.append(arg)
        arg_index += 1
    return "%s(%s)" % (method.__name__, ", ".join(args))


if __name__ == '__main__':
    def my_method(first_arg, second_arg=42, third_arg='something'):
        pass

    print get_method_sig(my_method)
    # my_method(first_argArg, second_arg=42, third_arg="something")

Bất kỳ lời giải thích nào về những gì được cho là phải làm gì?
Grantmcconnaughey

1
Đã thêm ý kiến ​​cho mẫu mã, hy vọng rằng sẽ giúp.
Arup Malakar

Thứ đáng yêu. Sẽ tốt hơn nữa nếu bạn có thể điều chỉnh nó để hoạt động với def foo(a, *, b:int, **kwargs)được gọi bằngfoo(4, b=3.3)
ofer.sheffer

8

Hãy thử gọi helpmột đối tượng để tìm hiểu về nó.

>>> foo = [1, 2, 3]
>>> help(foo.append)
Help on built-in function append:

append(...)
    L.append(object) -- append object to end

7

Có thể hơi muộn cho bữa tiệc, nhưng nếu bạn cũng muốn giữ trật tự của các đối số và mặc định của chúng , thì bạn có thể sử dụng mô-đun Tóm tắt Cú pháp Cây (ast) .

Đây là một bằng chứng về khái niệm (hãy cẩn thận mã để sắp xếp các đối số và khớp chúng với mặc định của chúng chắc chắn có thể được cải thiện / làm rõ hơn):

import ast

for class_ in [c for c in module.body if isinstance(c, ast.ClassDef)]:
    for method in [m for m in class_.body if isinstance(m, ast.FunctionDef)]:
        args = []
        if method.args.args:
            [args.append([a.col_offset, a.id]) for a in method.args.args]
        if method.args.defaults:
            [args.append([a.col_offset, '=' + a.id]) for a in method.args.defaults]
        sorted_args = sorted(args)
        for i, p in enumerate(sorted_args):
            if p[1].startswith('='):
                sorted_args[i-1][1] += p[1]
        sorted_args = [k[1] for k in sorted_args if not k[1].startswith('=')]

        if method.args.vararg:
            sorted_args.append('*' + method.args.vararg)
        if method.args.kwarg:
            sorted_args.append('**' + method.args.kwarg)

        signature = '(' + ', '.join(sorted_args) + ')'

        print method.name + signature

Lưu ý rằng các đối số không mặc định có thể tuân theo các đối số mặc định , vì vậy chúng ta có thể khớp chúng từ đuôi không?
Evgeni Sergeev

5

Nếu tất cả những gì bạn đang cố gắng làm là in chức năng thì hãy sử dụng pydoc.

import pydoc    

def foo(arg1, arg2, *args, **kwargs):                                                                    
    '''Some foo fn'''                                                                                    
    pass                                                                                                 

>>> print pydoc.render_doc(foo).splitlines()[2]
foo(arg1, arg2, *args, **kwargs)

Nếu bạn đang cố gắng thực sự phân tích chữ ký hàm thì hãy sử dụng argspec của mô-đun kiểm tra. Tôi đã phải làm điều đó khi xác nhận chức năng tập lệnh hook của người dùng vào một khung chung.


3

Mã ví dụ:

import inspect
from collections import OrderedDict


def get_signature(fn):
    params = inspect.signature(fn).parameters
    args = []
    kwargs = OrderedDict()
    for p in params.values():
        if p.default is p.empty:
            args.append(p.name)
        else:
            kwargs[p.name] = p.default
    return args, kwargs


def test_sig():
    def fn(a, b, c, d=3, e="abc"):
        pass

    assert get_signature(fn) == (
        ["a", "b", "c"], OrderedDict([("d", 3), ("e", "abc")])
    )

2

Sử dụng% pdef trong dòng lệnh (IPython), nó sẽ chỉ in chữ ký.

ví dụ %pdef np.loadtxt

 np.loadtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0, encoding='bytes')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.