2016-03-19 7 views
27

मैं एक शब्दकोश कि समारोह के आदानों की तुलना में अधिक आइटम हैं के साथ एक समारोह गठबंधन करने के लिए सबसे अच्छा तरीका रहा हूँकिसी फ़ंक्शन के साथ फ़ंक्शन को कॉल करने के लिए जिसमें फ़ंक्शन की तुलना में अधिक आइटम हैं, पैरामीटर हैं?

बुनियादी ** kwarg unpacking इस मामले में विफल रहता है:

def foo(a,b): 
    return a + b 

d = {'a':1, 
    'b':2, 
    'c':3} 

foo(**d) 
--> TypeError: foo() got an unexpected keyword argument 'c' 

कुछ शोध करने के बाद

import inspect 

# utilities 
def get_input_names(function): 
    '''get arguments names from function''' 
    return inspect.getargspec(function)[0] 

def filter_dict(dict_,keys): 
    return {k:dict_[k] for k in keys} 

def combine(function,dict_): 
    '''combine a function with a dictionary that may contain more items than the function's inputs ''' 
    filtered_dict = filter_dict(dict_,get_input_names(function)) 
    return function(**filtered_dict) 

# examples 
def foo(a,b): 
    return a + b 

d = {'a':1, 
    'b':2, 
    'c':3} 

print combine(foo,d) 
--> 3 

मेरा प्रश्न है: मैं निम्नलिखित दृष्टिकोण के साथ आया था इस इस समस्या से निपटने का एक अच्छा तरीका है, या वहाँ एक बेहतर अभ्यास है या वहाँ एक mechan है उस भाषा में आईएसएम है जिसे मैं शायद याद कर रहा हूं?

उत्तर

23

कैसे के बारे में बनाने एक decorator कि होगा फिल्टर अनुमति कीवर्ड तर्क केवल:

import inspect 


def get_input_names(function): 
    '''get arguments names from function''' 
    return inspect.getargspec(function)[0] 


def filter_dict(dict_,keys): 
    return {k:dict_[k] for k in keys} 


def filter_kwargs(func): 
    def func_wrapper(**kwargs): 
     return func(**filter_dict(kwargs, get_input_names(func))) 
    return func_wrapper 


@filter_kwargs 
def foo(a,b): 
    return a + b 


d = {'a':1, 
    'b':2, 
    'c':3} 

print(foo(**d)) 

क्या इस डेकोरेटर के बारे में अच्छा है कि यह सामान्य और पुन: प्रयोज्य है। और आपको जिस तरह से कॉल करना है और अपने लक्षित कार्यों का उपयोग करने की आवश्यकता नहीं है।

11

आपकी समस्या तरह से आप अपने कार्य निर्धारित होती है, तो वह ऐसा परिभाषित किया जाना चाहिए -

def foo(**kwargs): 

और फिर समारोह के अंदर तुम इतनी तरह कार्य करने के लिए भेजा तर्क की संख्या से अधिक पुनरावृति कर सकते हैं -

if kwargs is not None: 
     for key, value in kwargs.iteritems(): 
       do something 

इस पोस्ट में आपका kwargs उपयोग के बारे में और अधिक जानकारी प्राप्त कर सकते हैं ** - http://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/

+1

धन्यवाद। मुझे शायद यह उल्लेख करना चाहिए था कि मैं एक कार्यक्रम के लिए एक ढांचा तैयार कर रहा हूं जहां अन्य लोग (कभी-कभी पाइथन में सापेक्ष नौसिखिया) कार्य बना रहे हैं। इसलिए, मैं उन्हें ** kwargs से निपटने के लिए पसंद नहीं करना चाहूंगा, बल्कि मूलभूत फ़ंक्शन इनपुट का उपयोग करके: foo (a, b); मैं उपयोगिता कार्यों में इस ** kwargs फ़िल्टरिंग जटिलता छिपाना चाहता हूँ। –

3

मैं किसी चीज़ करना होगा इस तरह जी:

def combine(function, dictionary): 
    return function(**{key:value for key, value in dictionary.items() 
        if key in inspect.getargspec(function)[0]} 
    ) 

उपयोग:

>>> def this(a, b, c=5): 
...  print(a, b, c) 
... 
>>> combine(this, {'a': 4, 'b': 6, 'c': 6, 'd': 8}) 
4 6 6 
>>> combine(this, {'a': 6, 'b': 5, 'd': 8}) 
6 5 5 
8

तुम भी एक decorator function उपयोग कर सकते हैं उन कीवर्ड तर्क की अनुमति नहीं है आप में कार्य को फिल्टर करने की। आप 3.3 में signature समारोह नई का उपयोग अजगर 3.0 से अपने कार्य Signature

from inspect import signature 
from functools import wraps 


def decorator(func): 
    @wraps(func) 
    def wrapper(*args, **kwargs): 
     sig = signature(func) 
     result = func(*[kwargs[param] for param in sig.parameters]) 
     return result 
    return wrapper 

वापस जाने के लिए आप getargspec जो संस्करण के बाद से हटा दिया गया है का उपयोग कर सकते 3,0

import inspect 


def decorator(func): 
    @wraps(func) 
    def wrapper(*args, **kwargs): 
     argspec = inspect.getargspec(func).args 
     result = func(*[kwargs[param] for param in argspec]) 
      return result 
    return wrapper 

लागू करने के लिए अपने सजाने एक मौजूदा फंक्शन आपको अपने फंक्शन को अपने सजावट के लिए तर्क के रूप में पास करने की आवश्यकता है:

डेमो:

>>> def foo(a, b): 
...  return a + b 
... 
>>> foo = decorator(foo) 
>>> d = {'a': 1, 'b': 2, 'c': 3} 
>>> foo(**d) 
3 

एक नव कार्य करने के लिए अपने डेकोरेटर लागू करने के लिए बस @

>>> @decorator 
... def foo(a, b): 
...  return a + b 
... 
>>> foo(**d) 
3 

का उपयोग तुम भी मनमाने ढंग से कीवर्ड तर्क **kwargs का उपयोग कर अपने समारोह को परिभाषित कर सकते हैं।

>>> def foo(**kwargs): 
...  if 'a' in kwargs and 'b' in kwargs: 
...   return kwargs['a'] + kwargs['b'] 
... 
>>> d = {'a': 1, 'b': 2, 'c': 3} 
>>> foo(**d) 
3 
14

ये सभी उत्तर गलत हैं।

def foo(**kwargs): 
    a = kwargs.pop('a') 
    b = kwargs.pop('b') 
    if kwargs: 
     raise TypeError('Unexpected arguments: %r' % kwargs) 

अब, क्यों पृथ्वी पर किसी को भी है कि लिखना होगा:

संभव नहीं है कि तुम क्या कह रहे हैं ऐसा करने के लिए, क्योंकि समारोह इस तरह घोषित किया जा सकता है?

क्योंकि वे समय से पहले सभी तर्कों को नहीं जानते हैं। यहाँ एक और अधिक यथार्थवादी मामला है:

def __init__(self, **kwargs): 
    for name in self.known_arguments(): 
     value = kwargs.pop(name, default) 
     self.do_something(name, value) 
    super().__init__(**kwargs) # The superclass does not take any arguments 

और here कुछ वास्तविक दुनिया कोड जो वास्तव में यह करता है।

आप पूछ सकते हैं कि हमें अंतिम पंक्ति क्यों चाहिए। एक सुपरक्लास के लिए तर्क क्यों पास करते हैं जो कोई नहीं लेता है? Cooperative multiple inheritance। अगर मेरी कक्षा को तर्क मिलता है तो यह पहचान नहीं लेता है, इसे उस तर्क को निगलना नहीं चाहिए, न ही इसे गलती करनी चाहिए। इसे श्रृंखला को तर्क देना चाहिए ताकि एक और वर्ग जिसे मैं शायद नहीं जानता, इसे संभाल सकता है। और यदि कोई इसे संभालता है, तो object.__init__() उचित त्रुटि संदेश प्रदान करेगा। दुर्भाग्य से, अन्य उत्तरों उस सुंदरता को संभाल नहीं पाएंगे। वे **kwargs देखेंगे और या तो कोई तर्क नहीं पारित करेंगे या उन सभी को पास करेंगे, जो दोनों गलत हैं।

नीचे की रेखा: यह पता लगाने का कोई सामान्य तरीका नहीं है कि फ़ंक्शन कॉल वास्तव में फ़ंक्शन कॉल किए बिना कानूनी है या नहीं। inspect एक कच्चे अनुमान है, और पूरी तरह से भिन्न कार्यों के चेहरे में अलग हो जाता है। वैराडिक का मतलब यह नहीं है कि "जो कुछ भी आपको पसंद है"; इसका मतलब है "नियम हस्ताक्षर में व्यक्त करने के लिए बहुत जटिल हैं।" नतीजतन, कई मामलों में ऐसा करना संभव हो सकता है जो आप करने की कोशिश कर रहे हैं, वहां ऐसी स्थितियां हमेशा होंगी जहां कोई सही उत्तर नहीं है।

+1

धन्यवाद केविन! मैंने अंत में एलेक्स के जवाब को स्वीकार कर लिया क्योंकि यह मेरी स्थिति के लिए सबसे अधिक उपयोगी था, हालांकि मुझे तुम्हारा बहुत ही रोचक पढ़ा गया, और मैं मानता हूं कि यह समझना आवश्यक है कि 'फ़िल्टर क्वॉर्ग' दृष्टिकोण कहां पर विचार करने के लिए महत्वपूर्ण परिदृश्य हैं काम। –

2

यह अभी भी मूल समारोह को संशोधित है, लेकिन आप तर्क सूची के अंत में एक kwargs bitbucket बना सकते हैं:

def foo(a, b, **kwargs): 
    return a + b 

foo(**{ 
    'a': 5, 
    'b': 8, 
    'c': '' 
}) # 13 
संबंधित मुद्दे

 संबंधित मुद्दे