सवाल फ़ंक्शन होने का एक प्रभावी तरीका केवल एक लूप में निष्पादित होता है


फिलहाल, मैं निम्नलिखित की तरह सामान कर रहा हूं, जो थकाऊ हो रहा है:

run_once = 0
while 1:
    if run_once == 0:
        myFunction()
        run_once = 1:

मुझे लगता है कि इस सामान को संभालने का कुछ और स्वीकार्य तरीका है?

मैं जो खोज रहा हूं, वह मांग पर एक बार कार्य निष्पादित कर रहा है। उदाहरण के लिए, एक निश्चित बटन के प्रेस पर। यह एक इंटरेक्टिव ऐप है जिसमें बहुत से उपयोगकर्ता नियंत्रित स्विच हैं। प्रत्येक स्विच के लिए एक जंक वैरिएबल होने के कारण, यह ट्रैक रखने के लिए कि यह चलाया गया है या नहीं, ऐसा लगता है कि अक्षम है।


44
2017-11-05 05:25


मूल


यदि आपको एक बार दौड़ना है, तो आप फ़ंक्शन -> myFunction () को एक बार क्यों नहीं बुलाते हैं !! कृपया अपना कोड देखें, इरादे को बेहतर तरीके से समझाएं। - pyfunc
आप इसे लूप के बाहर क्यों नहीं छोड़ सकते? अधिक संदर्भ कृपया। - EightyEight
@pyfunc मुझे बताएं कि कोड अधिक स्पष्ट रूप से इस मुद्दे को व्यक्त करता है या नहीं - Ron
खैर, यह संभव है कि लूप कुछ कार्य के लिए प्रयोग पैरामीटर के माध्यम से पुनरावृत्ति करता है, और सभी कार्य एक के अलावा पैरामीटर का उपयोग करते हैं। हालांकि, मैं उन्हें लूप में भी डाल सकता हूं क्योंकि वे कार्य के लिए सभी कार्यान्वयन हैं। जैसे एक पुनर्प्राप्ति कार्य में, मेरा लूप मेरे द्वारा विकसित एम्बेडिंग विधियों के लिए कॉन्फ़िगरेशन के माध्यम से पुनरावृत्त करता है लेकिन बेसलाइन कीवर्ड-मिलान विधि हमेशा एक ही परिणाम आउटपुट करती है। इस तरह कोड कंप्यूटेशनल संसाधनों को बचाता है जबकि क्लीनर दिखता है। - Sean


जवाब:


मैं इस बात पर नजर रखने के लिए फंक्शन पर एक सजावटी का उपयोग करता हूं कि यह कितनी बार चलता है।

def run_once(f):
    def wrapper(*args, **kwargs):
        if not wrapper.has_run:
            wrapper.has_run = True
            return f(*args, **kwargs)
    wrapper.has_run = False
    return wrapper


@run_once
def my_function(foo, bar):
    return foo+bar

अभी व my_function केवल एक बार चलाएगा। इसके लिए अन्य कॉल वापस आ जाएंगे None। बस एक जोड़ें else के लिए खंड if अगर आप इसे कुछ और वापस करना चाहते हैं। आपके उदाहरण से, इसे कभी भी कुछ भी वापस करने की आवश्यकता नहीं है।

यदि आप फ़ंक्शन के निर्माण को नियंत्रित नहीं करते हैं, या फ़ंक्शन को अन्य संदर्भों में सामान्य रूप से उपयोग करने की आवश्यकता है, तो आप सजावटी को मैन्युअल रूप से भी लागू कर सकते हैं।

action = run_once(my_function)
while 1:
    if predicate:
        action()

यह छोड़ देगा my_function अन्य उपयोगों के लिए उपलब्ध है।

अंत में, यदि आपको केवल दो बार इसे चलाने की आवश्यकता है, तो आप बस कर सकते हैं

action = run_once(my_function)
action() # run once the first time

action.has_run = False
action() # run once the second time

79
2017-11-05 07:41



ऐसा लगता है कि मैं क्या देख रहा हूं, लेकिन मैं आपके उपयोग के सिंटैक्स से अनिश्चित हूं। @ Char के लिए क्या है? - Marcus Ottosson
@ मर्कस ओटोसन द @ चार इसे एक सजावटी बनाता है। यह बताने के लिए एक टिप्पणी बहुत लंबी है कि क्या है। यहाँ, एक है संपर्क। किसी भी दर पर, आप केवल दूसरे फॉर्म का उपयोग करना चाहते हैं जो मैंने प्रस्तुत किया है, जहां आप इसे मैन्युअल रूप से लागू करते हैं। आपको शायद अभी भी पता होना चाहिए कि एक सजावटी क्या है। - aaronasterling
अच्छा, मैं उसमें देख लूंगा। धन्यवाद - Marcus Ottosson
सजावट का उपयोग कैसे करें इसका क्लासिक उदाहरण। अच्छी तरह से किया! - jathanism
यह उल्लेखनीय है कि यह कक्षाओं के तरीकों पर भी काम करता है। - Ehtesh Choudhury


एक और विकल्प सेट करना है func_code  कोड ऑब्जेक्ट आपके फ़ंक्शन के लिए फ़ंक्शन के लिए कोड ऑब्जेक्ट होना जो कुछ भी नहीं करता है। यह आपके कार्य शरीर के अंत में किया जाना चाहिए।

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

def run_once():  
   # Code for something you only want to execute once
   run_once.func_code = (lambda:None).func_code

यहाँ run_once.func_code = (lambda:None).func_code लैम्बडा के कोड के साथ अपने फ़ंक्शन के निष्पादन योग्य कोड को प्रतिस्थापित करता है: कोई नहीं, इसलिए सभी बाद की कॉल run_once() कुछ नहीं करेगा

यह तकनीक सजावटी दृष्टिकोण से कम लचीला है स्वीकार्य उत्तर, लेकिन यदि आपके पास केवल एक ही कार्य है जिसे आप एक बार चलाने के लिए चाहते हैं तो अधिक संक्षिप्त हो सकता है।


13
2017-07-22 13:39



कुछ नया सीख लिया, धन्यवाद। :) - Marcus Ottosson


लूप से पहले फ़ंक्शन चलाएं। उदाहरण:

myFunction()
while True:
    # all the other code being executed in your loop

यह स्पष्ट समाधान है। यदि आंखों से मिलने से कहीं अधिक है, तो समाधान थोड़ा और जटिल हो सकता है।


5
2017-11-05 05:29



यह कटौती नहीं करेगा क्योंकि ओपी कहता है "उदाहरण के लिए, एक निश्चित बटन के प्रेस पर। यह एक इंटरेक्टिव ऐप है जिसमें बहुत से उपयोगकर्ता नियंत्रित स्विच हैं।" तो ओपी चाहता है कि फ़ंक्शन मुख्य रन लूप के अंदर से एक बार चलने योग्य हो। - Jamie Bullock


मुझे लगता है कि यह एक ऐसी क्रिया है जिसे आप अधिकतर समय में करना चाहते हैं, अगर कुछ शर्तों को पूरा किया जाता है। चूंकि आप हमेशा कार्रवाई नहीं करेंगे, आप इसे लूप के बाहर बिना शर्त तरीके से कर सकते हैं। अगर आपको कोई अनुरोध मिलता है तो कुछ आलसी (और इसे कैशिंग) प्राप्त करने की तरह कुछ, लेकिन इसे अन्यथा पुनर्प्राप्त नहीं करना।

def do_something():
    [x() for x in expensive_operations]
    global action
    action = lambda : None

action = do_something
while True:
    # some sort of complex logic...
    if foo:
        action()

5
2017-11-05 05:37



@ रयान गिन्स्ट्रॉम: वास्तव में !! - pyfunc
यह माना जाता है कि आप इस विशेष मामले के अनुरूप do_something () या myFunction () के तर्क को बदलना चाहते हैं (या कर सकते हैं)। शायद एक अलग संदर्भ में do_something / myFunction कहीं और कहा जाता है। (निश्चित रूप से हम तब तक नहीं जान पाएंगे जब तक पोस्टर स्पष्ट नहीं करता है।) - snapshoe
यह अत्यधिक संकुचित है। हालांकि साफ चाल है। मेरा मुख्य गपशप, और यह मुझे एक गंभीर विश्वास है, वह है do_somethingयह जानने की जरूरत है कि इसे अलिया किया जा रहा है action जो मुझे चिंताओं को अलग करने के कुछ प्रकार का उल्लंघन करने लगता है। मैं हालांकि, साफ चाल दोहराओ। - aaronasterling
-1। यह गन्दा है और बड़े कोड बेस में पठनीयता को नुकसान पहुंचा सकता है। वैश्विक चर, नाम  action, एक समारोह हर बार बुलाया जाता है (मूल प्रश्न के विपरीत जहां इसे केवल एक बार कहा जाता है)। - Noufal Ibrahim
action();action = lambda:None अतिरिक्त कार्य के बिना एक समान परिणाम प्राप्त करता है - John La Rooy


आप जो चाहते हैं उसे करने के कई तरीके हैं; हालांकि, ध्यान दें कि यह काफी संभव है - प्रश्न में वर्णित - आपको लूप के अंदर फ़ंक्शन को कॉल करने की आवश्यकता नहीं है।

यदि आप लूप के अंदर फ़ंक्शन कॉल करने का आग्रह करते हैं, तो आप यह भी कर सकते हैं:

needs_to_run= expensive_function
while 1:
    …
    if needs_to_run: needs_to_run(); needs_to_run= None
    …

4
2017-11-05 12:06



+1 मैं अपना जवाब हटाने का लुत्फ उठा रहा हूं लेकिन मैं हाल ही में बहुत कुछ कर रहा हूं। - aaronasterling
@अरॉन: आपको निश्चित रूप से अपना उत्तर नहीं हटाना चाहिए, जो भी आपके हटाए गए / शेष उत्तरों का अनुपात है :) - tzot
मुखर if needs_to_run is not None और उचित स्वरूपण यहां उचित हो सकता है। needs_to_run, run_once = None, needs_to_run; run_once() अपवादों से रक्षा कर सकते हैं, उपयोगकर्ता कीस्ट्रोक के जवाब में कई आविष्कार कम संभावना है। - jfs


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

def my_function1(_has_run=[]):
    if _has_run: return
    print "my_function1 doing stuff"
    _has_run.append(1)

def my_function2(_has_run=[]):
    if _has_run: return
    print "my_function2 doing some other stuff"
    _has_run.append(1)

for i in range(10):
    my_function1()
    my_function2()

my_function1(_has_run=[]) # force it to run

# output:
# my_function1 doing stuff
# my_function2 doing some other stuff
# my_function1 doing stuff

इसे करके थोड़ा और सरल बनाया जा सकता है क्या @gnibbler ने अपने जवाब में सुझाव दिया और एक इटरेटर का उपयोग करना (जिसे पायथन 2.2 में पेश किया गया था।):

from itertools import count

def my_function3(_count=count()):
    if _count.next(): return
    print "my_function3 doing something"

for i in range(10):
    my_function3()

# my_function3 doing something

3
2017-11-07 00:30



परिवर्तनीय कीवर्ड तर्कों का उपयोग करने के लिए +1। - Faheem Mitha


यहां एक ऐसा उत्तर दिया गया है जिसमें फ़ंक्शंस का पुनर्मूल्यांकन शामिल नहीं है, फिर भी उस बदसूरत "पहले" चेक की आवश्यकता को रोकता है।

__missing__ Python 2.5 और ऊपर द्वारा समर्थित है।

def do_once_varname1():
    print 'performing varname1'
    return 'only done once for varname1'
def do_once_varname2():
    print 'performing varname2'
    return 'only done once for varname2'

class cdict(dict):
    def __missing__(self,key):
        val=self['do_once_'+key]()
        self[key]=val
        return val

cache_dict=cdict(do_once_varname1=do_once_varname1,do_once_varname2=do_once_varname2)

if __name__=='__main__':
    print cache_dict['varname1'] # causes 2 prints
    print cache_dict['varname2'] # causes 2 prints
    print cache_dict['varname1'] # just 1 print
    print cache_dict['varname2'] # just 1 print

आउटपुट:

performing varname1
only done once for varname1
performing varname2
only done once for varname2
only done once for varname1
only done once for varname2

2
2017-09-29 00:05



मेरे लिए कुछ नया सीखना +1। - Marcus Ottosson


मान लीजिए कि कुछ कारण क्यों है myFunction() लूप से पहले नहीं कहा जा सकता है

from itertools import count
for i in count():
    if i==0:
        myFunction()

1
2017-11-05 06:26



बहुत चालाक विचार - लेकिन ऐसा लगता है कि ओपी ऐसा कुछ चाहता है जो फ़ंक्शन का एक पहलू है और इसके लिए किसी भी कॉल के लिए असल में, इस तरह एक बिंदु से बाहरी रूप से नियंत्रित होने के बजाय। - martineau


यहां कोड करने का एक स्पष्ट तरीका है, जहां किस कार्य की स्थिति को बुलाया गया है उसे स्थानीय रूप से रखा जाता है (इसलिए वैश्विक स्थिति से बचा जाता है)। मुझे अन्य उत्तरों में सुझाए गए गैर-स्पष्ट रूपों की तरह बहुत कुछ नहीं है: f () को देखना बहुत आश्चर्यजनक है और इसके लिए इसका मतलब यह नहीं है कि f () को कॉल किया जाता है।

यह dict.pop का उपयोग करके काम करता है जो एक धक्का में एक कुंजी देखता है, dict से कुंजी को हटा देता है, और कुंजी नहीं मिलने पर उपयोग करने के लिए डिफ़ॉल्ट मान लेता है।

def do_nothing(*args, *kwargs):
    pass

# A list of all the functions you want to run just once.
actions = [
    my_function,
    other_function
]
actions = dict((action, action) for action in actions)

while True:
    if some_condition:
        actions.pop(my_function, do_nothing)()
    if some_other_condition:
        actions.pop(other_function, do_nothing)()

1
2017-11-06 16:48





यह आपके कोड से अलग क्यों है?

myFunction()
while 1:
    # rest of your code
    pass

0
2017-11-05 05:29



क्यों करता है run_once अब और भी होने की जरूरत है? - Rafe Kettler
@ राफ केटलर: असल में, मैंने कभी जवाब देने का इरादा नहीं किया लेकिन आप टिप्पणियों में कोड नहीं दिखा सकते हैं। मैंने एक टिप्पणी की लेकिन मैंने सोचा कि मैं उससे भी पूछ सकता हूं। मुझे यकीन नहीं है कि यह एक सवाल था या नहीं। - pyfunc
हम कभी नहीं जानते। - Rafe Kettler
भ्रम के लिए खेद है, मैं देख सकता हूं कि यह एक उचित समाधान कैसे हो सकता है। अधिक जानकारी के लिए कृपया अद्यतन प्रश्न पढ़ें। - Marcus Ottosson