Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可能是Python中带有方法链接的monad_Python_Exception Handling_Monads_Method Chaining_Maybe - Fatal编程技术网

可能是Python中带有方法链接的monad

可能是Python中带有方法链接的monad,python,exception-handling,monads,method-chaining,maybe,Python,Exception Handling,Monads,Method Chaining,Maybe,我正在尝试用python实现Maybe monad。 然而,我也想要的是某种链接能力 所以我有一门课: class Maybe: def __init__(self, val): self.val = val def do(self, func): # Bind function if self.val is None: return None else: return func(

我正在尝试用python实现Maybe monad。 然而,我也想要的是某种链接能力

所以我有一门课:

class Maybe:
    def __init__(self, val):
        self.val = val

    def do(self, func):  # Bind function
        if self.val is None:
            return None
        else:
            return func(self.val)
我有两个职能:

def double(number):
    try:
        result = number * 2
        return Maybe(result)
    except:
        return Maybe(None)

def square(number):
    try:
        result = number * number
        return Maybe(result)
    except:
        return Maybe(None)
下面是我如何使用它的:

 result = Maybe(5).do(double).do(square)
    print(result.val)
我正在寻找一种方法来链接多个函数,每个函数执行一个特定的任务。每个函数都将前一个函数的输出作为输入。如果链中的任何函数引发异常,则链应该断开

这是模拟单子的正确方法吗

这也是处理异常的正确方法吗

这能改进吗


非常感谢。

以下内容满足了您的要求,并使功能更加简洁。还进行了更新以正确捕获异常:

class Maybe:
    def __init__(self, val, err=None):
        self.val = val
        self.err = err

    def __repr__(self):
        if self.err is not None:
           return 'Maybe('+repr(self.val)+', '+repr(self.err)+')'
        else:
           return 'Maybe('+repr(self.val)+')'

    def do(self, func):  # Bind function
        if self.val is not None:
            try:
                val = func(self.val)
            except Exception as e:
                return Maybe(None, e)
            if not isinstance(val, Maybe):
                return Maybe(val)
            else:
                 return val
        else:
            return Maybe(None, self.err)


def double(number):
    result = number * 2
    return result

def square(number):
    result = number * number
    return result

result = Maybe(5).do(double).do(square)
print(result.val)
print(result)
result2 = Maybe('a').do(double).do(square)
print(result2.val)
print(result2)
印刷品:

100
Maybe(100)
None
Maybe(None, TypeError("can't multiply sequence by non-int of type 'str'",))

这样做的缺点是它有意地抑制错误,这在python中通常被认为是一个坏主意

但是,您可以捕获并存储
实例中发生的任何错误,并将其报告回来

例如:

class Maybe(object):
    def __init__(self, val, error=None):
        self.val = val
        self.error = error

    def __repr__(self):
        if self.val is not None:
            return repr(self.val)
        else:
            return repr(self.error)

    def do(self, func):
        if self.val is None:
            return self
        try:
            return Maybe(func(self.val))
        except Exception as e:
            return Maybe(None, e)

def squared(x):
    return x * x

def addone(x):
    return x + 1

result1 = Maybe(5).do(squared).do(addone)
result2 = Maybe('a').do(squared).do(addone)
print result1
print result2
class Maybe:
    def __init__(self, val, error = None):
        self.val = val
        self.error = error

    def __call__(self, func, *xs, **kws):
        v = None
        e = None
        if self.val is not None:
            try:
                v = func(self.val, *xs, **kws)
            except Exception as e:
                pass
        return Maybe(v, error = e)

def double(n):
    return n * 2

def square(n):
    return n * n

def multiply_by(n, by):
    return n * by

def message(n, *xs, **kws):
    return 'Message: {} {} {}'.format(n, xs, kws)

ms = [
    Maybe(5)(double)(square),
    Maybe(4)(square)(square)(double),
    Maybe(3)(square)(square),
    Maybe(7)(multiply_by, 3),
    Maybe(9)(message, 1, 2, 3, foo = 'blah'),
    Maybe('hi')(double)(square),
]

for m in ms:
    print(dict(val = m.val, error = m.error))
这将产生:

26
TypeError("can't multiply sequence by non-int of type 'str'",)
这与DanD的答案类似,但其优点是存储发生的错误,而不是完全抑制它


无论你如何切分,这个习惯用法都会让人感觉有些“不和谐”,但这是一种更为稳健的处理方式

>我可以考虑一些调整:

  • 按照其他人的建议,存储异常
  • 使
    可以调用
    以消除对
    do
    的需要
  • 通过调用传递
    xs
    kws
    ,以防任何函数采用其他参数
例如:

class Maybe(object):
    def __init__(self, val, error=None):
        self.val = val
        self.error = error

    def __repr__(self):
        if self.val is not None:
            return repr(self.val)
        else:
            return repr(self.error)

    def do(self, func):
        if self.val is None:
            return self
        try:
            return Maybe(func(self.val))
        except Exception as e:
            return Maybe(None, e)

def squared(x):
    return x * x

def addone(x):
    return x + 1

result1 = Maybe(5).do(squared).do(addone)
result2 = Maybe('a').do(squared).do(addone)
print result1
print result2
class Maybe:
    def __init__(self, val, error = None):
        self.val = val
        self.error = error

    def __call__(self, func, *xs, **kws):
        v = None
        e = None
        if self.val is not None:
            try:
                v = func(self.val, *xs, **kws)
            except Exception as e:
                pass
        return Maybe(v, error = e)

def double(n):
    return n * 2

def square(n):
    return n * n

def multiply_by(n, by):
    return n * by

def message(n, *xs, **kws):
    return 'Message: {} {} {}'.format(n, xs, kws)

ms = [
    Maybe(5)(double)(square),
    Maybe(4)(square)(square)(double),
    Maybe(3)(square)(square),
    Maybe(7)(multiply_by, 3),
    Maybe(9)(message, 1, 2, 3, foo = 'blah'),
    Maybe('hi')(double)(square),
]

for m in ms:
    print(dict(val = m.val, error = m.error))

这个问题已经得到了回答,但我觉得使用Maybe monad的界面可以更具可读性。允许进行左右调用的接口,例如:

 square(double(Maybe(5)))
另外,最好将Maybe类型返回给用户使用,这样他们就可以选择进一步链接,而不是立即检索值。此功能类似于Swift的可选类型

class Maybe(object):
  def __init__(self, val=None)
     self.val

  def unwrap(self):
     return self.val

  def calc(self, func):
     try:
       return func(self.val)
     except:
       return None

def double(number):
    return Maybe(maybe.calc(lambda x: x*2))

def square(number):
    return Maybe(maybe.calc(lambda x: x**2))

print square(double(Maybe(5))) # prints Maybe type
print square(double(Maybe(5))).unwrap() # prints '100'
print square(double(None)) # prints 'None'

异常不会存储在my Response中,因为调用方希望在链式操作失败时检查异常本身并转换为“nothing”(即None)。这允许用户使用链轻松地处理条件语句中的失败。

这最好在代码检查时进行,因为您不想解决特定问题,只想对代码进行一些注释。不,这也不好,因为代码也不起作用:d看一看我想这是上下文:
Maybe(0)。do(double)
谢谢。。。个别方法中的异常处理真让我恼火。这看起来好多了。谢谢乔。。。这看起来更好。。。但是为什么你会称这种方法为“非音速”呢?主要是因为错误不会“传播”起来。相反,您需要检查返回的值。值检查代替try/except通常被认为是非音速的。这并不一定是坏事,只是看起来总是有点不合适。这基本上是“三思而后行”和“请求原谅比允许更容易”的老生常谈。Python更喜欢后者。非常感谢。。我现在被宠坏了!