在Python中可能的“类单子”
我在想办法整理一下我的代码。
在我的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)
我看过关于Haskell中单子(特别是Maybe)的教程,想知道有没有其他写法。
8 个回答
20
Python 对于单子(monad)的语法并不是特别友好。不过,如果你想只使用类似于 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))
当然,你可以把这些 lambda 表达式改成用变量来存储中间结果;怎么做完全取决于你。
31
利用短路行为,以及自定义对象默认是“真”的,而None
是“假”的特点:
person = Person.find(id=12345)
company = person and person.company
country = company and company.country
42
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 是一个编程术语,意思是“先尝试做,出错再说”。也就是说,在写代码的时候,我们先去尝试执行某个操作,如果遇到错误,再去处理这个错误。这种方法和“先检查再做”相对,后者是先确认一切都没问题再去执行。EAFP 的好处是代码通常会更简洁,因为我们不需要在执行之前做很多检查。