Mel*_*nez 32 python functional-programming scala
我非常喜欢在Scala中使用Option和Either monad.Python中有这些东西的等价物吗?如果没有,那么什么是pythonic方式处理错误或"缺乏价值"而不抛出异常?
Sin*_*ion 20
嗯,实际上,函数说"我此时没有定义"的pythonic方法是引发异常.
>>> int("blarg")
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: 'blarg'
>>> dict(foo=5)['bar']
Traceback (most recent call last):
...
KeyError: 'bar'
>>> 1 / 0
Traceback (most recent call last):
...
ZeroDivisionError: integer division or modulo by zero
Run Code Online (Sandbox Code Playgroud)
这是因为python没有(通常有用的)静态类型检查器.在编译时,python函数不能在语法上声明它具有特定的codomain; 没有办法强制调用者匹配函数返回类型中的所有情况.
如果您愿意,可以(非自然地)编写一个Maybe包装器:
class Maybe(object):
def get_or_else(self, default):
return self.vaue if isinstance(self, Just) else default
class Just(Maybe):
def __init__(self, value):
self.value = value
class Nothing(Maybe):
pass
Run Code Online (Sandbox Code Playgroud)
但我不会这样做,除非你试图将scala中的东西移植到python而不会改变太多
小智 9
mypy在常规Python上添加类型定义和类型检查(不是在运行时).他们有Optional:https://docs.python.org/3/library/typing.html#typing.Optional.更多信息,请访问https://www.python.org/dev/peps/pep-0484/#rationale-and-goals.Intellij拥有插件支持,使其非常专业和流畅.
在python中,由于缺少值,变量为None,因此您可以这样做.
vars = None
vars = myfunction()
if vars is None:
print 'No value!'
else:
print 'Value!'
Run Code Online (Sandbox Code Playgroud)
或者甚至只是检查是否存在这样的值
if vars is not None:
print vars
Run Code Online (Sandbox Code Playgroud)
您可以使用打字包(Python 3.6.9)。使用以下使类型检查器快乐
from typing import Optional, Union
def parse_int(s: str) -> Optional[int]:
try:
return int(s)
except:
return None
print('-- optional --')
print(parse_int('123'))
print(parse_int('a'))
def parse_int2(s: str) -> Union[str, int]:
try:
return int(s)
except Exception as e:
return f'Error during parsing "{s}": {e}'
print('-- either --')
print(parse_int2('123'))
print(parse_int2('a'))
Run Code Online (Sandbox Code Playgroud)
结果
-- optional --
123
None
-- either --
123
Error during parsing "a": invalid literal for int() with base 10: 'a'
Run Code Online (Sandbox Code Playgroud)
如果你想添加一元行为,Either你可以试试这个
from typing import TypeVar, Generic, Callable
A = TypeVar('A')
B = TypeVar('B')
C = TypeVar('C')
Either = NewType('Either', Union['Left[A]', 'Right[C]'])
class Left(Generic[A]):
def __init__(self, value: A):
self.__value = value
def get(self) -> A:
raise Exception('it is left')
def get_left(self) -> A:
return self.__value
def flat_map(self, f: Callable[[B], Either]) -> Either:
return self
def map(self, f: Callable[[B], C]) -> Either:
return self
def __str__(self):
return f'Left({self.__value})'
Run Code Online (Sandbox Code Playgroud)
和正确的类型
class Right(Generic[B]):
def __init__(self, value: B):
self.__value = value
def flat_map(self, f: Callable[[B], Either]) -> Either:
return f(self.__value)
def map(self, f: Callable[[B], C]) -> Either:
return Right(f(self.__value))
def __str__(self):
return f'Right({self.__value})'
def parse_int(s: str) -> Union[Left[str], Right[int]]:
try:
return Right(int(s))
except Exception as e:
return Left(f'Error during parsing {s}: {e}')
def divide(x: int) -> Union[Left[str], Right[int]]:
return Right(4 / x) if x != 0 else Left('zero !!!')
print(parse_int('1').map(lambda x: x * 2))
print(parse_int('a').map(lambda x: x * 2))
print(parse_int('2').flat_map(divide))
print(parse_int('0').flat_map(divide))
Run Code Online (Sandbox Code Playgroud)
结果
Right(2)
Left(Error during parsing a: invalid literal for int() with base 10: 'a')
Right(2.0)
Left(zero !!!)
Run Code Online (Sandbox Code Playgroud)
我意识到派对的时间已经很晚了,但是在决定实施之前我来谷歌这个页面,所以也许我可以帮助其他人用Google搜索.我实现了它,你可以从pypi中获取它pyther-maybe,它实现了Either和Maybe with Maybe作为Either的特殊子类.这个例子应该解释它是如何工作的:
import sys
from pyther_maybe import *
def save_div ( x, y ):
if y == 0:
return nothing() # alias of Maybe()
else:
return value(x / y) # alias of Maybe(x / y)
float_test = save_div(1.0, 3.0)
assert isinstance(float_test, Maybe)
if float_test: #nothing tests as false:
float = float_test() # calling the container with no arguments returns its value
else:
sys.exit("something went wrong")
print float
# or if you want to encode a reason:
def save_div ( x, y ):
if y == 0:
return left("You can't divide by zero, silly") # alias of Either(left=...)
else:
return right(x / y) # alis of Either(...)
float_test = save_div(4.2, 0.0)
assert isinstance(float_test, Either)
def fake_exit ( string ):
print "We would have exited with:"
print string
return "Whatever value"
if float_test:
# these two are te same
float = float_test()
float = float_test.right()
else:
fake_exit(float_test.left())
# or in a shorter and more pleasant format
# does the same as above
float = float_test.extract(fake_exit)
print float # prints "Whatever value"
# Also, these containers are mutable:
box = nothing()
try:
print box() # raises exception
except RightEitherException:
print "We caught an exception"
def change_box():
box(4)
change_box()
print box() # 4
Run Code Online (Sandbox Code Playgroud)
它有更多的功能,其中一些在实践中相当无用(例如它也是一个迭代器,并且有下标表示法pyther_maybe.either(x)[pyther_maybe.Right] == x.
| 归档时间: |
|
| 查看次数: |
10911 次 |
| 最近记录: |