विधि पैरामीटर नाम कैसे प्राप्त करें?


236

अजगर समारोह को देखते हुए:

def a_method(arg1, arg2):
    pass

मैं तर्कों की संख्या और नाम कैसे निकाल सकता हूं। यानी, यह देखते हुए कि मेरे पास एक संदर्भ है func, मैं चाहता हूं कि वह func.[something]वापस लौट आए ("arg1", "arg2")

इसके लिए उपयोग परिदृश्य यह है कि मेरे पास एक डेकोरेटर है, और मैं उसी क्रम में विधि तर्कों का उपयोग करना चाहता हूं जो वे एक कुंजी के रूप में वास्तविक फ़ंक्शन के लिए दिखाई देते हैं। यानी, "a,b"जब मैं बुलाऊंगा तो डेकोरेटर कैसा दिखेगा a_method("a", "b")?


1
लगभग समान प्रश्न के उत्तर की एक अलग सूची के लिए, इस अन्य
स्टैकओवरफ़्लो

1
आपका शीर्षक भ्रामक है: जब कोई 'विधि' शब्द 'फंक्शन' लिखता है, तो आमतौर पर एक क्लास विधि के बारे में सोचते हैं। फ़ंक्शन के लिए, आपका चयनित उत्तर (जौनी के। सेपनान से) अच्छा है। लेकिन (वर्ग) विधि के लिए, यह काम नहीं कर रहा है और निरीक्षण समाधान (ब्रायन से) का उपयोग किया जाना चाहिए।
जुह_

जवाबों:


351

inspectमॉड्यूल पर एक नज़र डालें - यह आपके लिए विभिन्न कोड ऑब्जेक्ट गुणों का निरीक्षण करेगा।

>>> inspect.getfullargspec(a_method)
(['arg1', 'arg2'], None, None, None)

अन्य परिणाम * args और ** kwargs चर, और प्रदान की गई चूक के नाम हैं। अर्थात।

>>> def foo(a, b, c=4, *arglist, **keywords): pass
>>> inspect.getfullargspec(foo)
(['a', 'b', 'c'], 'arglist', 'keywords', (4,))

ध्यान दें कि पायथन के कुछ कार्यान्वयन में कुछ कॉलबेल्ट इंट्रोस्पेक्टेबल नहीं हो सकते हैं। उदाहरण के लिए, सीपीथॉन में, सी में परिभाषित कुछ अंतर्निहित कार्य उनके तर्कों के बारे में कोई मेटाडेटा प्रदान नहीं करते हैं। नतीजतन, आपको एक अंतर्निहित फ़ंक्शन पर ValueErrorउपयोग करने inspect.getfullargspec()पर मिलेगा ।

पायथन 3.3 के बाद से, आप inspect.signature()कॉल करने योग्य ऑब्जेक्ट के कॉल हस्ताक्षर को देखने के लिए उपयोग कर सकते हैं :

>>> inspect.signature(foo)
<Signature (a, b, c=4, *arglist, **keywords)>

29
कोड संभवतः कैसे जान सकता है कि डिफ़ॉल्ट (4,)पैरामीटर cविशेष रूप से कीवर्ड पैरामीटर से मेल खाता है ?
फतुहोकू

63
@fatuhoku मैं एक ही बात सोच रहा था। यह बताता है कि यह अस्पष्ट नहीं है क्योंकि आप केवल एक सन्निहित ब्लॉक में अंत में डिफ़ॉल्ट तर्क जोड़ सकते हैं। डॉक्स से: "अगर इस टपल में n तत्व हैं, तो वे args में सूचीबद्ध अंतिम n तत्वों के अनुरूप हैं"
Soverman

9
मुझे लगता है कि जब से Python 3.x getargspec (...) को इंस्पेक्टर.सिग्नेचर (func) द्वारा प्रतिस्थापित किया गया है
डिएगो आंद्रेस डिसा एस्पिनोज़ा

2
2.6 संस्करण में बदल गया: एक नाम दिया टपल एर्गस्पेक (args, varargs, keywords, defaults)।
theannouncer

4
यह सही, @ DiegoAndrésDíazEspinoza है - अजगर 3 में, inspect.getargspecहै पदावनत , लेकिन प्रतिस्थापन है inspect.getfullargspec
जे ०8l० यू

100

CPython में, तर्कों की संख्या है

a_method.func_code.co_argcount

और उनके नाम की शुरुआत में हैं

a_method.func_code.co_varnames

ये CPython का कार्यान्वयन विवरण हैं, इसलिए यह संभवत: Python के अन्य कार्यान्वयनों, जैसे IronPython और Jython में काम नहीं करता है।

"पास-थ्रू" तर्कों को स्वीकार करने का एक पोर्टेबल तरीका यह है कि आप अपने फ़ंक्शन को हस्ताक्षर के साथ परिभाषित करें func(*args, **kwargs)। उदाहरण के लिए matplotlib में यह बहुत उपयोग किया जाता है , जहां बाहरी API परत निचले स्तर के एपीआई के लिए बहुत सारे खोजशब्द तर्क देती है।


co_varnames मानक पायथन के साथ काम करता है, लेकिन यह विधि बेहतर नहीं है क्योंकि यह आंतरिक तर्कों को भी प्रदर्शित करेगा।
मटका

11
AMethod.func_code.co_varnames [: aMethod.func_code.co_argcount] का उपयोग क्यों नहीं किया जाता है?
होचेल

तर्क के साथ काम नहीं करने के बाद *args, उदाहरण के लिए:def foo(x, *args, y, **kwargs): # foo.__code__.co_argcount == 1
निकोले माखालिन


कृपया इसके बजाय निरीक्षण का उपयोग करें। अन्यथा, 3.4+ में आपके कोड काम नहीं कर रहे हैं। देखें stackoverflow.com/questions/147816/…
ब्रायन मैककचटन

22

एक डेकोरेटर विधि में, आप मूल विधि के तर्कों को इस तरह से सूचीबद्ध कर सकते हैं:

import inspect, itertools 

def my_decorator():

        def decorator(f):

            def wrapper(*args, **kwargs):

                # if you want arguments names as a list:
                args_name = inspect.getargspec(f)[0]
                print(args_name)

                # if you want names and values as a dictionary:
                args_dict = dict(itertools.izip(args_name, args))
                print(args_dict)

                # if you want values as a list:
                args_values = args_dict.values()
                print(args_values)

यदि आप के **kwargsलिए महत्वपूर्ण हैं, तो यह थोड़ा जटिल होगा:

        def wrapper(*args, **kwargs):

            args_name = list(OrderedDict.fromkeys(inspect.getargspec(f)[0] + kwargs.keys()))
            args_dict = OrderedDict(list(itertools.izip(args_name, args)) + list(kwargs.iteritems()))
            args_values = args_dict.values()

उदाहरण:

@my_decorator()
def my_function(x, y, z=3):
    pass


my_function(1, y=2, z=3, w=0)
# prints:
# ['x', 'y', 'z', 'w']
# {'y': 2, 'x': 1, 'z': 3, 'w': 0}
# [1, 2, 3, 0]

यह उत्तर आंशिक रूप से अप्रचलित है और इसे अद्यतन किया जाना चाहिए।
इमोगो

15

मुझे लगता है कि आप जो खोज रहे हैं वह स्थानीय पद्धति है -


In [6]: def test(a, b):print locals()
   ...: 

In [7]: test(1,2)              
{'a': 1, 'b': 2}

7
यह एक फ़ंक्शन के बाहर बेकार है जो कि यहां ब्याज का संदर्भ है (डेकोरेटर)।
पायोत्र डोब्रोगोस्ट

8
वास्तव में वास्तव में मैं क्या देख रहा था, हालांकि यह यहां सवाल का जवाब नहीं है।
javabeangrinder 12

15

पायथन 3 संस्करण है:

def _get_args_dict(fn, args, kwargs):
    args_names = fn.__code__.co_varnames[:fn.__code__.co_argcount]
    return {**dict(zip(args_names, args)), **kwargs}

विधि एक शब्द देता है जिसमें आर्ग और क्वार्ग दोनों होते हैं।


ध्यान दें कि [:fn.__code__.co_argcount]यदि आप फ़ंक्शन तर्कों की तलाश कर रहे हैं तो यह बहुत महत्वपूर्ण है - अन्यथा इसमें फ़ंक्शन के भीतर बनाए गए नाम भी शामिल हैं।
सोरेन Bjornstad

13

यहाँ कुछ ऐसा है जो मुझे लगता है कि डेकोरेटर का उपयोग करके आप जो चाहते हैं, उसके लिए काम करेंगे।

class LogWrappedFunction(object):
    def __init__(self, function):
        self.function = function

    def logAndCall(self, *arguments, **namedArguments):
        print "Calling %s with arguments %s and named arguments %s" %\
                      (self.function.func_name, arguments, namedArguments)
        self.function.__call__(*arguments, **namedArguments)

def logwrap(function):
    return LogWrappedFunction(function).logAndCall

@logwrap
def doSomething(spam, eggs, foo, bar):
    print "Doing something totally awesome with %s and %s." % (spam, eggs)


doSomething("beans","rice", foo="wiggity", bar="wack")

इसे चलाएं, यह निम्नलिखित उत्पादन प्राप्त करेगा:

C:\scripts>python decoratorExample.py
Calling doSomething with arguments ('beans', 'rice') and named arguments {'foo':
 'wiggity', 'bar': 'wack'}
Doing something totally awesome with beans and rice.

11

पायथन 3.5+:

DeprecationWarning: inspect.getargspec () पदावनत किया जाता है, इसके बजाय निरीक्षण (असाइनमेंट) का उपयोग करें

तो पहले:

func_args = inspect.getargspec(function).args

अभी:

func_args = list(inspect.signature(function).parameters.keys())

परीक्षा करना:

'arg' in list(inspect.signature(function).parameters.keys())

यह देखते हुए कि हमारे पास फ़ंक्शन 'फ़ंक्शन' है जो तर्क 'arg' लेता है, यह सच के रूप में मूल्यांकन करेगा, अन्यथा झूठी के रूप में।

पायथन कंसोल से उदाहरण:

Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] on win32
>>> import inspect
>>> 'iterable' in list(inspect.signature(sum).parameters.keys())
True

8

पायथन में 3. Signatureहाथ में ऑब्जेक्ट के साथ , मूल्यों के लिए तर्क नामों के बीच मानचित्रण प्राप्त करने का एक आसान तरीका, हस्ताक्षर bind()विधि का उपयोग कर रहा है!

उदाहरण के लिए, यहाँ एक मानचित्र को प्रिंट करने के लिए एक डेकोरेटर है जैसे:

import inspect

def decorator(f):
    def wrapper(*args, **kwargs):
        bound_args = inspect.signature(f).bind(*args, **kwargs)
        bound_args.apply_defaults()
        print(dict(bound_args.arguments))

        return f(*args, **kwargs)

    return wrapper

@decorator
def foo(x, y, param_with_default="bars", **kwargs):
    pass

foo(1, 2, extra="baz")
# This will print: {'kwargs': {'extra': 'baz'}, 'param_with_default': 'bars', 'y': 2, 'x': 1}

6

यहां किसी भी मॉड्यूल का उपयोग किए बिना फ़ंक्शन पैरामीटर प्राप्त करने का एक और तरीका है।

def get_parameters(func):
    keys = func.__code__.co_varnames[:func.__code__.co_argcount][::-1]
    sorter = {j: i for i, j in enumerate(keys[::-1])} 
    values = func.__defaults__[::-1]
    kwargs = {i: j for i, j in zip(keys, values)}
    sorted_args = tuple(
        sorted([i for i in keys if i not in kwargs], key=sorter.get)
    )
    sorted_kwargs = {}
    for i in sorted(kwargs.keys(), key=sorter.get):
        sorted_kwargs[i] = kwargs[i]      
    return sorted_args, sorted_kwargs


def f(a, b, c="hello", d="world"): var = a


print(get_parameters(f))

आउटपुट:

(('a', 'b'), {'c': 'hello', 'd': 'world'})

2

तर्क नामों की सूची लौटाता है, विभाजन और नियमित कार्यों की देखभाल करता है:

def get_func_args(f):
    if hasattr(f, 'args'):
        return f.args
    else:
        return list(inspect.signature(f).parameters)

2

ब्रायन के जवाब के लिए अपडेट करें :

यदि पायथन 3 में एक फ़ंक्शन में केवल कीवर्ड तर्क हैं, तो आपको उपयोग करने की आवश्यकता है inspect.getfullargspec:

def yay(a, b=10, *, c=20, d=30):
    pass
inspect.getfullargspec(yay)

इसकी पैदावार:

FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(10,), kwonlyargs=['c', 'd'], kwonlydefaults={'c': 20, 'd': 30}, annotations={})

2

अजगर 3 में, नीचे *argsऔर **kwargsएक में बनाना है dict( आदेशों OrderedDictको बनाए रखने के लिए अजगर <3.6 का उपयोग करें dict):

from functools import wraps

def display_param(func):
    @wraps(func)
    def wrapper(*args, **kwargs):

        param = inspect.signature(func).parameters
        all_param = {
            k: args[n] if n < len(args) else v.default
            for n, (k, v) in enumerate(param.items()) if k != 'kwargs'
        }
        all_param .update(kwargs)
        print(all_param)

        return func(**all_param)
    return wrapper

1

inspect.signatureबहुत धीमा है। सबसे तेज़ तरीका है

def f(a, b=1, *args, c, d=1, **kwargs):
   pass

f_code = f.__code__
f_code.co_varnames[:f_code.co_argcount + f_code.co_kwonlyargcount]  # ('a', 'b', 'c', 'd')

0

थोड़ा सा ब्रायन के उत्तर को अपडेट करने के लिए , अब एक अच्छा बैकपोर्ट है inspect.signatureजिसे आप पुराने अजगर संस्करणों में उपयोग कर सकते हैं funcsigs:। इसलिए मेरी व्यक्तिगत प्राथमिकता रहेगी

try:  # python 3.3+
    from inspect import signature
except ImportError:
    from funcsigs import signature

def aMethod(arg1, arg2):
    pass

sig = signature(aMethod)
print(sig)

मज़े के लिए, अगर आप Signatureवस्तुओं के साथ खेलने में रुचि रखते हैं और यहां तक ​​कि यादृच्छिक हस्ताक्षर के साथ फ़ंक्शन बनाते हुए गतिशील रूप से आप मेरी makefunपरियोजना पर नज़र डाल सकते हैं ।


-3

अब dir()और क्या vars()?

लगता है कि वास्तव में क्या सुपर बस पूछा जा रहा है ...

फ़ंक्शन स्कोप के भीतर से बुलाया जाना चाहिए।

लेकिन सावधान रहें कि यह सभी स्थानीय चरों को लौटा देगा, इसलिए यदि आवश्यक हो तो फ़ंक्शन की शुरुआत में इसे करना सुनिश्चित करें।

यह भी ध्यान दें, जैसा कि टिप्पणियों में बताया गया है, यह इसे दायरे के बाहर से करने की अनुमति नहीं देता है। इसलिए ओपी का परिदृश्य ठीक नहीं है लेकिन फिर भी प्रश्न शीर्षक से मेल खाता है। इसलिए मेरा जवाब।


dir () सभी वैरिएबल नामों की सूची ('var1', 'var2'], vars () रिटर्न डिक्शनरी में फॉर्म {'var1': 0, 'var2': 'something'} वर्तमान स्थानीय दायरे के भीतर से। यदि कोई फ़ंक्शन में बाद में तर्क चर नाम का उपयोग करना चाहता है, तो उन्हें किसी अन्य स्थानीय चर में सहेजना चाहिए, क्योंकि बाद में इसे फ़ंक्शन में कॉल करना जहां वे एक और स्थानीय चर घोषित कर सकते हैं, इस सूची को "दूषित" करेगा। इस मामले में वे इसे फ़ंक्शन के बाहर उपयोग करना चाहते हैं, उन्हें कम से कम एक बार फ़ंक्शन चलाना होगा और इसे वैश्विक चर में सहेजना होगा। इसलिए निरीक्षण मॉड्यूल का उपयोग करना बेहतर है।
पीटर माजको
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.