2009-08-13 21 views
16

खोल मैं हमेशा इस तथ्य से नाराज हूँ:कोई नहीं या एक टपल रिटर्निंग और

$ cat foo.py 
def foo(flag): 
    if flag: 
     return (1,2) 
    else: 
     return None 

first, second = foo(True) 
first, second = foo(False) 

$ python foo.py 
Traceback (most recent call last): 
    File "foo.py", line 8, in <module> 
    first, second = foo(False) 
TypeError: 'NoneType' object is not iterable 

तथ्य यह है कि सही तरीके से मुसीबतों मैं लेखन त्रुटि को पकड़ने के लिए या

की तरह कुछ है करने के लिए या तो बिना अनपैक करने में
values = foo(False) 
if values is not None: 
    first, second = values 

जो कि कष्टप्रद है। क्या इस स्थिति में सुधार करने के लिए कोई चाल है (उदाहरण के लिए फू रिटर्निंग (कोई नहीं, कोई नहीं) के बिना किसी को भी पहले और दूसरे को सेट करने के लिए या मेरे द्वारा पेश किए जाने वाले मामलों के लिए सर्वोत्तम डिज़ाइन रणनीति के बारे में कोई सुझाव नहीं है? * चर संभवतः?

उत्तर

16

ठीक है, तुम कर सकते हो ...

first,second = foo(True) or (None,None) 
first,second = foo(False) or (None,None) 

लेकिन जहां तक ​​मैं जानता हूँ कि वहाँ के रूप में कोई भी विस्तार करने के लिए एक टपल की संपूर्णता में भरने के लिए कोई आसान तरीका है।

+0

ओहोह ... मैंने इस पर विचार नहीं किया। बहुत "perlish" दृष्टिकोण, लेकिन चालाक। –

+0

मैं इस बारे में असहमत हूं कि यह perl-ish है। 'x या y' '(x? x: y)' या '(यदि x तो x else y)' या' (यदि x नहीं तो y) है या फिर भी आप इसे समझा देना चाहते हैं तो एक बहुत ही पाइथोनिक तरीका है । –

+0

ठीक है, बस "जो भी या मर()" ठेठ perl वाक्यांश "के साथ" गाओ "से बाहर काम किया। –

7

मुझे नहीं लगता कि एक चाल है।

values = foo(False) 
if values: 
    first, second = values 

या यहाँ तक कि:: आप करने के लिए अपने फोन करने के कोड को आसान बनाने में कर सकते हैं

values = foo(False) 
first, second = values or (first_default, second_default) 

जहां first_default और second_default मान हैं आप पहले और दूसरे चूक के रूप में देना चाहते हैं।

+0

कौन सा पायथन संस्करण दूसरा विकल्प काम कर रहा है? वी = (1,); एक्स, वाई = वी या (वी, 2) –

18

मुझे नहीं लगता कि लौटने में क्या गलत है (कोई नहीं, कोई नहीं)। यहां सुझाए गए समाधानों की तुलना में यह बहुत साफ है जिसमें आपके कोड में कहीं अधिक बदलाव शामिल हैं।

यह भी समझ में नहीं आता है कि आप चाहते हैं कि कोई भी स्वचालित रूप से 2 चर में विभाजित न हो।

+1

मैं बस यही सोचने की प्रक्रिया में था। मैं मानता हूं कि यह समझ में नहीं आता है: वैचारिक दृष्टिकोण से, कोई भी वापस नहीं w.r.t. नोन्स का एक गुच्छा शायद अलग है (बेशक यह वास्तविक दिनचर्या पर निर्भर करता है।यहां हम नकली मामलों की बात कर रहे हैं) –

+2

+1 - बिल्कुल - यह अजीब है कि फ़ंक्शन को परिणामों का इतना बड़ा मिश्रण मिल जाए और कॉलर में इसका सामना करना पड़े। –

+1

@Alex: अच्छा, यह निर्भर करता है। आम तौर पर, आपके पास दिनचर्या के मामले हो सकते हैं जो _x_ (x = जो भी हो) के साथ वापस आते हैं या कोई नहीं मिला है। यदि आप जानते हैं कि एक्स एक ट्यूपल है, और दो ऑब्जेक्ट्स का टुपल है, तो यह एक विशेष मामला है, लेकिन मामला _x_ या कोई नहीं मिला जो अभी भी मान्य है। तथ्य यह है कि आप इसे अनपॅक करते हैं, जिसे नियत दिनचर्या से अनजान है। –

2

आपको समाधान की x or y शैली से सावधान रहना चाहिए। वे काम करते हैं, लेकिन वे आपके मूल विनिर्देश से थोड़ा अधिक व्यापक हैं। अनिवार्य रूप से, क्या होगा यदि foo(True) एक खाली ट्यूपल () देता है? जब तक आप जानते हैं कि (None, None) के रूप में इलाज करना ठीक है, तो आप प्रदान किए गए समाधानों के साथ अच्छे हैं।

यदि यह एक आम परिदृश्य थे, मैं शायद एक उपयोगिता समारोह की तरह लिखना चाहते हैं:

# needs a better name! :) 
def to_tup(t): 
    return t if t is not None else (None, None) 

first, second = to_tup(foo(True)) 
first, second = to_tup(foo(False)) 
14

मुझे लगता है कि अमूर्त की एक समस्या है।

एक फ़ंक्शन को कुछ स्तर के अमूर्तता को बनाए रखना चाहिए, जो कोड की जटिलता को कम करने में मदद करता है।
इस मामले में, या तो फ़ंक्शन सही अमूर्तता को बनाए रखता नहीं है, या तो कॉलर इसका सम्मान नहीं कर रहा है।

फ़ंक्शन get_point2d() जैसा कुछ हो सकता था; इस मामले में, अमूर्तता का स्तर ट्यूपल पर होता है, और इसलिए कोई भी वापसी नहीं करना कुछ विशेष मामले (उदा। मौजूदा इकाई) को सिग्नल करने का एक अच्छा तरीका होगा। इस मामले में त्रुटि दो वस्तुओं की अपेक्षा करेगी, जबकि वास्तव में केवल एक चीज आपको पता है कि फ़ंक्शन एक ऑब्जेक्ट देता है (2 डी बिंदु से संबंधित जानकारी के साथ)।

लेकिन यह get_two_values_from_db() जैसा कुछ भी हो सकता है; इस मामले में अबास्ट्रक्शन को कोई भी लौटाकर तोड़ा जाएगा, क्योंकि फ़ंक्शन (जैसा कि नाम बताता है) दो मान वापस कर देना चाहिए और एक नहीं!

किसी भी तरह से, एक समारोह का उपयोग करने का मुख्य लक्ष्य - जटिलता को कम करना - कम से कम आंशिक रूप से खो गया है।

ध्यान दें कि यह समस्या मूल नाम के साथ स्पष्ट रूप से दिखाई नहीं देगी; यही कारण है कि कार्य और विधियों के लिए अच्छे नाम देना हमेशा महत्वपूर्ण होता है।

+1

महान टिप्पणी। इच्छा है कि मैं +2 –

2

कैसे इस बारे में:

$ cat foo.py 
def foo(flag): 
    if flag: 
     return (1,2) 
    else: 
     return (None,)*2 

first, second = foo(True) 
first, second = foo(False) 

संपादित करें: बस स्पष्ट होना, केवल परिवर्तन return (None,)*2 साथ return None को बदलने के लिए है। मैं बेहद आश्चर्यचकित हूं कि किसी और ने इसके बारे में सोचा नहीं है। (या यदि उनके पास है, तो मैं जानना चाहूंगा कि उन्होंने इसका उपयोग क्यों नहीं किया।)

+3

कर सकता हूं क्योंकि ओपी ने स्पष्ट रूप से कहा था "बिना फू लौटने के (कोई नहीं, कोई नहीं)"। 'वापसी (कोई नहीं,) * 2'' वापसी (कोई नहीं, कोई नहीं) 'जैसा ही है। – mhawke

+0

क्या आप वाकई यही मतलब था? मैंने सोचा कि ओपी सिर्फ * टाइपिंग * लम्बी अभिव्यक्ति 'वापसी कोई नहीं, कोई नहीं' से बचना चाहता था। मेरा रास्ता उस समस्या को हल करता है। –

+0

ठीक है, यह पूरी तरह से इसे हल नहीं करता है, लेकिन इसे कम करता है, और किसी दिए गए आकार के लंबे tuples के लिए कभी भी बेहतर काम करता है। –

1

ठीक है, मैं बस वापस लौटूंगा (कोई नहीं, कोई नहीं), लेकिन जब तक हम whacko-land (हे) में हैं, यहां ट्यूपल के उप-वर्ग का उपयोग करने का एक तरीका है। अन्य मामले में, आप कोई भी वापस नहीं लौटते हैं, लेकिन बदले में एक खाली कंटेनर लौटाते हैं, जो चीजों की भावना में दिखता है। कंटेनर का "इटरेटर" अनपॅक खाली होने पर कोई भी मूल्य नहीं। इटरेटर प्रोटोकॉल वैसे भी ...

v2.5.2 का उपयोग कर परीक्षण किया गया दर्शाता:

class Tuple(tuple): 
    def __iter__(self): 
     if self: 
      # If Tuple has contents, return normal tuple iterator... 
      return super(Tuple, self).__iter__() 
     else: 
      # Else return a bogus iterator that returns None twice... 
      class Nonerizer(object): 
       def __init__(self): 
        self.x=0 
       def __iter__(self): 
        return self 
       def next(self): 
        if self.x < 2: 
         self.x += 1 
         return None 
        else: 
         raise StopIteration 
      return Nonerizer() 


def foo(flag): 
    if flag: 
     return Tuple((1,2)) 
    else: 
     return Tuple() # It's not None, but it's an empty container. 

first, second = foo(True) 
print first, second 
first, second = foo(False) 
print first, second 

आउटपुट है वांछित:

वापसी:

1 2 
None None 
+0

अच्छे कोड-फू के लिए स्थायी उद्घोषणा :) –

+0

'Nonerizer()' को 'itertools.repeat (कोई नहीं, 2) 'के साथ प्रतिस्थापित किया जा सकता है। – augurar

+1

@augurar या बस 'iter ((कोई नहीं, कोई नहीं))', पूरे अभ्यास को व्यर्थ बनाते हैं। –

0

मैं इस समस्या के लिए एक समाधान पाया कोई नहीं या कोई वस्तु वापस नहीं।

हालांकि आप किसी वस्तु को वापस करने के लिए केवल कक्षा लिखना नहीं चाहते हैं।

from collections import namedtuple 
def foo(flag): 
if flag: 
    return None 
else: 
    MyResult = namedtuple('MyResult',['a','b','c'] 
    return MyResult._make([1,2,3]) 

और फिर: इस के लिए, आप एक नामित टपल

इस तरह

उपयोग कर सकते हैं

result = foo(True) # result = True 
result = foo(False) # result = MyResult(a=1, b=2, c=3) 

और आप इस तरह के परिणाम की पहुंच है:

print result.a # 1 
print result.b # 2 
print result.C# 3 
संबंधित मुद्दे