“和"怎么做?和“或"以非布尔值行事? [英] How do "and" and "or" act with non-boolean values?

查看:20
本文介绍了“和"怎么做?和“或"以非布尔值行事?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习 python,并遇到了一些又好又短但并不完全有意义的代码

上下文是:

def fn(*args):返回 len(args) 和 max(args)-min(args)

我知道它在做什么,但为什么 python 会这样做 - 即返回值而不是 True/False?

10 和 7-2

返回 5.同样,将 and 更改为 or 将导致功能更改.所以

10 或 7 - 2

将返回 10.

这是合法/可靠的风格,还是有任何陷阱?

解决方案

TL;DR

我们首先总结两个逻辑运算符 andor 的两种行为.这些习语将构成我们下面讨论的基础.

<块引用>

如果有则返回第一个 Falsy 值,否则返回最后一个表达式中的值.

<块引用>

如果有则返回第一个 Truthy 值,否则返回最后一个表达式中的值.

无论操作数如何,唯一返回布尔值的运算符是 not 运算符.


真实"和真实"评估

声明

len(args) 和 max(args) - min(args)

是一种非常 pythonic 简洁(并且可以说可读性较差)的方式来表示如果 args 不为空,则返回结果max(args) - min(args)",否则返回 0.通常,它是 if-else 表达式的更简洁表示.例如,

exp1 和 exp2

应该(大致)翻译成:

r1 = exp1如果 r1:r1 = exp2

或者,等价地,

r1 = exp2 if exp1 else exp1

同样,

exp1 或 exp2

应该(大致)翻译成:

r1 = exp1如果不是 r1:r1 = exp2

或者,等价地,

r1 = exp1 if exp1 else exp2

其中 exp1exp2 是任意 python 对象,或返回某个对象的表达式.理解逻辑 andor 运算符的使用的关键是理解它们不限于操作或返回布尔值.任何具有真实性值的对象都可以在这里进行测试.这包括 intstrlistdicttuplesetNoneType 和用户定义的对象.短路规则仍然适用.

但什么是真实?
它指的是在条件表达式中使用时如何评估对象.@Patrick Haugh 在这篇文章中很好地总结了真实性.

<块引用>

所有值都被认为是真实的";除了以下,它们是假":

  • 错误
  • 0
  • 0.0
  • 0j
  • 十进制(0)
  • 分数(0, 1)
  • [] - 一个空的 list
  • {} - 一个空的 dict
  • () - 一个空的 tuple
  • '' - 一个空的 str
  • b'' - 一个空的字节
  • set() - 一个空的 set
  • 一个空的range,例如range(0)
  • 对象
    • obj.__bool__() 返回 False
    • obj.__len__() 返回 0

一个真实的"value 将满足 ifwhile 执行的检查陈述.我们使用真实"和假"区别于boolTrueFalse.


如何工作

我们以 OP 的问题为基础,继续讨论这些运算符在这些情况下的作用.

<块引用>

给定一个具有定义的函数

def foo(*args):...

如何返回最小值和最大值之间的差值在零个或多个参数的列表中?

找到最小值和最大值很容易(使用内置函数!).这里唯一的障碍是适当地处理参数列表可能为空的极端情况(例如,调用 foo()).由于 and 运算符,我们可以在一行中完成这两项操作:

def foo(*args):返回 len(args) 和 max(args) - min(args)

foo(1, 2, 3, 4, 5)#4富()# 0

由于使用了 and,如果第一个表达式为 True,则还必须计算第二个表达式.请注意,如果第一个表达式被评估为真,则返回值总是第二个表达式的结果.如果第一个表达式被评估为 Falsy,那么返回的结果就是第一个表达式的结果.

在上面的函数中,如果foo接收到一个或多个参数,len(args)大于0(一个正数),所以返回的结果是max(args) - min(args).OTOH,如果没有传递任何参数,则 len(args)0,即 Falsy,返回 0.

请注意,编写此函数的另一种方法是:

def foo(*args):如果不是 len(args):返回 0返回最大值(参数) - 最小值(参数)

或者,更简洁地说,

def foo(*args):如果不是 args 则返回 0 否则 max(args) - min(args)

当然,如果这些函数都不执行任何类型检查,那么除非您完全信任所提供的输入,否则不要依赖这些构造的简单性.


如何工作

我用一个人为的例子以类似的方式解释了 or 的工作原理.

<块引用>

给定一个具有定义的函数

def foo(*args):...

您将如何完成 foo 以返回所有超过 9000 的数字?

我们使用 来处理这里的极端情况.我们将 foo 定义为:

def foo(*args):return [x for x in args if x >9000] 或没有超过 9000 的数字!"富(9004、1、2、500)# [9004]富(1、2、3、4)# '没有超过 9000 的数字!'

foo 对列表执行过滤以保留所有超过 9000 的数字.如果存在任何这样的数字,列表推导的结果是一个非空列表,它是真实的,所以它被返回(这里是短路).如果不存在这样的数字,则列表 comp 的结果是 [],即 Falsy.所以第二个表达式现在被求值(一个非空字符串)并被返回.

使用条件,我们可以将这个函数重写为,

def foo(*args):r = [x for x in args if x >9000]如果不是 r:return '没有超过 9000 的数字!'返回 r

和以前一样,这种结构在错误处理方面更加灵活.

I'm trying to learn python and came across some code that is nice and short but doesn't totally make sense

the context was:

def fn(*args):
    return len(args) and max(args)-min(args)

I get what it's doing, but why does python do this - ie return the value rather than True/False?

10 and 7-2

returns 5. Similarly, changing the and to or will result in a change in functionality. So

10 or 7 - 2

Would return 10.

Is this legit/reliable style, or are there any gotchas on this?

解决方案

TL;DR

We start by summarising the two behaviour of the two logical operators and and or. These idioms will form the basis of our discussion below.

and

Return the first Falsy value if there are any, else return the last value in the expression.

or

Return the first Truthy value if there are any, else return the last value in the expression.

The behaviour is also summarised in the docs, especially in this table:

The only operator returning a boolean value regardless of its operands is the not operator.


"Truthiness", and "Truthy" Evaluations

The statement

len(args) and max(args) - min(args)

Is a very pythonic concise (and arguably less readable) way of saying "if args is not empty, return the result of max(args) - min(args)", otherwise return 0. In general, it is a more concise representation of an if-else expression. For example,

exp1 and exp2

Should (roughly) translate to:

r1 = exp1
if r1:
    r1 = exp2

Or, equivalently,

r1 = exp2 if exp1 else exp1

Similarly,

exp1 or exp2

Should (roughly) translate to:

r1 = exp1
if not r1:
    r1 = exp2

Or, equivalently,

r1 = exp1 if exp1 else exp2

Where exp1 and exp2 are arbitrary python objects, or expressions that return some object. The key to understanding the uses of the logical and and or operators here is understanding that they are not restricted to operating on, or returning boolean values. Any object with a truthiness value can be tested here. This includes int, str, list, dict, tuple, set, NoneType, and user defined objects. Short circuiting rules still apply as well.

But what is truthiness?
It refers to how objects are evaluated when used in conditional expressions. @Patrick Haugh summarises truthiness nicely in this post.

All values are considered "truthy" except for the following, which are "falsy":

  • None
  • False
  • 0
  • 0.0
  • 0j
  • Decimal(0)
  • Fraction(0, 1)
  • [] - an empty list
  • {} - an empty dict
  • () - an empty tuple
  • '' - an empty str
  • b'' - an empty bytes
  • set() - an empty set
  • an empty range, like range(0)
  • objects for which
    • obj.__bool__() returns False
    • obj.__len__() returns 0

A "truthy" value will satisfy the check performed by if or while statements. We use "truthy" and "falsy" to differentiate from the bool values True and False.


How and Works

We build on OP's question as a segue into a discussion on how these operators in these instances.

Given a function with the definition

def foo(*args):
    ...

How do I return the difference between the minimum and maximum value in a list of zero or more arguments?

Finding the minimum and maximum is easy (use the inbuilt functions!). The only snag here is appropriately handling the corner case where the argument list could be empty (for example, calling foo()). We can do both in a single line thanks to the and operator:

def foo(*args):
     return len(args) and max(args) - min(args)

foo(1, 2, 3, 4, 5)
# 4

foo()
# 0

Since and is used, the second expression must also be evaluated if the first is True. Note that, if the first expression is evaluated to be truthy, the return value is always the result of the second expression. If the first expression is evaluated to be Falsy, then the result returned is the result of the first expression.

In the function above, If foo receives one or more arguments, len(args) is greater than 0 (a positive number), so the result returned is max(args) - min(args). OTOH, if no arguments are passed, len(args) is 0 which is Falsy, and 0 is returned.

Note that an alternative way to write this function would be:

def foo(*args):
    if not len(args):
        return 0
    
    return max(args) - min(args)

Or, more concisely,

def foo(*args):
    return 0 if not args else max(args) - min(args)

If course, none of these functions perform any type checking, so unless you completely trust the input provided, do not rely on the simplicity of these constructs.


How or Works

I explain the working of or in a similar fashion with a contrived example.

Given a function with the definition

def foo(*args):
    ...

How would you complete foo to return all numbers over 9000?

We use or to handle the corner case here. We define foo as:

def foo(*args):
     return [x for x in args if x > 9000] or 'No number over 9000!'

foo(9004, 1, 2, 500)
# [9004]

foo(1, 2, 3, 4)
# 'No number over 9000!'

foo performs a filtration on the list to retain all numbers over 9000. If there exist any such numbers, the result of the list comprehension is a non-empty list which is Truthy, so it is returned (short circuiting in action here). If there exist no such numbers, then the result of the list comp is [] which is Falsy. So the second expression is now evaluated (a non-empty string) and is returned.

Using conditionals, we could re-write this function as,

def foo(*args):
    r = [x for x in args if x > 9000]
    if not r:
        return 'No number over 9000!' 
    
    return r

As before, this structure is more flexible in terms of error handling.

这篇关于“和"怎么做?和“或"以非布尔值行事?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆