2012-01-22 19 views
5

पायथन जटिल अज्ञात कार्यों का समर्थन नहीं करता है। एक अच्छा विकल्प क्या है? उदाहरण के लिए:पायथन: अज्ञात कार्यों के विकल्प

class Calculation: 
    def __init__(self, func): 
     self.func = func 

    def __call__(self, data): 
     try: 
     # check if the value has already been calculated 
     # if it has, it would be cached under key = self.func 
      return data[self.func] 
     except KeyError: 
      pass # first-time call; calculate and cache the values 
     data[self.func] = self.func(data) 
     return data[self.func] 

# with a simple function, which can be represented using lambda, this works great 
f1 = Calculation(lambda data : data['a'] * data['b']) 

# with a complicated function, I can do this: 
def f2_aux: 
    # some complicated calculation, which isn't suitable for a lambda one-liner 
f2 = Calculation(f2_aux) 

क्या यह एक उचित डिजाइन शुरू करने के लिए है?

यदि हां, तो क्या मॉड्यूल में परिभाषित प्रत्येक एफ * के लिए f * _aux की कुरूपता से बचने का कोई तरीका है?

अद्यतन:

उपयोग का उदाहरण:

d = {'a' : 3, 'b' : 6} 

# computes 3 * 6 
# stores 18 in d under a key <function <lambda> at ...> 
# returns 18 
f1(d) 

# retrieves 18 from d[<function <lambda> at ...>] 
# returns 18, without having to recalculate it 
f1(d) 

अद्यतन:

बस मेरी समझ के लिए, मैं भीतरी समारोह का उपयोग करता है एक संस्करण जोड़ा।

def memoize(func): 
    def new_func(data): 
     try: 
     # check if the value has already been calculated 
     # if it has, it would be cached under key = self.func 
      return data[func] 
     except KeyError: 
      pass # first-time call; calculate and cache the values 
     data[func] = func(data) 
     return data[func] 
    return new_func 

@memoize 
def f1(data): 
    return data['a'] * data['b'] 
+5

नहीं, यह उचित डिजाइन नहीं है। आप यादें कर रहे हैं (जो अज्ञात कार्यों से असंबंधित है), और इसे बुरी तरह से कर रहा है। 'f1 = lambda a: अभिव्यक्ति' हमेशा 'def f1 (ए): वापसी अभिव्यक्ति' जैसा ही है। [यह अध्ययन करने के लिए एक अच्छा ज्ञापन सजावट है] (http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize)। बीटीडब्लू, '@ डिकोरेटर डीफ़ फ़ंक्शन: पास' हमेशा' डीफ़ फ़ंक्शन: पास के समान ही होता है; समारोह = सजावट (कार्य) ' –

+2

क्या बुरा है यह है कि आपका ज्ञापन टूट गया है। परिणाम कैश 'डेटा' भी आपके फ़ंक्शन का तर्क है ... –

+0

@ फ्रैंकिसएविला: मैं शब्द तत्व 'डेटा [f]' में 'f (डेटा)' के मान को कैश करना चाहता था। मुझे पता है कि मेरे पास पास किया गया डेटा कभी भी ऐसी कुंजी का उपयोग नहीं करेगा - और दूसरे के साथ संघर्ष तब नहीं होना चाहिए जब किसी अन्य कार्य के मूल्य को किसी अन्य कुंजी के अंतर्गत कैश किया जाएगा। ऐसा लगता है जैसे यह काम करता है (तकनीकी रूप से); अनावश्यक रूप से भ्रमित कोड में समस्या क्या है? – max

उत्तर

5

आपको अज्ञात कार्यों की आवश्यकता नहीं है। इसके अलावा, इस से बेहतरकरण किया गया है, शायद आपके लिए अपना रोल करने का कोई कारण नहीं है।

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

@Calculation 
def f2(): 
    ... 

यह केवल Calculation में समारोह में परिभाषित किया गया यह लपेटता है, और उस f2 के रूप में के परिणाम संग्रहीत। डेकोरेटर वाक्य रचना के बराबर होने का परिभाषित किया गया है: इस तरह के अपने उदाहरण में से एक के रूप में एक वर्ग लिखने के लिए एक संक्षिप्त विकल्प हो सकता है

_decorator = Calculation # a fresh identifier 
# not needed here, but in other cases (think properties) it's useful 
def f2(): 
    ... 
f2 = _decorator(f2) 
+0

क्या मैं सही ढंग से समझता हूं कि आम तौर पर एक सजावट एक ऐसा कार्य होता है जो एक कार्य को तर्क के रूप में लेता है, और एक और कार्य देता है - इस मामले में, 'क्लास कैलकुलेशन' इस कन्स्ट्रक्टर हस्ताक्षर और इसकी '__call__' विधि के कारण इस भूमिका को फिट करता है? – max

+0

@ मैक्स: सजावटी पर कोई प्रतिबंध नहीं है, बशर्ते कि उन्हें कॉल करने योग्य होना चाहिए, और * उपयोगी * होना चाहिए, उनके पास सार्थक वापसी मूल्य होना चाहिए। कक्षाएं '__new__' /' __init__' के माध्यम से कॉल करने योग्य हैं, और आपकी कक्षा के उदाहरण कॉल करने योग्य हैं (हालांकि '__call__'), वापसी मूल्य उपयोगी है। – delnan

+0

@ मैक्स "एक कॉल करने योग्य", पायथन parlance में। –

1

एक बंद। इस तकनीक में def अन्य डीफ़ के अंदर डालने शामिल है। आंतरिक कार्य को संलग्न कार्य में चर के लिए उपयोग किया जा सकता है। पायथन 3 में, nonlocal कीवर्ड आपको उस चर तक पहुंच लिखने देता है। पायथन 2 में, आपको आंतरिक फ़ंक्शन से इसे अपडेट करने में सक्षम होने के लिए नॉनोकोकल चर के लिए एक परिवर्तनीय मान का उपयोग करने की आवश्यकता है।

गुमनाम कार्यों के बारे में प्रश्न के बारे में, भाषा जानबूझकर तुम वापस कुछ भी एक लैम्ब्डा संभाल कर सकते हैं की तुलना में अधिक जटिल के लिए डीईएफ़उपयोग करने के लिए धक्का।

+0

क्या आपका मतलब है कि मैंने अपने प्रश्न के आखिरी अपडेट में जो कुछ जोड़ा है? – max

+0

हां, यह एक बंद है। –

4

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

पायथन में आप lambda कथन के साथ अज्ञात कार्य करते हैं। उदाहरण के लिए आप यह कर सकते हैं:

output = mysort(input, lambda x: x.lastname) 

लैम्ब्डा एक समारोह पैदा करेगा, लेकिन यह समारोह स्थानीय अंतरिक्ष में कोई नाम नहीं है, और खुद के लिए यह अपने नाम सिर्फ '<lambda>' है। लेकिन अगर हम mysort को देखो, यह कुछ इस तरह परिभाषित करना होगा:

def mysort(input, getterfunc): 
    blahblahblah 

हम यहाँ इस संदर्भ समारोह में सभी अनाम नहीं है में देखने के रूप में,। इसका नाम है, getterfunc।इस फ़ंक्शन के दृष्टिकोण से इससे कोई फर्क नहीं पड़ता कि फ़ंक्शन में गुजरने वाला फ़ंक्शन अज्ञात है या नहीं। यह बस के रूप में अच्छी तरह से काम करता है, और सभी महत्वपूर्ण मायनों में बिल्कुल बराबर है:

def get_lastname(x): 
    return x.lastname 

output = mysort(input, get_lastname) 

ज़रूर, इसे और अधिक कोड का उपयोग करता है, लेकिन यह धीमी नहीं या ऐसा कुछ है। पायथन में, इसलिए अज्ञात कार्य सामान्य कार्यों के लिए सिंटेक्टिक चीनी के अलावा कुछ भी नहीं हैं।

सही मायने में एक गुमनाम समारोह

lambda x: x.lastname 

होगा लेकिन जैसा कि हम कुछ भी करने के लिए जिसके परिणामस्वरूप समारोह निर्दिष्ट नहीं करते, हम एक नाम समारोह के लिए नहीं मिलता है, और फिर हम इसका इस्तेमाल नहीं कर सकते हैं। सभी वास्तव में अज्ञात कार्य अनुपयोगी हैं।

इसी कारण से, यदि आपको एक ऐसा फ़ंक्शन चाहिए जो लैम्ब्डा नहीं हो सकता है, तो इसे सामान्य कार्य करें। यह किसी भी सार्थक तरीके से कभी भी अज्ञात नहीं हो सकता है, तो इसे अज्ञात क्यों बनाते हैं? Lambdas उपयोगी होते हैं जब आप एक छोटे से एक लाइन फ़ंक्शन चाहते हैं और आप पूर्ण फ़ंक्शन को परिभाषित करके स्थान बर्बाद नहीं करना चाहते हैं। वे अज्ञात हैं अप्रासंगिक हैं।

+0

धन्यवाद .. मुझे लगता है कि मैं बस लिखे गए कोड की मात्रा को बचाने की कोशिश कर रहा था (और इसलिए संभावित टाइपो की संख्या), जो मैं मानता हूं कि शुरुआत करने के लिए एक प्रमुख चिंता नहीं होनी चाहिए। – max

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