草庐IT

python - 在返回值满足某些条件之前,如何调用一系列函数?

coder 2023-08-23 原文

有时我发现自己写的代码是这样的:

def analyse(somedata):
    result = bestapproach(somedata)
    if result:
        return result
    else:
        result = notasgood(somedata)
        if result:
            return result
        else:
            result = betterthannothing(somedata)
            if result:
                return result
            else:
                return None

太丑了。当然,有些人喜欢省略一些语法:

def analyse(somedata):
    result = bestapproach(somedata)
    if result:
        return result
    result = notasgood(somedata)
    if result:
        return result
    result = betterthannothing(somedata)
    if result:
        return result

但这并没有太大的改进;这里仍然有大量重复的代码,而且仍然很难看。

我研究了使用带有标记值的内置 iter(),但在这种情况下,None 值被用来表示循环应该保持going,而不是用于发出循环应该终止信号的哨兵。

Python 中是否有任何其他(理智的)技术来实现这种“不断尝试直到找到可行的东西”模式?

我应该澄清一下,“返回值满足某些条件”并不局限于示例中的条件是 if bool(result) is True 的情况。可能的分析函数列表中的每一个都会产生一些衡量成功程度的系数(例如 R 平方值),并且您想要设置接受的最低阈值。因此,一般解决方案不应固有地依赖于结果的真值。

最佳答案

选项 #1:使用 or

当函数总数 a) 已知,b) 很小,并且测试条件完全基于返回的真值时,可以简单地使用 or正如 Grapsus 建议的那样:

d = 'somedata'
result = f1(d) or f2(d) or f3(d) or f4(d)

因为 Python's boolean operators short-circuit , 函数从右到左执行,直到其中一个函数产生一个返回值,评估为 True , 此时分配给 result并且不评估其余功能;或者直到你用完函数,并且result已分配 False .


选项 #2:使用生成器

当函数总数 a) 未知,或 b) 非常大时,单线生成器理解方法起作用,如 Bitwise 建议的那样:

result = (r for r in (f(somedata) for f in functions) if <test-condition>).next()

这比选项 #1 有额外的优势,您可以使用任何 <test-condition>你希望,而不是仅仅依靠真值。每次.next()被称为:

  1. 我们向外部生成器询问它的下一个元素
  2. 外层生成器向内层生成器请求它的下一个元素
  3. 内部生成器请求 f来自 functions并尝试评估 f(somedata)
  4. 如果可以计算表达式(即 f 是一个函数并且 somedata 是一个有效的参数),内部生成器产生 f(somedata) 的返回值到外部发电机
  5. 如果<test-condition>满足时,外部生成器产生 f(somedata) 的返回值我们将其指定为 result
  6. 如果<test-condition>第5步不满意,重复第2-4步

此方法的一个弱点是嵌套推导可能不如其多行等价物直观。此外,如果内部生成器在不满足测试条件的情况下耗尽,.next()提出 StopIteration必须处理(在 try-except block 中)或阻止(通过确保最后一个函数始终“成功”)。


选项 #3:使用自定义函数

由于我们可以将可调用函数放在一个列表中,一种选择是按照它们应该使用的顺序明确列出您想要“尝试”的函数,然后遍历该列表:

def analyse(somedata):
    analysis_functions = [best, okay, poor]
    for f in analysis_functions:
        result = f(somedata)
        if result:
            return result

优点:修复了重复代码的问题,更清楚你是在进行一个迭代的过程,它短路了(找到“好的”结果后不继续执行函数)。

这也可以用 Python 的 for ... else 编写语法:*

def analyse(somedata):
    analysis_functions = [best, okay, poor]
    for f in analysis_functions:
        result = f(somedata)
        if result:
            break
    else:
        return None
    return result

这里的优点是识别了退出函数的不同方式,如果您希望 analyse() 完全失败,这可能很有用。函数返回 None 以外的内容, 或引发异常。否则,它只会更长更深奥。

*如"Transforming Code into Beautiful, Idiomatic Python"中所述, 从@15:50 开始。

关于python - 在返回值满足某些条件之前,如何调用一系列函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23434852/

有关python - 在返回值满足某些条件之前,如何调用一系列函数?的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  3. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  6. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  7. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  8. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  9. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  10. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

随机推荐