也许Python中的"善良"monad

And*_*yuk 29 python haskell

试图找到一种方法来清理我的一些代码.

所以,我的Python代码中有这样的东西:

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)
Run Code Online (Sandbox Code Playgroud)

在阅读了关于Haskell的monad(特别是Maybe)的教程后,我想知道是否可以用另一种方式编写它.

Kat*_*iel 39

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
Run Code Online (Sandbox Code Playgroud)

EAFP

  • 使用异常(EAFP)的问题在于您无法区分错误(函数调用无法完成)和空结果(函数调用已正确完成且未返回任何内容)."异常"一词的意思是"通常不应发生的事情"(可能是错误).使用异常来模拟正常的控制流是误导性的.也许如果他们被称为throwables会更糟糕. (14认同)
  • 对于这个具体案例,这是明确的正确答案.作为monad的`Maybe`的全部目的是将EAFP方法明确地建模为一流实体.在Python中,它在这种形式中都是隐式的和惯用的,所以使用它! (7认同)
  • @drozzy:如果你需要根据哪些变量是"无"来有条件地执行不同的代码片段,那么显然你需要条件. (3认同)
  • 为什么Person.find在try除了块之外? (3认同)
  • @Giorgio:关于`AttributeError`捕获太多的好点(尽管通常情况下,如果无意中引发了`AttributeError`,它会指示代码中的错误).在Python中有一个先例用于控制流的异常:`StopIteration`用于停止`for`循环,`GeneratorExit`用于`generator.close()`,甚至`sys.exit()`只是` SystemExit`例外.[没有`AttributeError`它看起来不那么优雅](http://stackoverflow.com/a/8507638/4279). (3认同)

jfs*_*jfs 26

利用短路行为,默认情况下自定义对象为true,None为false:

person  = Person.find(id=12345)
company = person and person.company
country = company and company.country
Run Code Online (Sandbox Code Playgroud)


dfl*_*str 16

Python对monad没有特别好的语法.话虽如此,如果你想限制自己使用像Maybemonad 这样的东西(意思是你只能使用Maybe;你将无法制作处理任何monad的泛型函数),你可以使用以下做法:

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
Run Code Online (Sandbox Code Playgroud)

然后,使当前返回的所有方法None返回Just(value)Nothing替代.这允许您编写此代码:

Person.find(id=12345).andThen(lambda person: Company.find(person.companyId)).andThen(lambda company: Country.find(company.countryId))
Run Code Online (Sandbox Code Playgroud)

您当然可以调整lambdas以将中间结果存储在变量中; 这取决于你如何正确地做到这一点.


Rot*_*eti 8

我认为这是一个完美的情况getattr(object, name[, default])

person  = Person.find(id=12345)
company = getattr(person, 'company', None)
country = getattr(company, 'country', None)
Run Code Online (Sandbox Code Playgroud)


men*_*kgs 7

您检查了PyMonad吗?

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

它不仅包括Maybe monad,还包括列表monad,Functor和Applicative functor类。Monoids等。

在您的情况下,它将类似于:

country = Person.find(id=12345)          >> (lambda person: 
          Company.find(person.companyId) >> (lambda company: 
          Country.find(company.countryId))
Run Code Online (Sandbox Code Playgroud)

比EAFP更容易理解和清洁。