Bir fonksiyonun aldığı anahtar kelime argümanlarını listeleyebilir misiniz?


104

Anahtar / değerleri anahtar kelime argümanları olarak geçirmem gereken bir dikte sahibim .. Örneğin ..

d_args = {'kw1': 'value1', 'kw2': 'value2'}
example(**d_args)

Bu iyi çalışıyor, ancak d_args diktinde exampleişlev tarafından kabul edilmeyen değerler varsa , açıkça ölür .. Örneğin, örnek işlev olarak tanımlanırsadef example(kw2):

Ne neslini d_argsne de exampleişlevini kontrol etmediğim için bu bir sorun . Her ikisi de harici modüllerden geliyor ve examplesadece diktetteki anahtar kelime argümanlarının bazılarını kabul ediyor ..

İdeal olarak yapardım

parsed_kwargs = feedparser.parse(the_url)
valid_kwargs = get_valid_kwargs(parsed_kwargs, valid_for = PyRSS2Gen.RSS2)
PyRSS2Gen.RSS2(**valid_kwargs)

Muhtemelen, geçerli anahtar kelime argümanları listesinden dikteyi filtreleyeceğim, ancak merak ediyordum: Belirli bir fonksiyonun aldığı anahtar kelime argümanlarını programatik olarak listelemenin bir yolu var mı?

Yanıtlar:


150

Doğrudan kod nesnesini incelemekten ve değişkenler üzerinde çalışmaktan biraz daha iyi, inceleme modülünü kullanmaktır.

>>> import inspect
>>> def func(a,b,c=42, *args, **kwargs): pass
>>> inspect.getargspec(func)
(['a', 'b', 'c'], 'args', 'kwargs', (42,))

Belirli bir argüman setiyle çağrılabilir olup olmadığını bilmek istiyorsanız, önceden belirlenmiş bir varsayılan olmadan argümanlara ihtiyacınız vardır. Bunlar şu şekilde elde edilebilir:

def getRequiredArgs(func):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if defaults:
        args = args[:-len(defaults)]
    return args   # *args and **kwargs are not required, so ignore them.

Daha sonra, belirli bir diktenizde neyi kaçırdığınızı söyleyen bir işlev:

def missingArgs(func, argdict):
    return set(getRequiredArgs(func)).difference(argdict)

Benzer şekilde, geçersiz bağımsız değişkenleri kontrol etmek için şunu kullanın:

def invalidArgs(func, argdict):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if varkw: return set()  # All accepted
    return set(argdict) - set(args)

Ve eğer çağrılabilir ise tam bir test:

def isCallableWithArgs(func, argdict):
    return not missingArgs(func, argdict) and not invalidArgs(func, argdict)

(Bu, yalnızca python'un arg ayrıştırması kadar iyidir. Herhangi bir çalışma zamanı, kwarg'larda geçersiz değerler için kontroller açıkça tespit edilemez.)


Güzel! Bu işlevi bilmiyordum!
DzinX

1
Kod nesnelerini kullanan yöntemin aşağı yukarı aynı olduğu göz önüne alındığında, bir modülü daha içe aktarmak zorunda kalmanın bir faydası var mı?
jmetz

@jmets - kesinlikle - bir kitaplık modülü kullanmak, kendinize ait bir modül kullanmaktan neredeyse her zaman daha iyidir. Ayrıca, kod nesnesindeki öznitelikler daha içseldir ve değişime açıktır (örneğin, bunun pyhon3'teki koda taşındığına dikkat edin ). Modülü geleceğe yönelik arayüz olarak kullanmak, bu dahili bileşenlerden bazılarının değişmesi durumunda sizi biraz daha fazla korur. Ayrıca, inceleyemeyeceğiniz işlevlere uygun bir tür hatası atmak gibi yapmayı düşünmemiş olabileceğiniz şeyleri de yapar (örn. C işlevleri).
Brian

13
inspect.getargspec(f)Python 3.0'dan beri kullanımdan kaldırılmıştır; modern yöntem inspect.signature(f).
gerrit

Bilginize, Cython ve Python'u desteklemek istiyorsanız, bu yöntem bir Cython'd işlevi üzerinde çalışmaz. co_varnamesSeçenek, diğer taraftan, hem de çalışır.
partofthething

32

Bu, tüm geçerli bağımsız değişkenlerin, anahtar sözcüklerin ve anahtar sözcük olmayanların adlarını yazdıracaktır:

def func(one, two="value"):
    y = one, two
    return y
print func.func_code.co_varnames[:func.func_code.co_argcount]

Bunun nedeni, ilkinin co_varnamesdaima parametreler olmasıdır (sonraki, yyukarıdaki örnekte olduğu gibi yerel değişkenlerdir ).

Şimdi bir işleve sahip olabilirsiniz:

def getValidArgs(func, argsDict):
    '''Return dictionary without invalid function arguments.'''
    validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
    return dict((key, value) for key, value in argsDict.iteritems() 
                if key in validArgs)

Daha sonra bunun gibi kullanabilirsiniz:

>>> func(**getValidArgs(func, args))

DÜZENLEME : Küçük bir ekleme: Bir işlevin yalnızca anahtar kelime argümanlarına gerçekten ihtiyacınız varsa, func_defaultsbunları ayıklamak için özelliği kullanabilirsiniz :

def getValidKwargs(func, argsDict):
    validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
    kwargsLen = len(func.func_defaults) # number of keyword arguments
    validKwargs = validArgs[-kwargsLen:] # because kwargs are last
    return dict((key, value) for key, value in argsDict.iteritems() 
                if key in validKwargs)

Artık işlevinizi bilinen bağımsız değişkenlerle çağırabilirsiniz, ancak çıkarılmış kwargs, örneğin:

func(param1, param2, **getValidKwargs(func, kwargsDict))

Bu varsayar funckullandığı hiçbir *argsya **kwargsda imzası büyü.


Ya sadece "anahtar kelime" bağımsız değişkenleri "anahtarlarını" yazdırmak istersem?
Jia

7

Python 3.0'da:

>>> import inspect
>>> import fileinput
>>> print(inspect.getfullargspec(fileinput.input))
FullArgSpec(args=['files', 'inplace', 'backup', 'bufsize', 'mode', 'openhook'],
varargs=None, varkw=None, defaults=(None, 0, '', 0, 'r', None), kwonlyargs=[], 
kwdefaults=None, annotations={})

7

Bir Python 3 çözümü için, parametre türlerineinspect.signature göre kullanabilir ve filtreleyebilirsiniz . bilmek istediğiniz .

Konumsal veya anahtar kelime, yalnızca anahtar kelime, var konumsal ve var anahtar kelime parametreleriyle örnek bir işlev almak:

def spam(a, b=1, *args, c=2, **kwargs):
    print(a, b, args, c, kwargs)

Bunun için bir imza nesnesi oluşturabilirsiniz:

from inspect import signature
sig =  signature(spam)

ve ardından ihtiyacınız olan ayrıntıları bulmak için bir liste anlayışı ile filtreleyin:

>>> # positional or keyword
>>> [p.name for p in sig.parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD]
['a', 'b']
>>> # keyword only
>>> [p.name for p in sig.parameters.values() if p.kind == p.KEYWORD_ONLY]
['c']

ve benzer şekilde, p.VAR_POSITIONALile ve anahtar sözcüğünü kullanan değişken konumsallar için VAR_KEYWORD.

Ayrıca, p.defaultşuna eşit olup olmadığını kontrol ederek varsayılan bir değerin var olup olmadığını kontrol etmek için eğer ifadesine bir cümle ekleyebilirsiniz p.empty.


3

DzinX'in cevabını genişletmek:

argnames = example.func_code.co_varnames[:func.func_code.co_argcount]
args = dict((key, val) for key,val in d_args.iteritems() if key in argnames)
example(**args)
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.