Varsayılan bağımsız değişken değerleri dahil olmak üzere bir işlevin imzasını nasıl okuyabilirim?


129

Bir fonksiyon nesnesi verildiğinde, onun imzasını nasıl alabilirim? Örneğin:

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

Ben almak isterim "myMethod(firt, second, third='something')".


3
Lütfen sorunuzu detaylandırabilir ve beklenen sonucu içeren bir örnek verebilir misiniz?
jhwist

Muhtemelen, Python'da veya üçüncü taraf kitaplıklarda, yöntemin adı verildiğinde bir yöntemin imzasını (adlar ve parametrelerin türleri ve dönüş değeri) döndürecek işlevsellik arıyor.
Michael Petrotta

1
İmza, nasıl adlandırılacağı gibi falan? help(yourmethod)Örneğin deneyinhelp(map)
Nick T

Yanıtlar:


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',))

Ancak, bunun inspect.getargspec()Python 3.0'dan beri kullanımdan kaldırıldığını unutmayın .

Python 3.0-3.4 önerir inspect.getfullargspec().

Python 3.5+ önerir inspect.signature().


AttributeError: "modül" nesnesinin "getargspec" özniteliği yok
Spì

3
@Spi, inspect.getargspecbir modül için arama yapıyorsunuz, bir işlev değil.
Mike Graham

Teşekkürler, sorun, inceleme modülünü görmeyen Eclipse ile
ilgiliydi

Bir işlevin bağımsız değişken ek açıklamaları veya yalnızca anahtar sözcük bağımsız değişkenleri varsa (= Python 3 kullanıyorsanız) getfullargspecbunun yerine çağırmanız gerekir . ( ValueError: Function has keyword-only arguments or annotations, use getfullargspec() API which can support them)
badp

2
@darth_coder: Python2'de, girdi bir Python işlevi, yani Python'da uygulanan bir işlev olarak tanınmazsa getargspecyükseltir . CPython'da, C'de uygulanır, dolayısıyla . Çağrı imzasını anlamak için kaynak kodunu kontrol etmeniz gerekecek. Python3'te farklı şekilde uygulanır ve bir örnek döndürür . TypeErrorException.__init__TypeErrorgetargspecinspect.getargspec(Exception.__init__)ArgSpec
unutbu

44

Muhtemelen bir işlevin imzasını bulmanın en kolay yolu şudur 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)

Ayrıca, Python 3'te inspectçağrılan modüle signature, çağrılabilir bir nesnenin imzasını ve dönüş açıklamasını temsil etmek için tasarlanmış bir yöntem eklenmiştir :

>>> 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.signatureayrıca funcsigsarka plan
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")

Bunun ne yapması gerektiğine dair herhangi bir açıklama var mı?
grantmcconnaughey

1
Kod örneğine yorumlar eklendi, umarım yardımcı olur.
Arup Malakar

Harika şeyler. def foo(a, *, b:int, **kwargs)foo(4, b=3.3)
ofer.sheffer

8

Bunu helpöğrenmek için bir nesneyi aramayı deneyin .

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

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

7

Partiye biraz geç kalmış olabilir, ancak argümanların sırasını ve varsayılanlarını da korumak istiyorsanız , Soyut Sözdizimi Ağacı modülünü (ast) kullanabilirsiniz .

İşte bir kavram kanıtı (argümanları sıralamak ve bunları varsayılan değerleriyle eşleştirmek için koda dikkat edin, kesinlikle geliştirilebilir / daha net hale getirilebilir):

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

O Not varsayılan olmayan argümanlar varsayılan argümanlar takip edemez biz sadece kuyruğundan onları maç, böylece?
Evgeni Sergeev

5

Yapmaya çalıştığınız tek şey işlevi yazdırmaksa, pydoc kullanın.

import pydoc    

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

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

İşlev imzasını gerçekten analiz etmeye çalışıyorsanız, denetleme modülünün argspec'ini kullanın. Bunu, bir kullanıcının kanca komut dosyası işlevini genel bir çerçeveye doğrularken yapmak zorundaydım.


3

Örnek kod:

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

Komut satırında (IPython)% pdef kullanın, yalnızca imzayı yazdıracaktır.

Örneğin %pdef np.loadtxt

 np.loadtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0, encoding='bytes')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.