"and" 和 "or" 如何处理非布尔值?
How do "and" and "or" act with non-boolean values?
我正在努力学习 python 并遇到了一些不错且简短但并不完全有意义的代码
上下文是:
def fn(*args):
return len(args) and max(args)-min(args)
我明白它在做什么,但为什么 python 这样做 - 即 return 值而不是 True/False?
10 and 7-2
returns 5. 同样,将 and 更改为 or 将导致功能发生变化。所以
10 or 7 - 2
会return10.
这是 legit/reliable 风格,还是有什么问题?
引用自Python Docs
Note that neither and
nor or
restrict the value and type they return
to False
and True
, but rather return the last evaluated argument. This
is sometimes useful, e.g., if s
is a string that should be replaced by
a default value if it is empty, the expression s or 'foo'
yields the
desired value.
所以,这就是 Python 被设计用来评估布尔表达式的方式,上面的文档让我们了解了他们这样做的原因。
要获得布尔值,只需对其进行类型转换。
return bool(len(args) and max(args)-min(args))
为什么?
短路。
例如:
2 and 3 # Returns 3 because 2 is Truthy so it has to check 3 too
0 and 3 # Returns 0 because 0 is Falsey and there's no need to check 3 at all
or
也一样,即它会return一找到Truthy的表达式,导致求值表达式的其余部分是多余的。
而不是 return 硬核 True
或 False
,Python returns Truthy 或 Falsey,无论如何都将评估为 True
或 False
。您可以按原样使用该表达式,它仍然有效。
要了解什么是 Truthy 和 Falsey,请检查
Is this legit/reliable style, or are there any gotchas on this?
这是合法的,它是一个 short circuit evaluation,其中最后一个值是 returned。
你提供了一个很好的例子。如果没有传递任何参数,该函数将 return 0
,并且代码不必检查没有传递任何参数的特殊情况。
另一种使用它的方法是将 None 个参数默认为可变基元,如空列表:
def fn(alist=None):
alist = alist or []
....
如果一些非真值被传递给 alist
它默认为一个空列表,这是避免 if
语句和 mutable default argument pitfall
的便捷方式
是的。这是和比较的正确行为。
至少在 Python、A and B
returns B
if A
本质上是 True
包括 if A
NOT Null,NOT None
NOT 空容器(例如空的 list
、dict
等)。 A
返回 IFF A
本质上是 False
或 None
或 Empty 或 Null。
另一方面,A or B
returns A
if A
本质上是 True
包括如果 A
不是 Null,NOT None
不是空容器(例如空的 list
、dict
等),否则它是 returns B
。
这种行为很容易被忽视(或忽略),因为在 Python 中,任何 non-null
非空对象的计算结果为 True 都被视为布尔值。
例如,以下所有内容都会打印"True"
if [102]:
print "True"
else:
print "False"
if "anything that is not empty or None":
print "True"
else:
print "False"
if {1, 2, 3}:
print "True"
else:
print "False"
另一方面,以下所有内容都将打印 "False"
if []:
print "True"
else:
print "False"
if "":
print "True"
else:
print "False"
if set ([]):
print "True"
else:
print "False"
TL;DR
我们首先总结两个逻辑运算符and
和or
的两种行为。这些成语将构成我们下面讨论的基础。
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 docs 中进行了总结,尤其是在 table:
唯一的运算符 return 计算布尔值而不考虑其操作数是 not
运算符。
“真实”和“真实”评价
声明
len(args) and max(args) - min(args)
是一种 非常 pythonic 简洁(并且可以说可读性较差)的表达方式“if args
不为空,returnmax(args) - min(args)
”的结果,否则return0
。通常,它是 if-else
表达式的更简洁表示。例如,
exp1 and exp2
应该(大致)翻译成:
r1 = exp1
if r1:
r1 = exp2
或者,等价地,
r1 = exp2 if exp1 else exp1
同理,
exp1 or exp2
应该(大致)翻译成:
r1 = exp1
if not r1:
r1 = exp2
或者,等价地,
r1 = exp1 if exp1 else exp2
其中 exp1
和 exp2
是任意 python 对象,或者 return 某些对象的表达式。理解逻辑 and
和 or
运算符的用法的关键是理解它们不限于对布尔值进行操作或 returning 布尔值。任何具有真值的对象都可以在这里进行测试。这包括 int
、str
、list
、dict
、tuple
、set
、NoneType
和用户定义的对象。短路规则仍然适用。
但什么是真实?
它指的是在条件表达式中使用时如何评估对象。 @Patrick Haugh 在 .
中很好地总结了真实性
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
.
and
的工作原理
我们以 OP 的问题为基础,继续讨论这些运算符在这些情况下的表现。
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?
找到最小值和最大值很容易(使用内置函数!)。这里唯一的障碍是适当地处理参数列表可能为空的极端情况(例如,调用 foo()
)。由于 and
运算符,我们可以在一行中完成这两项操作:
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4
foo()
# 0
由于使用了 and
,如果第一个表达式是 True
,则还必须计算第二个表达式。请注意,如果第一个表达式被评估为真值,return 值是 always 第二个表达式 的结果。如果第一个表达式被评估为 Falsy,则结果 returned 是第一个表达式的结果。
在上面的函数中,如果foo
接收到一个或多个参数,len(args)
大于0
(一个正数),所以结果returned是 max(args) - min(args)
。 OTOH,如果没有传递任何参数,len(args)
是 0
,这是 Falsy,而 0
是 returned.
请注意,编写此函数的另一种方法是:
def foo(*args):
if not len(args):
return 0
return max(args) - min(args)
或者,更简洁地说,
def foo(*args):
return 0 if not args else max(args) - min(args)
当然,none 这些函数执行任何类型检查,所以除非您完全信任所提供的输入,否则 不要 依赖这些结构的简单性。
or
的工作原理
我用一个人为的例子以类似的方式解释了 or
的工作原理。
Given a function with the definition
def foo(*args):
...
How would you complete foo
to return all numbers over 9000
?
我们使用or
来处理这里的极端情况。我们定义foo
为:
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
对列表执行过滤以保留超过 9000
的所有数字。如果存在任何这样的数字,列表理解的结果是一个非空列表,它是 Truthy,所以它是 returned(这里是短路)。如果不存在这样的数字,则列表 comp 的结果是 []
,这是 Falsy。所以第二个表达式现在被评估(一个非空字符串)并且是 returned.
使用条件,我们可以将这个函数重写为,
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
和以前一样,这种结构在错误处理方面更加灵活。
and 和 or 执行布尔逻辑,但它们 return 是比较时的实际值之一。当使用 和 时,值在布尔上下文中从左到右计算。 0、''、[]、()、{}、 和 None 在布尔上下文中为假;其他一切都是真的。
如果布尔上下文中的所有值都为真,和 return最后一个值。
>>> 2 and 5
5
>>> 2 and 5 and 10
10
如果在布尔上下文中任何值为假,和 returns 第一个假值。
>>> '' and 5
''
>>> 2 and 0 and 5
0
所以代码
return len(args) and max(args)-min(args)
returns 当存在 args 时 max(args)-min(args)
的值,否则 returns len(args)
为 0。
Is this legit/reliable style, or are there any gotchas on this?
我想补充一下这个问题,它不仅合法可靠,而且非常实用。这是一个简单的例子:
>>>example_list = []
>>>print example_list or 'empty list'
empty list
因此,您可以真正发挥自己的优势。为了简洁起见,我是这样看的:
Or
运算符
Python 的 or
运算符 returns 第一个 Truth-y 值,或最后一个值,并停止
And
运算符
Python的and
运算符returns第一个False-y值,或者最后一个值,停止
幕后花絮
在python中,除0外,所有数字都被解释为True
。因此,说:
0 and 10
等同于:
False and True
这显然是False
。因此合乎逻辑的是 returns 0
陷阱
是的,有一些问题。
fn() == fn(3) == fn(4, 4)
首先,如果fn
returns 0
,你无法知道它是在没有任何参数的情况下被调用的,有一个参数还是有多个相等的参数:
>>> fn()
0
>>> fn(3)
0
>>> fn(3, 3, 3)
0
fn
是什么意思?
那么,Python就是动态语言。它没有在任何地方指定 fn
做什么,它的输入应该是什么以及它的输出应该是什么样子。因此,正确命名函数非常重要。同样,参数不必称为 args
。 delta(*numbers)
或 calculate_range(*numbers)
可能更好地描述了该函数应该做什么。
参数错误
最后,逻辑运算符 and
应该可以防止函数在没有任何参数的情况下调用失败。但是,如果某些参数不是数字,它仍然会失败:
>>> fn('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>> fn(1, '2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: '>' not supported between instances of 'str' and 'int'
>>> fn('a', 'b')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
可能的选择
下面是根据"Easier to ask for forgiveness than permission." principle写函数的方法:
def delta(*numbers):
try:
return max(numbers) - min(numbers)
except TypeError:
raise ValueError("delta should only be called with numerical arguments") from None
except ValueError:
raise ValueError("delta should be called with at least one numerical argument") from None
举个例子:
>>> delta()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in delta
ValueError: delta should be called with at least one numerical argument
>>> delta(3)
0
>>> delta('a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 'b')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta(3, 4.5)
1.5
>>> delta(3, 5, 7, 2)
5
如果你真的不想在没有任何参数的情况下调用 delta
时引发异常,你可以 return 一些否则不可能的值(例如 -1
或None
):
>>> def delta(*numbers):
... try:
... return max(numbers) - min(numbers)
... except TypeError:
... raise ValueError("delta should only be called with numerical arguments") from None
... except ValueError:
... return -1 # or None
...
>>>
>>> delta()
-1
通俗易懂,
AND : if first_val is False return first_val else second_value
例如:
1 and 2 # here it will return 2 because 1 is not False
但是,
0 and 2 # will return 0 because first value is 0 i.e False
and =>谁假,谁假。如果两者都为真那么只有它会变为真
或: if first_val is False return second_val else first_value
原因是,如果 first 为假,它会检查 2 是否为真。
例如:
1 or 2 # here it will return 1 because 1 is not False
但是,
0 or 2 # will return 2 because first value is 0 i.e False
or => 假则真。所以如果第一个值是假的,不管 2 值是什么。
所以它 returns 可以是第二个值。
如果有人是真的那么它就会变成真的。如果两者都为假,则它将变为假。
我正在努力学习 python 并遇到了一些不错且简短但并不完全有意义的代码
上下文是:
def fn(*args):
return len(args) and max(args)-min(args)
我明白它在做什么,但为什么 python 这样做 - 即 return 值而不是 True/False?
10 and 7-2
returns 5. 同样,将 and 更改为 or 将导致功能发生变化。所以
10 or 7 - 2
会return10.
这是 legit/reliable 风格,还是有什么问题?
引用自Python Docs
Note that neither
and
noror
restrict the value and type they return toFalse
andTrue
, but rather return the last evaluated argument. This is sometimes useful, e.g., ifs
is a string that should be replaced by a default value if it is empty, the expressions or 'foo'
yields the desired value.
所以,这就是 Python 被设计用来评估布尔表达式的方式,上面的文档让我们了解了他们这样做的原因。
要获得布尔值,只需对其进行类型转换。
return bool(len(args) and max(args)-min(args))
为什么?
短路。
例如:
2 and 3 # Returns 3 because 2 is Truthy so it has to check 3 too
0 and 3 # Returns 0 because 0 is Falsey and there's no need to check 3 at all
or
也一样,即它会return一找到Truthy的表达式,导致求值表达式的其余部分是多余的。
而不是 return 硬核 True
或 False
,Python returns Truthy 或 Falsey,无论如何都将评估为 True
或 False
。您可以按原样使用该表达式,它仍然有效。
要了解什么是 Truthy 和 Falsey,请检查
Is this legit/reliable style, or are there any gotchas on this?
这是合法的,它是一个 short circuit evaluation,其中最后一个值是 returned。
你提供了一个很好的例子。如果没有传递任何参数,该函数将 return 0
,并且代码不必检查没有传递任何参数的特殊情况。
另一种使用它的方法是将 None 个参数默认为可变基元,如空列表:
def fn(alist=None):
alist = alist or []
....
如果一些非真值被传递给 alist
它默认为一个空列表,这是避免 if
语句和 mutable default argument pitfall
是的。这是和比较的正确行为。
至少在 Python、A and B
returns B
if A
本质上是 True
包括 if A
NOT Null,NOT None
NOT 空容器(例如空的 list
、dict
等)。 A
返回 IFF A
本质上是 False
或 None
或 Empty 或 Null。
另一方面,A or B
returns A
if A
本质上是 True
包括如果 A
不是 Null,NOT None
不是空容器(例如空的 list
、dict
等),否则它是 returns B
。
这种行为很容易被忽视(或忽略),因为在 Python 中,任何 non-null
非空对象的计算结果为 True 都被视为布尔值。
例如,以下所有内容都会打印"True"
if [102]:
print "True"
else:
print "False"
if "anything that is not empty or None":
print "True"
else:
print "False"
if {1, 2, 3}:
print "True"
else:
print "False"
另一方面,以下所有内容都将打印 "False"
if []:
print "True"
else:
print "False"
if "":
print "True"
else:
print "False"
if set ([]):
print "True"
else:
print "False"
TL;DR
我们首先总结两个逻辑运算符and
和or
的两种行为。这些成语将构成我们下面讨论的基础。
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 docs 中进行了总结,尤其是在 table:
唯一的运算符 return 计算布尔值而不考虑其操作数是 not
运算符。
“真实”和“真实”评价
声明
len(args) and max(args) - min(args)
是一种 非常 pythonic 简洁(并且可以说可读性较差)的表达方式“if args
不为空,returnmax(args) - min(args)
”的结果,否则return0
。通常,它是 if-else
表达式的更简洁表示。例如,
exp1 and exp2
应该(大致)翻译成:
r1 = exp1
if r1:
r1 = exp2
或者,等价地,
r1 = exp2 if exp1 else exp1
同理,
exp1 or exp2
应该(大致)翻译成:
r1 = exp1
if not r1:
r1 = exp2
或者,等价地,
r1 = exp1 if exp1 else exp2
其中 exp1
和 exp2
是任意 python 对象,或者 return 某些对象的表达式。理解逻辑 and
和 or
运算符的用法的关键是理解它们不限于对布尔值进行操作或 returning 布尔值。任何具有真值的对象都可以在这里进行测试。这包括 int
、str
、list
、dict
、tuple
、set
、NoneType
和用户定义的对象。短路规则仍然适用。
但什么是真实?
它指的是在条件表达式中使用时如何评估对象。 @Patrick Haugh 在
All values are considered "truthy" except for the following, which are "falsy":
None
False
0
0.0
0j
Decimal(0)
Fraction(0, 1)
[]
- an emptylist
{}
- an emptydict
()
- an emptytuple
''
- an emptystr
b''
- an emptybytes
set()
- an emptyset
- an empty
range
, likerange(0)
- objects for which
obj.__bool__()
returnsFalse
obj.__len__()
returns0
A "truthy" value will satisfy the check performed by
if
orwhile
statements. We use "truthy" and "falsy" to differentiate from thebool
valuesTrue
andFalse
.
and
的工作原理
我们以 OP 的问题为基础,继续讨论这些运算符在这些情况下的表现。
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?
找到最小值和最大值很容易(使用内置函数!)。这里唯一的障碍是适当地处理参数列表可能为空的极端情况(例如,调用 foo()
)。由于 and
运算符,我们可以在一行中完成这两项操作:
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4
foo()
# 0
由于使用了 and
,如果第一个表达式是 True
,则还必须计算第二个表达式。请注意,如果第一个表达式被评估为真值,return 值是 always 第二个表达式 的结果。如果第一个表达式被评估为 Falsy,则结果 returned 是第一个表达式的结果。
在上面的函数中,如果foo
接收到一个或多个参数,len(args)
大于0
(一个正数),所以结果returned是 max(args) - min(args)
。 OTOH,如果没有传递任何参数,len(args)
是 0
,这是 Falsy,而 0
是 returned.
请注意,编写此函数的另一种方法是:
def foo(*args):
if not len(args):
return 0
return max(args) - min(args)
或者,更简洁地说,
def foo(*args):
return 0 if not args else max(args) - min(args)
当然,none 这些函数执行任何类型检查,所以除非您完全信任所提供的输入,否则 不要 依赖这些结构的简单性。
or
的工作原理
我用一个人为的例子以类似的方式解释了 or
的工作原理。
Given a function with the definition
def foo(*args): ...
How would you complete
foo
to return all numbers over9000
?
我们使用or
来处理这里的极端情况。我们定义foo
为:
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
对列表执行过滤以保留超过 9000
的所有数字。如果存在任何这样的数字,列表理解的结果是一个非空列表,它是 Truthy,所以它是 returned(这里是短路)。如果不存在这样的数字,则列表 comp 的结果是 []
,这是 Falsy。所以第二个表达式现在被评估(一个非空字符串)并且是 returned.
使用条件,我们可以将这个函数重写为,
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
和以前一样,这种结构在错误处理方面更加灵活。
and 和 or 执行布尔逻辑,但它们 return 是比较时的实际值之一。当使用 和 时,值在布尔上下文中从左到右计算。 0、''、[]、()、{}、 和 None 在布尔上下文中为假;其他一切都是真的。
如果布尔上下文中的所有值都为真,和 return最后一个值。
>>> 2 and 5
5
>>> 2 and 5 and 10
10
如果在布尔上下文中任何值为假,和 returns 第一个假值。
>>> '' and 5
''
>>> 2 and 0 and 5
0
所以代码
return len(args) and max(args)-min(args)
returns 当存在 args 时 max(args)-min(args)
的值,否则 returns len(args)
为 0。
Is this legit/reliable style, or are there any gotchas on this?
我想补充一下这个问题,它不仅合法可靠,而且非常实用。这是一个简单的例子:
>>>example_list = []
>>>print example_list or 'empty list'
empty list
因此,您可以真正发挥自己的优势。为了简洁起见,我是这样看的:
Or
运算符
Python 的 or
运算符 returns 第一个 Truth-y 值,或最后一个值,并停止
And
运算符
Python的and
运算符returns第一个False-y值,或者最后一个值,停止
幕后花絮
在python中,除0外,所有数字都被解释为True
。因此,说:
0 and 10
等同于:
False and True
这显然是False
。因此合乎逻辑的是 returns 0
陷阱
是的,有一些问题。
fn() == fn(3) == fn(4, 4)
首先,如果fn
returns 0
,你无法知道它是在没有任何参数的情况下被调用的,有一个参数还是有多个相等的参数:
>>> fn()
0
>>> fn(3)
0
>>> fn(3, 3, 3)
0
fn
是什么意思?
那么,Python就是动态语言。它没有在任何地方指定 fn
做什么,它的输入应该是什么以及它的输出应该是什么样子。因此,正确命名函数非常重要。同样,参数不必称为 args
。 delta(*numbers)
或 calculate_range(*numbers)
可能更好地描述了该函数应该做什么。
参数错误
最后,逻辑运算符 and
应该可以防止函数在没有任何参数的情况下调用失败。但是,如果某些参数不是数字,它仍然会失败:
>>> fn('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>> fn(1, '2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: '>' not supported between instances of 'str' and 'int'
>>> fn('a', 'b')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
可能的选择
下面是根据"Easier to ask for forgiveness than permission." principle写函数的方法:
def delta(*numbers):
try:
return max(numbers) - min(numbers)
except TypeError:
raise ValueError("delta should only be called with numerical arguments") from None
except ValueError:
raise ValueError("delta should be called with at least one numerical argument") from None
举个例子:
>>> delta()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in delta
ValueError: delta should be called with at least one numerical argument
>>> delta(3)
0
>>> delta('a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 'b')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta(3, 4.5)
1.5
>>> delta(3, 5, 7, 2)
5
如果你真的不想在没有任何参数的情况下调用 delta
时引发异常,你可以 return 一些否则不可能的值(例如 -1
或None
):
>>> def delta(*numbers):
... try:
... return max(numbers) - min(numbers)
... except TypeError:
... raise ValueError("delta should only be called with numerical arguments") from None
... except ValueError:
... return -1 # or None
...
>>>
>>> delta()
-1
通俗易懂,
AND : if first_val is False return first_val else second_value
例如:
1 and 2 # here it will return 2 because 1 is not False
但是,
0 and 2 # will return 0 because first value is 0 i.e False
and =>谁假,谁假。如果两者都为真那么只有它会变为真
或: if first_val is False return second_val else first_value
原因是,如果 first 为假,它会检查 2 是否为真。
例如:
1 or 2 # here it will return 1 because 1 is not False
但是,
0 or 2 # will return 2 because first value is 0 i.e False
or => 假则真。所以如果第一个值是假的,不管 2 值是什么。 所以它 returns 可以是第二个值。
如果有人是真的那么它就会变成真的。如果两者都为假,则它将变为假。