पाइथन में ** क्वार्ग्स का उपयोग करने का उचित तरीका


454

**kwargsजब डिफ़ॉल्ट मानों की बात आती है तो पायथन में उपयोग करने का उचित तरीका क्या है ?

kwargsएक शब्दकोश देता है, लेकिन डिफ़ॉल्ट मान सेट करने का सबसे अच्छा तरीका क्या है, या क्या कोई है? क्या मुझे इसे केवल एक शब्दकोश के रूप में एक्सेस करना चाहिए? फ़ंक्शन प्राप्त करें का उपयोग करें?

class ExampleClass:
    def __init__(self, **kwargs):
        self.val = kwargs['val']
        self.val2 = kwargs.get('val2')

एक साधारण सवाल है, लेकिन एक है कि मैं पर अच्छे संसाधन नहीं मिल सकता है। लोग इसे कोड में अलग-अलग तरीके से करते हैं जो मैंने देखा है और यह जानना मुश्किल है कि क्या उपयोग करना है।

जवाबों:


468

आप उन get()कुंजियों के लिए एक डिफ़ॉल्ट मान पास कर सकते हैं जो शब्दकोश में नहीं हैं:

self.val2 = kwargs.get('val2',"default value")

हालाँकि, यदि आप किसी विशेष डिफ़ॉल्ट मान के साथ किसी विशेष तर्क का उपयोग करने की योजना बनाते हैं, तो पहले स्थान पर नामित तर्कों का उपयोग क्यों नहीं करते हैं?

def __init__(self, val2="default value", **kwargs):

16
मैं केवल आवश्यक तर्कों के लिए स्थितिगत तर्कों का उपयोग करना पसंद करता हूं, और उन तर्कों के लिए kwargs जो निर्दिष्ट किए जा सकते हैं या नहीं भी हो सकते हैं, लेकिन डिफ़ॉल्ट मान होना मददगार है। kwargs अच्छा है क्योंकि आप अपने args को किसी भी क्रम में चुन सकते हैं। स्थितिगत तर्क आपको वह स्वतंत्रता नहीं देते हैं।
काकोआ जूल

95
आप किसी भी क्रम में नामित तर्क पारित कर सकते हैं। आपको केवल पदों का पालन करने की आवश्यकता है यदि आप नामों का उपयोग नहीं करते हैं - जो कि kwargs के मामले में, आपको करना होगा। बल्कि, नाम के तर्कों का उपयोग करने के लिए kwargs के विपरीत आपको नामों का उपयोग न करने की अतिरिक्त स्वतंत्रता मिलती है - फिर, हालांकि, आपको आदेश रखना होगा।
बाल्फा

13
@ केक: आप अपने द्वारा चुने गए क्रम में हमेशा नामित तर्क प्रस्तुत कर सकते हैं। इस लचीलेपन को पाने के लिए आपको ** kwargs का उपयोग करने की आवश्यकता नहीं है।
S.Lott

13
pylint झंडे इसे खराब रूप में kwargs का उपयोग करने के लिए __init__()। क्या कोई समझा सकता है कि यह एक लिंट-योग्य अपराध क्यों है?
हुग्डब्रोएन


271

जबकि अधिकांश उत्तर कह रहे हैं कि, जैसे,

def f(**kwargs):
    foo = kwargs.pop('foo')
    bar = kwargs.pop('bar')
    ...etc...

के समान है"

def f(foo=None, bar=None, **kwargs):
    ...etc...

यह सच नहीं है। बाद के मामले में, के fरूप में कहा जा सकता है f(23, 42), जबकि पूर्व का मामला केवल तर्कों को स्वीकार करता है - कोई स्थितिगत कॉल नहीं। अक्सर आप कॉलर को अधिकतम लचीलेपन की अनुमति देना चाहते हैं और इसलिए दूसरा रूप, जैसा कि अधिकांश उत्तर मुखर है, बेहतर है: लेकिन यह हमेशा ऐसा नहीं होता है। जब आप कई वैकल्पिक मापदंडों को स्वीकार करते हैं, जिनमें से आमतौर पर केवल कुछ ही पारित किए जाते हैं, तो यह एक उत्कृष्ट विचार हो सकता है (नाम कॉल में दुर्घटनाओं और अपठनीय कोड से बचना!) नामित तर्कों के उपयोग के लिए मजबूर करना - threading.Threadएक उदाहरण है। पहला रूप यह है कि आप इसे पायथन 2 में कैसे लागू करते हैं।

मुहावरा इतना महत्वपूर्ण है कि पायथन 3 में अब विशेष सहायक वाक्यविन्यास है: हस्ताक्षर *में एक के बाद प्रत्येक तर्क defकेवल कीवर्ड है, अर्थात, इसे एक स्थैतिक तर्क के रूप में पारित नहीं किया जा सकता है, लेकिन केवल एक नाम के रूप में। तो पायथन 3 में आप उपरोक्त कोड दे सकते हैं:

def f(*, foo=None, bar=None, **kwargs):
    ...etc...

वास्तव में, पायथन 3 में आप कीवर्ड-केवल तर्क भी दे सकते हैं जो वैकल्पिक नहीं हैं (डिफ़ॉल्ट मान के बिना)।

हालांकि, पायथन 2 में अभी भी लंबे समय से उत्पादक जीवन है, इसलिए बेहतर है कि आप उन तकनीकों और मुहावरों को भूलें जो आपको पायथन 2 के महत्वपूर्ण डिजाइन विचारों पर लागू करते हैं जो सीधे पायथन 3 में भाषा में समर्थित हैं!


10
@ एलेक्स मार्टेली: मुझे एक भी उत्तर नहीं मिला है, जो दावा करता है कि नाम के तर्कों के समान kwargs हैं, अकेले बेहतर होने दें। लेकिन
Py3k के

1
@ एलेक्स मार्टेली: आपके उत्तर के लिए बहुत बहुत धन्यवाद, यह मुझे पता चला कि अजगर 3 अनिवार्य कीवर्ड-तर्क की अनुमति देता है, जिसके अभाव में अक्सर मेरे कोड और कार्यों में वास्तुकला का असंतोष होता था।
फ्लो

78

मैं कुछ इस तरह का सुझाव देता हूं

def testFunc( **kwargs ):
    options = {
            'option1' : 'default_value1',
            'option2' : 'default_value2',
            'option3' : 'default_value3', }

    options.update(kwargs)
    print options

testFunc( option1='new_value1', option3='new_value3' )
# {'option2': 'default_value2', 'option3': 'new_value3', 'option1': 'new_value1'}

testFunc( option2='new_value2' )
# {'option1': 'default_value1', 'option3': 'default_value3', 'option2': 'new_value2'}

और फिर किसी भी तरह से मूल्यों का उपयोग करें

dictionaryA.update(dictionaryB)किसी डुप्लिकेट कुंजी dictionaryBको dictionaryAअधिलेखित करने की सामग्री को जोड़ता है ।


2
धन्यवाद @ अभिनव जी गुप्ता! ठीक वही जो मेरे द्वारा खोजा जा रहा था। बस गयी for key in options: self.__setattr__(key, options[key])और मुझे जाना अच्छा लगा। :)
propjk007

53

आप करेंगे

self.attribute = kwargs.pop('name', default_value)

या

self.attribute = kwargs.get('name', default_value)

यदि आप उपयोग करते हैं pop, तो आप जांच कर सकते हैं कि क्या कोई नकली मूल्य भेजे गए हैं, और उचित कार्रवाई (यदि कोई है) करें।


2
क्या आप यह स्पष्ट कर सकते हैं कि सुझाव देने से आपका क्या मतलब है .pop"आपको यह जाँचने में मदद करेगा कि क्या कोई स्पुरियस वैल्यू भेजी गई है"?
एलन एच।

13
@ एलन एच .: यदि सभी पॉपिंग के बाद कंवरों में कुछ बचा हुआ है, तो आपको संयमी मूल्य मिल गए हैं।
विनय साजिप

@VinaySajip: ठीक है, .pop "बनाम" पर एक महान बिंदु है।
MestreLion

1
@MestreLion: यह इस बात पर निर्भर करता है कि आपके एपीआई कितने खोजशब्द तर्क देते हैं। मैं यह दावा नहीं करता कि मेरा सुझाव नामित तर्कों से बेहतर है, लेकिन पायथन आपको kwargsएक कारण के लिए अनाम तर्कों को पकड़ने की अनुमति देता है ।
विनय साजिप

तो, बस जाँच। यदि पॉप मौजूद है तो पॉप डिक्शनरी वापस करता है और यदि यह पास नहीं होता है default_value? और बाद में उस चाबी को हटा देता है?
डैनियल मोलर

43

** kwargs और डिफ़ॉल्ट मान का उपयोग करना आसान है। कभी-कभी, हालाँकि, आपको पहली जगह में ** kwargs का उपयोग नहीं करना चाहिए।

इस मामले में, हम वास्तव में ** kwargs का सबसे अच्छा उपयोग नहीं कर रहे हैं।

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = kwargs.get('val',"default1")
        self.val2 = kwargs.get('val2',"default2")

ऊपर एक "क्यों परेशान है?" घोषणा। यह वैसा ही है

class ExampleClass( object ):
    def __init__(self, val="default1", val2="default2"):
        self.val = val
        self.val2 = val2

जब आप ** kwargs का उपयोग कर रहे हैं, तो आपका मतलब है कि एक कीवर्ड न केवल वैकल्पिक है, बल्कि सशर्त है। सरल डिफ़ॉल्ट मानों की तुलना में अधिक जटिल नियम हैं।

जब आप ** kwargs का उपयोग कर रहे हैं, तो आप आमतौर पर निम्नलिखित जैसे कुछ और मतलब रखते हैं, जहां सरल चूक लागू नहीं होती हैं।

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = "default1"
        self.val2 = "default2"
        if "val" in kwargs:
            self.val = kwargs["val"]
            self.val2 = 2*self.val
        elif "val2" in kwargs:
            self.val2 = kwargs["val2"]
            self.val = self.val2 / 2
        else:
            raise TypeError( "must provide val= or val2= parameter values" )

मुझे लगता है कि थोड़ा दिमाग लगाना पसंद है! मैं सोचता रहा, "लेकिन आप बस का उपयोग कर सकते हैं या पॉप के साथ - ओह, वे सह-निर्भर हैं ..."
trojjer

28

चूँकि **kwargsजब तर्कों की संख्या अज्ञात है, तो ऐसा क्यों नहीं किया जा रहा है?

class Exampleclass(object):
  def __init__(self, **kwargs):
    for k in kwargs.keys():
       if k in [acceptable_keys_list]:
          self.__setattr__(k, kwargs[k])

हाँ, यह सुरुचिपूर्ण और शक्तिशाली है ... स्वीकार्य_केक्स_लिस्ट के आस-पास के चौकोर कोष्ठकों के बारे में भी निश्चित नहीं है: हालांकि, मैं इसे टुपल या सूची बनाऊंगा और फिर "अगर" कथन में उन कोष्ठकों को छोड़
दूंगा

मैंने उन मामलों के लिए इसे थोड़ा संशोधित किया, जब सभी कुंजियाँ अपेक्षित हैं: stackoverflow.com/questions/1098549/…
विद्रोह

14

यहाँ एक और दृष्टिकोण है:

def my_func(arg1, arg2, arg3):
    ... so something ...

kwargs = {'arg1': 'Value One', 'arg2': 'Value Two', 'arg3': 'Value Three'}
# Now you can call the function with kwargs like this:

my_func(**kwargs)

Django CBVs (जैसे get_form_kwargs()) में बहुत इस्तेमाल किया । ccbv.co.uk/projects/Django/1.5/django.views.generic.edit/…
trojjer

यह get_form()विधि बताती है कि किसी अन्य विधि ( get_form_kwargsजैसा कि ऊपर उल्लेख किया गया है) के संदर्भ में बड़े पैमाने पर खोजशब्द तर्क प्राप्त करना है । यह प्रपत्र को दर्शाता है इस प्रकार है: form_class(**self.get_form_kwargs())
ट्रोजर

तब get_form_kwargs()उपवर्ग दृश्य में ओवरराइड करना और विशिष्ट तर्क के आधार पर कवर्स जोड़ना / निकालना आसान होता है। लेकिन यह एक Django ट्यूटोरियल के लिए है।
trojjer

12

मुझे लगता है कि **kwargsजब डिफ़ॉल्ट मानों की बात आती है तो पायथन में उपयोग करने का उचित तरीका शब्दकोश विधि का उपयोग करना है setdefault, जैसा कि नीचे दिया गया है:

class ExampleClass:
    def __init__(self, **kwargs):
        kwargs.setdefault('val', value1)
        kwargs.setdefault('val2', value2)

इस तरह, यदि कोई उपयोगकर्ता कीवर्ड में 'val' या 'val2' पास करता है args, तो उनका उपयोग किया जाएगा; अन्यथा, जो डिफ़ॉल्ट मान सेट किए गए हैं, उनका उपयोग किया जाएगा।


11

आप ऐसा कुछ कर सकते हैं

class ExampleClass:
    def __init__(self, **kwargs):
        arguments = {'val':1, 'val2':2}
        arguments.update(kwargs)
        self.val = arguments['val']
        self.val2 = arguments['val2']

11

पर बाद @srhegde का उपयोग करने का सुझाव setattr :

class ExampleClass(object):
    __acceptable_keys_list = ['foo', 'bar']

    def __init__(self, **kwargs):
        [self.__setattr__(key, kwargs.get(key)) for key in self.__acceptable_keys_list]

यह वेरिएंट तब उपयोगी होता है जब हमारी acceptableसूची में सभी वस्तुओं के वर्ग होने की उम्मीद की जाती है ।


1
यह सूची बोध के लिए उपयोग का मामला नहीं है, आपको अपने इनिट विधि में लूप के लिए उपयोग करना चाहिए।
ettanany

5

यदि आप इसे * args के साथ संयोजित करना चाहते हैं तो आपको परिभाषा के अंत में * args और ** kwargs रखना होगा।

इसलिए:

def method(foo, bar=None, *args, **kwargs):
    do_something_with(foo, bar)
    some_other_function(*args, **kwargs)

1

@AbhinavGupta और @Steef ने उपयोग करने का सुझाव दिया update(), जो मुझे बड़े तर्क सूचियों के प्रसंस्करण के लिए बहुत मददगार लगा:

args.update(kwargs)

क्या होगा यदि हम यह जाँचना चाहते हैं कि उपयोगकर्ता ने किसी भी प्रकार की अस्थिर / असमर्थित दलीलें पारित नहीं की हैं? @VinaySajip ने बताया कि pop()इसका उपयोग तर्कों की सूची को पुनरावृत्त करने के लिए किया जा सकता है। फिर, किसी भी बचे हुए तर्क के लिए गंभीर हैं। अच्छा लगा।

इसे करने का एक और संभावित तरीका यहां दिया जा रहा है, जो प्रयोग करने के सरल वाक्य-विन्यास को बनाए रखता है update():

# kwargs = dictionary of user-supplied arguments
# args = dictionary containing default arguments

# Check that user hasn't given spurious arguments
unknown_args = user_args.keys() - default_args.keys()
if unknown_args:
    raise TypeError('Unknown arguments: {}'.format(unknown_args))

# Update args to contain user-supplied arguments
args.update(kwargs)

unknown_argsउन setतर्कों का नाम है, जो चूक में नहीं होते हैं।


0

अज्ञात या एकाधिक तर्कों को संसाधित करने का एक और सरल समाधान हो सकता है:

class ExampleClass(object):

    def __init__(self, x, y, **kwargs):
      self.x = x
      self.y = y
      self.attributes = kwargs

    def SomeFunction(self):
      if 'something' in self.attributes:
        dosomething()

0

** kwargs किसी भी कीवर्ड तर्क को जोड़ने की स्वतंत्रता देता है। एक कुंजी की एक सूची हो सकती है जिसके लिए वह डिफ़ॉल्ट मान सेट कर सकता है। लेकिन अनिश्चित संख्या की कुंजी के लिए डिफ़ॉल्ट मान सेट करना अनावश्यक लगता है। अंत में, यह महत्वपूर्ण हो सकता है कि उदाहरण के रूप में चाबी हो। तो, मैं इस प्रकार है:

class Person(object):
listed_keys = ['name', 'age']

def __init__(self, **kwargs):
    _dict = {}
    # Set default values for listed keys
    for item in self.listed_keys: 
        _dict[item] = 'default'
    # Update the dictionary with all kwargs
    _dict.update(kwargs)

    # Have the keys of kwargs as instance attributes
    self.__dict__.update(_dict)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.