【问题标题】:Functional python programming and conditionals函数式python编程和条件
【发布时间】:2012-10-23 22:21:55
【问题描述】:

我正在尝试以一种功能性的方式编写一个 python 函数。问题是我不知道如何将 if 条件转换为功能样式。我有两个变量:AC,我想检查以下条件:

def function():
    if(A==0): return 0
    elif(C!=0): return 0
    elif(A > 4): return 0
    else: someOtherFunction()

我查看了lambda shortcircuiting,但无法正常工作。

提前感谢您的帮助!

【问题讨论】:

  • 返回0 表示失败是一种非常糟糕的做法。我建议你要么抛出异常(最好),或者在最坏的情况下,返回None
  • 我可能是唯一的一个,但这个问题对我来说绝对没有意义。
  • 我遇到的问题是 Python 不是 一种纯函数式语言,因此不应像使用它一样使用它。 Python 有函数式的方面,这对于某些任务来说非常棒,但是对于像这样的任务,命令式的风格更加清晰和容易,所以使用它。
  • 可以在一行中完成:“return 0 if A == 0 else (0 if C != 0 else (0 if A > 4 else someOtherFunction()))”缺少可读性。

标签: python lambda functional-programming conditional-statements


【解决方案1】:

来自link you posted

FP 不鼓励或完全禁止陈述, 而是使用表达式的评估

因此,您可以使用conditional expression,而不是if-statements:

def function():
    return (0 if ((A == 0) or (C != 0) or (A > 4)) else
            someOtherFunction())

或者,(如果有许多不同的值特别有用):

def function():
    return (0 if A == 0 else
            0 if C != 0 else
            0 if A > 4 else
            someOtherFunction())

顺便提一下链接的文章提出

(<cond1> and func1()) or (<cond2> and func2()) or (func3())

相当于

if <cond1>:   func1()
elif <cond2>: func2()
else:         func3()

问题是它们不相等!当&lt;cond1&gt; 为真但func1() 为假(例如False0None)时,布尔表达式无法返回正确的值。 (或者类似地,&lt;cond2&gt; 为真但func2 为假。)

(<cond1> and func1())

的目的是当&lt;cond1&gt; 为真时计算为func1(),但当func1() 为假时,(&lt;cond1&gt; and func1()) 计算为False,因此整个表达式被传递,Python 继续评估 (&lt;cond2&gt; and func2()) 而不是短路。

所以这里有一段有趣的历史。 2005 年, Raymond Hettinger foundz = (0+4j) 时在type(z)==types.ComplexType and z.real or z 中存在类似的难以发现的错误,因为z.real 是错误的。出于避免我们遇到类似错误的愿望,使用a less error-prone syntax(条件表达式)的想法诞生了。

【讨论】:

  • 第三个代码是我一直在寻找的,但该代码似乎在语法上有些错误...
  • 我很好奇如何在没有三元组的情况下仅使用布尔值来编写它(我自己失败了)。
  • @thg435:您也许可以使用(boolean and return_value) 表达式。例如:(False and 'retvalA') or (True and 'retvalB') or 'retvalC' 的计算结果为 'retvalB'。但是,您必须小心您的返回值是真实的。正是为了克服返回 Falsish 值的问题,才创建了三元表达式。
  • @unutbu:是的,但是在这种特定情况下(retval=0)会是什么样子?
  • @thg435: 一段有趣的历史:Raymond Hettinger found type(z)==types.ComplexType and z.real or zz = (0+4j) 时包含一个难以发现的错误,因为z.real 是错误的。出于将我们从类似错误中拯救出来的愿望,PEP308 诞生了。
【解决方案2】:

您当前的代码中没有任何非“功能风格”!谁说条件句无论如何都起作用?几乎所有函数式语言都有某种条件运算符,例如 Lisp 中的 cond 特殊形式。

如果代码使用赋值运算符,或者以某种方式改变状态(例如,附加到列表),我会对代码提出问题,但事实上,问题中的函数已经处于“函数式” " - 没有状态变化。

也许你的意思是这样的?

return A != 0 and C == 0 and A <= 4 and someOtherFunction()

如果A == 0C != 0A &gt; 4 以上将返回False,在所有其他情况下它将返回调用someOtherFunction() 的值。顺便说一句,False 可以假定为 0(例如,42 + False == 42),因此从调用者的角度来看,问题中代码中的语义将被保留。

请注意,您将链接中的信息与上下文无关。绝对没有必要为此使用lambda,本文只是解释如何绕过Python 中lambdas 的固有限制,即您不能在内部返回语句(如if-elif-else) -只允许使用表达式,但您可以使用布尔运算符来伪造它们。在正常的函数上下文中,一定要使用条件。

【讨论】:

  • 我同意,但是根据我在第一篇文章中提供的链接,if 条件可以转换为 lambda 表达式。在我的作业中,它说我应该让我的代码尽可能地像函数一样,这就是我问的原因。
  • 即使他们可以被转换,无论如何也不要。你把事情做到了极致,这样一个人为的代码会让你一事无成。我敢肯定这不是你老师的想法。
【解决方案3】:

虽然 Peter Norvig 是一个非常棒的人,但他的网站很难搜索。

我记得在一次功能性 Python 演讲之前的一些研究期间,我在他的网站上读到过关于 Can I do the equivalent of (test ? result : alternative) in Python? 的信息。

我不会根据我的发现来左右你,但你还是应该去阅读关于函数式三元条件运算符的部分。

def if_(test, result, alternative=None):
    "If test is true, 'do' result, else alternative. 'Do' means call if callable."
    if test:
        if callable(result): result = result()
        return result
    else:
        if callable(alternative): alternative = alternative()
        return alternative

【讨论】:

    【解决方案4】:

    按原样使用。

    Python 确实没有 有语法和内置库,可以很容易地对所有函数进行编程以直接返回单个表达式。无论如何,这不是函数式风格最重要的部分,最重要的部分是确保您的函数保持参照完整性。基本上,这意味着无论何时为它们提供相同的输入值,它们都会返回相同的输出。

    因此,当尝试在 Python 中进行函数式编程时,我确实完全避免使用语句。我使用一个局部变量赋值块作为来自 Haskell 的 let ... in ... 的等价物。我使用 if/elif/else 链作为 Haskell 中的 case 表达式的等效项。并且通常有一些内置类型没有提供足够的接口来创建它们的新“修改”版本而不是就地更新它们,因此您必须使用显式复制操作来实现此类操作,然后使用突变新副本。

    Python 允许您直接实现函数式设计。您可以轻松地将您的程序构建为一组显式传递状态且没有副作用的函数,因此您可以以非常相似的方式设计高级算法函数式编程语言。从这个意义上说,几乎每种编程语言都支持函数式编程,如果您准备好忍受伪造一流函数所必需的样板文件。由于 Python 具有 一流的功能,您甚至不必忍受样板文件。

    但这就是 Python 在支持函数式编程方面所能做到的。它并不真正支持将函数实现为单个引用透明的表达式。但这并不重要。在不强制或不跟踪纯度的语言中,您可以获得函数式编程的几乎所有好处,您只需将程序设计为一堆引用透明的函数,然后如何实现只要 interface 保持引用透明,这些函数实际上并不重要。

    【讨论】:

      猜你喜欢
      • 2015-11-21
      • 2010-09-06
      • 2017-05-24
      • 2021-01-11
      • 2012-06-13
      • 1970-01-01
      • 2016-01-11
      • 1970-01-01
      • 2011-05-15
      相关资源
      最近更新 更多