2011-12-14 9 views
21

मेरे कुछ कोड को साफ़ करने का तरीका खोजने का प्रयास कर रहा है। (विशेष रूप से हो सकता है में), मैं अगर यह किसी अन्य तरीके से लिखने के लिए संभव है सोच रहा थाशायद "दयालु" मोनैड पाइथन

company = None 
country = None 

person = Person.find(id=12345) 
if person is not None: # found   
    company = Company.find(person.companyId) 

    if company is not None: 
     country = Country.find(company.countryId) 

return (person, company, country) 

हास्केल के monads पर एक ट्यूटोरियल पढ़ा करने के बाद:

तो मैं अपने अजगर कोड में कुछ इस तरह की है।

उत्तर

36
company = country = None 
try: 
    person = Person.find(id=12345) 
    company = Company.find(person.companyId) 
    country = Country.find(company.countryId) 
except AttributeError: 
    pass # `person` or `company` might be None 

EAFP

+6

यह स्पष्ट इस विशिष्ट मामले के लिए सही जवाब है। एक मोनैड के रूप में 'शायद' का पूरा उद्देश्य ईएएफपी दृष्टिकोण को प्रथम श्रेणी की इकाई के रूप में स्पष्ट रूप से मॉडल करना है। पायथन में, यह इस रूप में अंतर्निहित और मूर्खतापूर्ण दोनों है, इसलिए इसका उपयोग करें! –

+0

दुर्भाग्य से मुझे वास्तव में "पता" की आवश्यकता है कि कौन सा व्यक्ति या कंपनी कोई नहीं है। – drozzy

+2

@ डोज़ज़ी: यदि आपको कोड के विभिन्न टुकड़ों को सशर्त रूप से निष्पादित करने की आवश्यकता है, तो कौन से चर 'कोई नहीं' हैं, तो स्वयं स्पष्ट रूप से आपको सशर्त की आवश्यकता है। – katrielalex

3
person = Person.find(id=12345) 
company = None if person is None else Company.find(person.companyId) 
country = None if company is None else Country.find(company.countryId) 

return (person, company, country) 
+4

मैं वास्तव में लिखता हूं कि दूसरी तरफ 'कंपनी = कंपनी.फिंड (person.companyID) अगर कोई और व्यक्ति नहीं है। यह 'कोई नहीं है 'हटा देता है और असाधारण एक के बजाय सामान्य मामला पहला होता है। –

15

अजगर monads के लिए एक विशेष रूप से अच्छा वाक्य रचना नहीं है। ऐसा कहा जा रहा है कि, यदि आप Maybe मोनैड (जैसे कि आप केवल Maybe का उपयोग करने में सक्षम होंगे) का उपयोग करने के लिए स्वयं को सीमित करना चाहते हैं, तो आप किसी भी मोनैड से निपटने वाले सामान्य कार्य नहीं कर पाएंगे), आप इसका उपयोग कर सकते हैं निम्नलिखित दृष्टिकोण:

class Maybe(): 
    def andThen(self, action): # equivalent to Haskell's >>= 
     if self.__class__ == _Maybe__Nothing: 
      return Nothing 
     elif self.__class__ == Just: 
      return action(self.value) 

    def followedBy(self, action): # equivalent to Haskell's >> 
     return self.andThen(lambda _: action) 

class _Maybe__Nothing(Maybe): 
    def __repr__(self): 
     return "Nothing" 

Nothing = _Maybe__Nothing() 

class Just(Maybe): 
    def __init__(self, v): 
     self.value = v 
    def __repr__(self): 
     return "Just(%r)" % self.value 

फिर, तरीकों कि वर्तमान में None वापसी या तो Just(value) या Nothing बजाय लौटने के सभी करते हैं। यह आप इस कोड को लिखने के लिए अनुमति देता है:

Person.find(id=12345).andThen(lambda person: Company.find(person.companyId)).andThen(lambda company: Country.find(company.countryId)) 

आप निश्चित रूप से lambdas अनुकूलन चर में मध्यवर्ती परिणाम स्टोर करने के लिए कर सकते हैं; यह आप पर निर्भर करता है कि यह ठीक से कैसे करें।

+0

इसके अलावा, मैं यहां एक और समस्या का सामना कर रहा हूं, यह है कि मुझे अंत में "इंटरमीडिएट" मान नहीं मिलते - जैसे "व्यक्ति" और "कंपनी"। यह केवल मुझे देश का शायद एक देता है। – drozzy

+0

यदि आप सभी परिणाम प्राप्त करना चाहते हैं, तो आपको अपने लैम्बडा को इस तरह लपेटना होगा: 'Person.find (id = 12345) .andhen (lambda person: company.find (person.companyId) .andhen (lambda company: Country। ढूंढें (company.countryId) .andhen (लैम्ब्डा देश: बस ((व्यक्ति, कंपनी, देश)))) '। माता-पिता की हास्यास्पद राशि पर ध्यान दें; यदि आप इस तरह की एक कार्यात्मक शैली में प्रोग्राम करना चाहते हैं तो उन्हें टाला नहीं जा सकता है। – dflemstr

+0

@dflemstr तो अंतिम "और फिर" अनिवार्य रूप से परिणाम वापस करने के लिए है? दिलचस्प। – drozzy

19

शॉर्ट सर्किट व्यवहार शोषण और एक कस्टम वस्तु डिफ़ॉल्ट रूप से सच है कि और None गलत है:

person = Person.find(id=12345) 
company = person and person.company 
country = company and company.country 
0

अधिक "pythonic" एक अलग प्रतिमान लागू करने के लिए (नहीं है कि यह दिलचस्प नहीं है कोशिश कर रहा से और ठंडा) अपनी वस्तुओं को बुद्धिमत्ता जोड़ना होगा ताकि वे अपने गुणों को प्राप्त कर सकें (और चाहे वे बिल्कुल मौजूद हों)।

बोलो एक बेस क्लास का एक उदाहरण है जो आपकी "खोज" विधि का उपयोग करता है और आईडी उदाहरण विशेषता नामों और कक्षा के नामों का सहसंबंध आपके उदाहरण के साथ काम करने के लिए करता है - मैंने कंपनी के लिए खोज के लिए न्यूनतम व्यक्ति और कंपनी कक्षाएं रखीं काम करने के लिए:

class Base(object): 
    def __getattr__(self, attr): 
     if hasattr(self, attr + "Id"): 
      return globals()[attr.title()].find(getattr(self, attr + "Id")) 
     return None 
    @classmethod 
    def find(cls, id): 
     return "id %d " % id 

class Person(Base): 
    companyId=5 

class Company(Base): 
    pass 

और कंसोल पर, ऊपर कोड पेस्ट करने के बाद:

>>> p = Person() 
>>> p.company 
'id 5 ' 

इस Base अपने कोड के साथ ऊपर बस हो सकता है:

person = Person.find(id=12345) 
company = person.company 
country = company and company.country 
+0

एचएम ... मुझे लगता है कि तुमने मुझे गलत समझा। वास्तव में "firstName, lastName" आदि जैसे गुणों के साथ एक "व्यक्ति" ऑब्जेक्ट वापस करना है ... यह सिर्फ आईडी को वापस नहीं करना चाहिए। या शायद मैं इस बिंदु को याद कर रहा हूँ? – drozzy

+0

मैंने आपको समझ लिया - यह सिर्फ 'खोज' का मेरा कार्यान्वयन है, जो स्ट्रिंग को वापस करता है, इसे आईडी नंबर से अलग करने के लिए (5 के रूप में हार्डकोड किया गया) - यहां नया क्या है '__getattr__'- आप वही खोज पाएंगे विधि अब आपके पास है। – jsbueno

+0

क्षमा करें, लेकिन मुझे नहीं पता कि यह लाइन क्या करती है: 'ग्लोबल्स() [attr.title()]। (Getattr (self, attr + "id"))' – drozzy

2

क्या आपने PyMonad की जांच की है?

https://pypi.python.org/pypi/PyMonad/

यह न केवल एक हो सकता है कि इकाई, लेकिन यह भी एक सूची इकाई, एक functor और अनुप्रयोगी functor कक्षाएं भी शामिल है। मोनोइड्स और अधिक।

आपके मामले में यह कुछ इस तरह होगा:

country = Person.find(id=12345)   >> (lambda company: 
      Company.find(person.companyId) >> (lambda country: 
      Country.find(company.countryId)) 

आसान समझने के लिए और EAFP से क्लीनर।

1

मुझे लगता है कि इस बात के लिए एक सही फिट है:

getattr(object, name[, default])

मैं getattr आवश्यक लगता है जब वस्तुओं के साथ काम करने और जिम्मेदार बताते हैं। यह dict.get(key[, default]) के बराबर है।

person = Person.find(id=12345) 
company = person and getattr(person, 'company', None) 
country = company and getattr(company, 'country', None) 
संबंधित मुद्दे