2013-07-10 4 views
51

में कनवर्ट करना मेरे पास पाइथन 3.2 में एक कोड था और मैं इसे पायथन 2.7 में चलाने के लिए चाहता था। मैंने इसे परिवर्तित कर दिया है (दोनों संस्करणों में missing_elements का कोड डाला है) लेकिन मुझे यकीन नहीं है कि यह करने का सबसे प्रभावी तरीका है या नहीं। असल में क्या होता है यदि दो yield from कॉल ऊपरी आधे में नीचे और missing_element फ़ंक्शन में निचले आधे में हैं? क्या दो हिस्सों (ऊपरी और निचले) की प्रविष्टियां एक-दूसरे में एक-दूसरे में संलग्न होती हैं ताकि माता-पिता रिकर्सन yield from कॉल के साथ काम कर सकें और दोनों हिस्सों को एकसाथ इस्तेमाल कर सकें?"से उपज" कथन को पायथन 2.7 कोड

def missing_elements(L, start, end): # Python 3.2 
    if end - start <= 1: 
     if L[end] - L[start] > 1: 
      yield from range(L[start] + 1, L[end]) 
     return 

index = start + (end - start) // 2 

# is the lower half consecutive? 
consecutive_low = L[index] == L[start] + (index - start) 
if not consecutive_low: 
    yield from missing_elements(L, start, index) 

# is the upper part consecutive? 
consecutive_high = L[index] == L[end] - (end - index) 
if not consecutive_high: 
    yield from missing_elements(L, index, end) 

def main(): 
    L = [10, 11, 13, 14, 15, 16, 17, 18, 20] 
    print(list(missing_elements(L, 0, len(L)-1))) 
    L = range(10, 21) 
    print(list(missing_elements(L, 0, len(L)-1))) 

def missing_elements(L, start, end): # Python 2.7 
    return_list = []     
    if end - start <= 1: 
     if L[end] - L[start] > 1: 
      return range(L[start] + 1, L[end]) 

    index = start + (end - start) // 2 

    # is the lower half consecutive? 
    consecutive_low = L[index] == L[start] + (index - start) 
    if not consecutive_low: 
     return_list.append(missing_elements(L, start, index)) 

    # is the upper part consecutive? 
    consecutive_high = L[index] == L[end] - (end - index) 
    if not consecutive_high: 
     return_list.append(missing_elements(L, index, end)) 
    return return_list 

उत्तर

63

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

yield from foo: 

... इस में:

for bar in foo: 
    yield bar 

हो सकती है एक प्रदर्शन लागत, ** लेकिन कभी भी अर्थपूर्ण अंतर नहीं होता है।


Are the entries from the two halves (upper and lower) appended to each other in one list so that the parent recursion function with the yield from call and use both the halves together?

नहीं! इटरेटर और जेनरेटर का पूरा बिंदु यह है कि आप वास्तविक सूचियां नहीं बनाते हैं और उन्हें एक साथ जोड़ते हैं।

लेकिन प्रभाव समान है: आप केवल एक से उपज करते हैं, फिर दूसरे से उपज करते हैं।

यदि आप ऊपरी आधा और निचले आधे के बारे में "आलसी सूचियों" के रूप में सोचते हैं, तो हाँ, आप इसे "आलसी परिशिष्ट" के रूप में सोच सकते हैं जो एक बड़ी "आलसी सूची" बनाता है। और यदि आप पैरेंट फ़ंक्शन के परिणाम पर list पर कॉल करते हैं, तो आप निश्चित रूप से वास्तविक list प्राप्त करेंगे जो कि दो सूचियों को एक साथ जोड़ने के बराबर है यदि आप के बजाय yield list(…) कर चुके हैं।

लेकिन मुझे लगता है कि इसके बारे में अन्य तरीकों के बारे में सोचना आसान है: यह वही है जो for लूप करता है।

यदि आपने दो पुनरावृत्तियों को चर में सहेजा है, और itertools.chain(upper, lower) से अधिक हो गया है, तो यह पहले से लूपिंग जैसा होगा और फिर दूसरे पर लूपिंग जैसा होगा, है ना? यहां कोई अंतर नहीं है। वास्तव में, आप बस के रूप में chain को लागू कर सकते हैं:

for arg in *args: 
    yield from arg 

* नहीं मान अपने फोन करने वाले, उपज भाव स्वयं के मूल्य, करने के लिए जनरेटर की पैदावार जनरेटर के भीतर (जो का उपयोग कर फोन करने वाले से आते हैं send विधि), जैसा कि PEP 342 में वर्णित है। आप इन उदाहरणों का उपयोग अपने उदाहरणों में नहीं कर रहे हैं। और मैं शर्त लगाता हूं कि आप अपने असली कोड में नहीं हैं। लेकिन कोरआउट-स्टाइल कोड अक्सर yield from अभिव्यक्ति के मान का उपयोग करता है-उदाहरण के लिए PEP 3156 देखें। इस तरह का कोड आमतौर पर पाइथन 3.3 जेनरेटर की अन्य विशेषताओं पर निर्भर करता है-विशेष रूप से, PEP 380 से StopIteration.value से yield from पेश किया गया था - इसलिए इसे फिर से लिखना होगा। लेकिन यदि नहीं, तो आप पीईपी का उपयोग कर सकते हैं जो आपको पूर्ण डरावनी गन्दा समतुल्य दिखाता है, और आप निश्चित रूप से उन हिस्सों को कम कर सकते हैं जिनकी आप परवाह नहीं करते हैं। और यदि आप अभिव्यक्ति के मूल्य का उपयोग नहीं करते हैं, तो यह उपरोक्त दो पंक्तियों पर निर्भर करता है।

** कोई बड़ा नहीं है, और पाइथन 3 का उपयोग करने के बारे में आप कुछ भी नहीं कर सकते हैं।3 या पूरी तरह से अपने कोड पुनर्गठन। यह बिल्कुल वही मामला है जो पाइथन 1.5 लूप, या किसी अन्य मामले में सूची समझों का अनुवाद करते हैं जब संस्करण X.Y में नया अनुकूलन होता है और आपको पुराने संस्करण का उपयोग करने की आवश्यकता होती है।

+2

आप शायद 'उपज के लिए bar', नहीं' foo' चाहते हैं। – ovgolovin

+0

@ovgolovin: धन्यवाद; तय की। – abarnert

+0

एक सवाल कैसे रिकर्सिव कॉल काम करते हैं? क्या पैरेंट फ़ंक्शन से "उपज" बच्चे में दो "उपज" से जुड़ी होती है। अगर लगातार नहीं है: missing_elements (एल, स्टार्ट, इंडेक्स) से उपज # लगातार ऊपरी हिस्सा है? consecutive_high = एल [इंडेक्स] == एल [अंत] - (अंत - सूचकांक) अगर लगातार नहीं है: missing_elements (एल, इंडेक्स, अंत) – vkaul11

2

के लिए-छोरों के साथ उन्हें बदलें:

yield from range(L[start] + 1, L[end]) 

==> 

for i in range(L[start] + 1, L[end]): 
    yield i 

ही तत्वों के बारे में:

yield from missing_elements(L, index, end) 

==> 

for el in missing_elements(L, index, end): 
    yield el 
3

मुझे लगता है मैं अजगर 3.x अनुकरण करने के लिए अजगर 2. x में yield from निर्माण एक रास्ता मिल गया यह कुशल नहीं है और यह एक छोटे hacky है, लेकिन यहाँ यह है:

import types 

def inline_generators(fn): 
    def inline(value): 
     if isinstance(value, InlineGenerator): 
      for x in value.wrapped: 
       for y in inline(x): 
        yield y 
     else: 
      yield value 
    def wrapped(*args, **kwargs): 
     result = fn(*args, **kwargs) 
     if isinstance(result, types.GeneratorType): 
      result = inline(_from(result)) 
     return result 
    return wrapped 

class InlineGenerator(object): 
    def __init__(self, wrapped): 
     self.wrapped = wrapped 

def _from(value): 
    assert isinstance(value, types.GeneratorType) 
    return InlineGenerator(value) 

उपयोग:

1 1 1 2 1 1 2 1 2 3 

हो सकता है कि किसी को यह उपयोगी पाता है:

@inline_generators 
def outer(x): 
    def inner_inner(x): 
     for x in range(1, x + 1): 
      yield x 
    def inner(x): 
     for x in range(1, x + 1): 
      yield _from(inner_inner(x)) 
    for x in range(1, x + 1): 
     yield _from(inner(x)) 

for x in outer(3): 
    print x, 

उत्पादन उत्पन्न करता है।

ज्ञात मुद्दे: भेजने के लिए समर्थन का अभाव है() और विभिन्न कोने मामलों पीईपी 380 में वर्णित ये जोड़ा जा सकता है और मैं अपनी प्रविष्टि संपादित करेंगे एक बार मैं यह काम कर रहा हो।

+4

इस समाधान का लाभ क्या है, अर्नर्नर्ट के पहले, सरल समाधान पर, जहां लूप के लिए एक में कनवर्ट करें? – ToolmakerSteve

+0

इसे एक सक्रियस्टेट नुस्खा होना चाहिए। – refi64

+0

अच्छा कार्यान्वयन। बस रिमांडिंग कि ट्रोलियस प्रोजेक्ट (पायथन <3.3 के लिए असिंसिओ) एक 'से' विधि के साथ समान है। इसका कार्यान्वयन निश्चित रूप से उत्पादन तैयार है। – jsbueno

0

मुझे पाइथन 2.7 में सबजेनरेटर्स को लागू करने के लिए एक सुंदर तंत्र होने के लिए संसाधन संदर्भों का उपयोग करना है (python-resources मॉड्यूल का उपयोग करके)। सुविधाजनक रूप से मैं संसाधन संसाधनों का उपयोग कर रहा हूं वैसे भी।

अजगर 3.3 में आप चाहते हैं:

@resources.register_func 
def get_a_thing(type_of_thing): 
    if type_of_thing is "A": 
     yield from complicated_logic_for_handling_a() 
    else: 
     yield from complicated_logic_for_handling_b() 

def complicated_logic_for_handling_a(): 
    a = expensive_setup_for_a() 
    yield a 
    expensive_tear_down_for_a() 

def complicated_logic_for_handling_b(): 
    b = expensive_setup_for_b() 
    yield b 
    expensive_tear_down_for_b() 

अजगर 2.7 में आप होगा:

@resources.register_func 
def get_a_thing(type_of_thing): 
    if type_of_thing is "A": 
     with resources.complicated_logic_for_handling_a_ctx() as a: 
      yield a 
    else: 
     with resources.complicated_logic_for_handling_b_ctx() as b: 
      yield b 

@resources.register_func 
def complicated_logic_for_handling_a(): 
    a = expensive_setup_for_a() 
    yield a 
    expensive_tear_down_for_a() 

@resources.register_func 
def complicated_logic_for_handling_b(): 
    b = expensive_setup_for_b() 
    yield b 
    expensive_tear_down_for_b() 

नोट कैसे जटिल-तर्क संचालन केवल एक संसाधन के रूप में पंजीकरण की आवश्यकता है।

4

मैं सिर्फ इस मुद्दे में आए और के बाद से मैं वापसी मान yield from की जरूरत मेरी उपयोग में थोड़ा और अधिक मुश्किल था:

result = yield from other_gen() 

यह एक सरल for पाश के रूप में प्रतिनिधित्व नहीं किया जा सकता लेकिन साथ reproduced किया जा सकता है यह:

_iter = iter(other_gen()) 
try: 
    while True: #broken by StopIteration 
     yield next(_iter) 
except StopIteration as e: 
    if e.args: 
     result = e.args[0] 
    else: 
     result = None 

उम्मीद है कि यह उन लोगों की मदद करेगा जो एक ही समस्या में आते हैं।:)

1

क्या क्रम में स्फूर्ति -380 से परिभाषा का उपयोग कर एक अजगर 2 वाक्य रचना संस्करण का निर्माण करने के बारे में:

बयान:

_i = iter(EXPR) 
try: 
    _y = next(_i) 
except StopIteration as _e: 
    _r = _e.value 
else: 
    while 1: 
     try: 
      _s = yield _y 
     except GeneratorExit as _e: 
      try: 
       _m = _i.close 
      except AttributeError: 
       pass 
      else: 
       _m() 
      raise _e 
     except BaseException as _e: 
      _x = sys.exc_info() 
      try: 
       _m = _i.throw 
      except AttributeError: 
       raise _e 
      else: 
       try: 
        _y = _m(*_x) 
       except StopIteration as _e: 
        _r = _e.value 
        break 
     else: 
      try: 
       if _s is None: 
        _y = next(_i) 
       else: 
        _y = _i.send(_s) 
      except StopIteration as _e: 
       _r = _e.value 
       break 
RESULT = _r 
:

RESULT = yield from EXPR 

को शब्दार्थ बराबर है जनरेटर में

, कथन:

return value 

शब्दार्थ

raise StopIteration(value) 
सिवाय इसके कि

, जैसा कि वर्तमान, अपवाद लौटने जनरेटर के भीतर खंड को छोड़कर द्वारा पकड़ा नहीं किया जा सकता के बराबर है।

StopIteration अपवाद बर्ताव करता है जैसे कि thusly परिभाषित:

class StopIteration(Exception): 

    def __init__(self, *args): 
     if len(args) > 0: 
      self.value = args[0] 
     else: 
      self.value = None 
     Exception.__init__(self, *args) 
संबंधित मुद्दे