* Args और ** kwargs के साथ डिफ़ॉल्ट तर्क


84

में अजगर 2.x (मैं 2.7 का उपयोग करें), जो के साथ डिफ़ॉल्ट तर्क का उपयोग करने के लिए उचित तरीका है *argsऔर **kwargs?
मुझे इस विषय से संबंधित SO पर एक प्रश्न मिला है, लेकिन वह पायथन 3 के लिए है :
* args, ** kwargs और वैकल्पिक / डिफ़ॉल्ट तर्क के साथ पायथन फ़ंक्शन को कॉल करना

वहाँ, वे कहते हैं कि यह विधि काम करती है:

def func(arg1, arg2, *args, opt_arg='def_val', **kwargs):
    #...

2.7 में, यह एक में परिणाम है SyntaxError। क्या ऐसे फ़ंक्शन को परिभाषित करने का कोई अनुशंसित तरीका है?
मैं इसे इस तरह से काम कर रहा था, लेकिन मुझे लगता है कि वहाँ एक अच्छा समाधान है।

def func(arg1, arg2, *args, **kwargs):
    opt_arg ='def_val'
    if kwargs.__contains__('opt_arg'):
        opt_arg = kwargs['opt_arg']
    #...

अभी भी सबसे अधिक स्पष्ट व्याख्या जो मैंने चलाई है: saltycrane.com/blog/2008/01/…
— verbsintransit

4
कभी भी स्पष्ट रूप से कॉल न करें __contains__। हमेशा का उपयोग करें in: 'opt_arg' in kwargs। (इससे भी बेहतर: के kwargs.get('opt_arg', 'def_val')रूप में mgilson के जवाब में)।
— nnonneo 19

जवाबों:


80

पहले डिफ़ॉल्ट तर्क रखें *args:

def foo(a, b=3, *args, **kwargs):

अब, bस्पष्ट रूप से सेट हो जाएगा यदि आप एक खोजशब्द तर्क या दूसरे स्थितीय तर्क के रूप में इसे पारित।

उदाहरण:

foo(x) # a=x, b=3, args=(), kwargs={}
foo(x, y) # a=x, b=y, args=(), kwargs={}
foo(x, b=y) # a=x, b=y, args=(), kwargs={}
foo(x, y, z, k) # a=x, b=y, args=(z, k), kwargs={}
foo(x, c=y, d=k) # a=x, b=3, args=(), kwargs={'c': y, 'd': k}
foo(x, c=y, b=z, d=k) # a=x, b=z, args=(), kwargs={'c': y, 'd': k}

ध्यान दें, विशेष रूप से, foo(x, y, b=z)काम नहीं करता है क्योंकि bउस स्थिति में स्थिति द्वारा सौंपा गया है।


यह कोड पायथन 3 में भी काम करता है। पाइथन 3 के बाद डिफॉल्ट arg को डालना *argsएक "कीवर्ड-ओनली" तर्क बनाता है जिसे केवल नाम से निर्दिष्ट किया जा सकता है, स्थिति से नहीं। यदि आप Python 2 में एक कीवर्ड-केवल तर्क चाहते हैं, तो आप @ mgilson के समाधान का उपयोग कर सकते हैं।


1
हाँ, यह अस्पष्टता के कारण है *args। यदि आप एक खोजशब्द-केवल तर्क चाहते हैं तो आपका रास्ता सही है।
— nnonneo

बस इसे उपरोक्त टिप्पणियों में उत्तर मिला। (क्या होगा अगर मैं एक अलग बी के साथ फ़ंक्शन को कॉल करना चाहता हूं, और इसके अलावा मैं * args जोड़ना चाहता हूं?)

वैसे भी, पूछने से पहले, मैंने इस समाधान की कोशिश की, लेकिन मुझे यह भी पता चला कि केवल ऑप्टगार्ग को परिभाषित करने के बाद ही मैंने काम किया है, मैं केवल बौनों का उपयोग करता हूं।

@nneonneo: मुझे आपके उदाहरण मिले, लेकिन इस तरह से अभी भी हमें डिफ़ॉल्ट तर्क निर्दिष्ट करने की स्वतंत्रता नहीं मिली है और * उसी समय, जैसे कि पायथन 3.x इसे अनुमति देता है, जैसा कि लिंक में बताया गया है; क्या यह?

5
नहीं *args, भरते समय आप एक डिफ़ॉल्ट तर्क को अकेले नहीं छोड़ सकते । यही कारण है कि कार्यक्षमता को पायथन 3 में जोड़ा गया था। आमतौर पर, पायथन 2 में डिफ़ॉल्ट तर्क 0 या कुछ के रूप में स्पष्ट होते हैं Noneताकि उन्हें स्पष्ट रूप से पारित किया जा सके।
— nneonneo

55

अन्य प्रश्न में सिंटैक्स केवल python3.x है और कीवर्ड को केवल तर्क निर्दिष्ट करता है। यह python2.x पर काम नहीं करता है।

Python2.x के लिए, मैं popइसे kwargs से बाहर करूंगा :

def func(arg1, arg2, *args, **kwargs):
    opt_arg = kwargs.pop('opt_arg', 'def_val')

यह डिफ़ॉल्ट तर्क से पहले * आर्ग्स को भी निर्दिष्ट करता है।

4

आप इस तरह से एक डेकोरेटर का उपयोग कर सकते हैं:

import functools
def default_kwargs(**defaultKwargs):
    def actual_decorator(fn):
        @functools.wraps(fn)
        def g(*args, **kwargs):
            defaultKwargs.update(kwargs)
            return fn(*args, **defaultKwargs)
        return g
    return actual_decorator

तो बस करो:

@default_kwargs(defaultVar1 = defaultValue 1, ...)
def foo(*args, **kwargs):
    # Anything in here

उदाहरण के लिए:

@default_kwargs(a=1)
def f(*args, **kwargs):
    print(kwargs['a']+ 1)

f() # Returns 2
f(3) # Returns 4

1

अपने समाधान दृष्टिकोण के काफी करीब चिपके रहते हुए इसे और अधिक सामान्य बनाने की कोशिश करते हुए और अधिक कॉम्पैक्ट मैं कुछ इस तरह से विचार करने का सुझाव दूंगा:

>>> def func(arg1, arg2, *args, **kwargs):
...     kwargs_with_defaults = dict({'opt_arg': 'def_val', 'opt_arg2': 'default2'}, **kwargs)
...     #...
...     return arg1, arg2, args, kwargs_with_defaults

>>> func('a1', 'a2', 'a3', 'a5', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'def_val', 'y': 'bar', 'x': 'foo'})

>>> func('a1', 'a2', 'a3', 'a5', opt_arg='explicit_value', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'explicit_value', 'y': 'bar', 'x': 'foo'})

0

पायथन 2.x से निपटने का दूसरा तरीका:

def foo(*args, **kwargs):
    if 'kwarg-name' not in kwargs.keys():
        kwargs['kwarg-name'] = 'kwarg-name-default-value'
    return bar(*args, **kwargs)

यह *args@ nneonneo के उत्तर के विपरीत अंतर्निहित कॉल के लिए मनमाने ढंग से गुजरता है।


1
यह स्पष्ट है अगर आप मान्य कोड का इस्तेमाल किया होगा, यानी 'opt_arg'बजाय < kwarg-name >और 'def_val'के बजाय< kwarg-name-default-value >
— wjandrea

0

यह उत्तर डैनियल अमेरीको द्वारा सुझाए गए का एक विस्तार है ।

यदि वे कड़ाई से परिभाषित नहीं हैं, तो यह डेकोरेटर डिफ़ॉल्ट कवार मान प्रदान करता है।

from functools import wraps

def force_kwargs(**defaultKwargs):
    def decorator(f):
        @wraps(f)
        def g(*args, **kwargs):
            new_args = {}
            new_kwargs = defaultKwargs
            varnames = f.__code__.co_varnames
            new_kwargs.update(kwargs)
            for k, v in defaultKwargs.items():
                if k in varnames:
                    i = varnames.index(k)
                    new_args[(i, k)] = new_kwargs.pop(k)
            # Insert new_args into the correct position of the args.
            full_args = list(args)
            for i, k in sorted(new_args.keys()):
                if i <= len(full_args):
                    full_args.insert(i, new_args.pop((i, k)))
                else:
                    break
            # re-insert the value as a key-value pair
            for (i, k), val in new_args.items():
                new_kwargs[k] = val
            return f(*tuple(full_args), **new_kwargs)
        return g
    return decorator

परिणाम

@force_kwargs(c=7)
def f(a, b='B', c='C', d='D', *args, **kw):
    return a, b, c, d, args, kw
#                               a    b  c    d  args      kwargs
f('r')                      # 'r', 'B', 7, 'D',   (),         {}
f(1,2,3)                    #   1,   2, 7,   3,   (),         {}
f(1, 2, 3, b=3, c=9, f='F') #   1,   3, 9,   2, (3,), {'f': 'F'}

प्रकार

यदि आप फ़ंक्शन परिभाषा में लिखे गए डिफ़ॉल्ट मानों का उपयोग करना चाहते हैं, तो आप तर्क डिफ़ॉल्ट मानों का उपयोग कर सकते हैं f.func_defaults, जो डिफ़ॉल्ट मानों को सूचीबद्ध करता है। आपको इन डिफ़ॉल्ट मानों को चर नामों के साथ मिलान करने के लिए zipउनके साथ होना होगा f.__code__.varnames।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.