Scala 的选项或两者是否有 Python 等价物?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22992433/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 06:11:09  来源:igfitidea点击:

Is there a Python equivalent for Scala's Option or Either?

pythonscalafunctional-programming

提问by Melvic Ybanez

I really enjoy using the Option and Either monads in Scala. Are there any equivalent for these things in Python? If there aren't, then what is the pythonic way of handling errors or "absence of value" without throwing exceptions?

我真的很喜欢在Scala中使用Option和Either monad。Python 中有这些东西的等价物吗?如果没有,那么在不抛出异常的情况下处理错误或“缺少值”的pythonic方法是什么?

采纳答案by SingleNegationElimination

The pythonic way for a function to say "I am not defined at this point" is to raise an exception.

函数说“此时我没有定义”的 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

This is, in part, because there's no (generally useful) static type checker for python. A Python function cannotsyntactically state, at compile time, that it has a particular codomain; there's no way to force callers to match all of the cases in the function's return type.

这部分是因为没有(通常有用的)python 静态类型检查器。Python 函数在编译时不能在语法上声明它有一个特定的 codomain;没有办法强制调用者匹配函数返回类型中的所有情况。

If you prefer, you can write (unpythonically) a Maybewrapper:

如果您愿意,您可以(非python地)编写一个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

But I would not do this, unless you're trying to port something from Scala to Python without changing much.

但我不会这样做,除非你试图将一些东西从 Scala 移植到 Python 而不做太多改变。

回答by jordsti

In python, for an absence of value, the variable is None, so you can do it this way.

在python中,如果没有值,变量是None,所以你可以这样做。

vars = None

vars = myfunction()

if vars is None:
     print 'No value!'
else:
     print 'Value!'

or even just check if a value is present like this

甚至只是检查是否存在这样的值

if vars is not None:
     print vars

回答by SemanticBeeng

mypyadds type definitions and type checking (not at runtime) over regular Python. They have an Optional: https://docs.python.org/3/library/typing.html#typing.Optional. More here https://www.python.org/dev/peps/pep-0484/#rationale-and-goals. Intellij has plugin support which makes it all very professional and smooth.

mypy在常规 Python 上添加类型定义和类型检查(不是在运行时)。他们有一个Optionalhttps://docs.python.org/3/library/typing.html#typing.Optional。更多在这里https://www.python.org/dev/peps/pep-0484/#rationale-and-goals。Intellij 具有插件支持,这使得它非常专业和流畅。

回答by Zorf

I realize this is pretty late to the party but I came to this page on top of google before deciding to implement it so maybe I can help others googling with this. I implemented it, you can get it from pypi as pyther-maybe, it implements both Either and Maybe with Maybe as a special subclass of Either. This example should explain how it works:

我意识到这对派对来说已经很晚了,但我在决定实施它之前来到了谷歌顶部的这个页面,所以也许我可以帮助其他人在谷歌上搜索这个。我实现了它,你可以从 pypi as 获取它pyther-maybe,它实现了或者和可能,而作为一个特殊的子类。这个例子应该解释它是如何工作的:

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

It has more features than that, some of which are pretty useless in practise (it's also an iterator for instance and has subscript notation like pyther_maybe.either(x)[pyther_maybe.Right] == x.

它有更多的特性,其中一些在实践中是非常无用的(例如它也是一个迭代器,并且有像pyther_maybe.either(x)[pyther_maybe.Right] == x.

回答by Adam L. Taylor

A list that happens to always be of length zero or one fulfills some of the same goals as optional/maybe types. You won't get the benefits of static typing in Python, but you'll probably get a run-time error even on the happy path if you write code that tries to use the "maybe" without explicitly "unwrapping" it.

碰巧总是长度为零或一的列表实现了一些与可选/可能类型相同的目标。您不会在 Python 中获得静态类型的好处,但是如果您编写的代码尝试使用“可能”而不显式“解包”它,即使在愉快的路径上,您也可能会遇到运行时错误。

回答by binrebin

Try This:

试试这个:

from monad import Monad

class Either(Monad):
  # pure :: a -> Either a
  @staticmethod
  def pure(value):
    return Right(value)

  # flat_map :: # Either a -> (a -> Either b) -> Either b
  def flat_map(self, f):
    if self.is_left:
      return self
    else:
      return f(self.value)

class Left(Either):
  def __init__(self, value):
    self.value = value
    self.is_left = True

class Right(Either):
  def __init__(self, value):
    self.value = value
self.is_left = False