15

我正在经历 LPTHW,我遇到了一些我无法理解的东西。什么时候你想要你的布尔值andor返回布尔值以外的东西?LPTHW 文本指出,像 python 这样的所有语言都有这种行为。他是指解释型语言还是编译型语言,还是鸭子类型语言和静态类型语言?

我运行了以下代码:

>>> False and 1
False
>>> True and 1
1
>>> 1 and False
False
>>> 1 and True
True
>>> True and 121
121
>>> False or 1
1
>>> False or 112
112
>>> False or "Khadijah"
'Khadijah'
>>> True and 'Khadijah'
'Khadijah'
>>> False or 'b'
'b'
>>> b = (1, 2, "K")
>>> b
(1, 2, 'K')
>>> False or b
(1, 2, 'K')
>>> 

请帮助我了解这里发生了什么。

根据文档:http ://docs.python.org/2/library/stdtypes.html

除非另有说明,否则具有布尔结果的操作和内置函数始终返回0False为假和1或为真。True(重要的例外:布尔运算总是返回它们orand操作数之一。)

根据 LPTHW:http ://learnpythonthehardway.org/book/ex28.html 为什么"test" and "test"返回“测试”或1 and 1返回 1 而不是 True?Python 和许多类似的语言将操作数之一返回到其布尔表达式,而不仅仅是 True 或 False。这意味着,如果您执行 False and 1,您将获得第一个操作数 (False),但如果您执行 True and 1,您将获得第二个操作数 (1)。玩这个。

4

4 回答 4

15

我认为您对文档所说的内容感到困惑。看看这两个文档部分:Truth Value Testing 和 Boolean Operators。引用第一部分的最后一段:

 除非另有说明,否则具有布尔结果的操作和内置函数始终返回 0 或 False 为假和 1 或 为真。True(重要的例外:布尔运算 总是返回它们or 的 and 操作数之一。)

如您所见,您对操作和内置函数是正确的,但请参阅重要异常部分,明确说明布尔运算符将返回其操作数之一

现在,他们能返回什么几乎不取决于操作者的短路逻辑。对于or运算符,它将返回表达式中的第一个值,因为当它找到一个时,整个表达式为真。如果每个操作数都是falseor将返回最后一个操作数,这意味着迭代每个操作数都无法找到真实的操作数。

对于and运算符,如果表达式为真,则返回最后一个操作数,如果表达式为假,则返回第一个假操作数。您可以在 Wikipedia 页面上阅读有关短路评估的更多信息。

您的问题中有很多示例,让我们分析其中的一些示例:

>>> False and 1  # return false (short circuited at first falsey value)
False
>>> True and 1   # return 1 (never short circuited and return the last truthy value)
1
>>> 1 and False  # return false (short circuited at first falsey value, in this case the last operand)
False
>>> 1 and True  # return True (never short circuited and return the last truthy value)
True
>>> True and 121  # return 121 (never short circuited and return the last truthy value)
121
>>> False or 1  # return 1 (since the first operand was falsey, or kept looking for a first truthy value which happened to be the last operator)
1
>>> False or 112  # return 112 for same reason as above
112
>>> False or "Khadijah"  # return "Khadijah" for same reason as above
'Khadijah'
>>> True and 'Khadijah'  # return "Khadijah" because same reason as second example
'Khadijah'

我认为这应该说明问题。为了帮助您进一步理解为什么这很有用,请考虑以下示例:

你有一个随机生成名字的函数

import random

def generate_name():
    return random.choice(['John', 'Carl', 'Tiffany'])

并且您有一个变量,您不知道它是否已经分配了名称,所以不要这样做:

if var is None:
    var = generate_name()

你可以做oneliner:

var = var or generate_name()

由于None是一个假值,or将继续其搜索并评估第二个操作数,即调用最终返回生成名称的函数。这是一个非常愚蠢的例子,我见过这种风格的更好用法(虽然不是在 Python 中)。我现在想不出更好的例子。你也可以看看这个问题,关于这个话题有非常有用的答案:Python是否支持短路?

最后但同样重要的是,这与静态类型、鸭子类型、动态、解释、编译等任何语言无关。它只是一种语言功能,可能会派上用场,而且很常见,因为我能想到的几乎所有编程语言都提供此功能。

希望这可以帮助!

于 2014-03-23T23:43:48.637 回答
3

这与 Python 中实现短路效应的方式有关。

使用and(remember True and X = X),正确表达式的结果被压入堆栈,如果为 false,则立即弹出,否则弹出第二个表达式:

>>> import dis
>>> 
>>> dis.dis(lambda : True and 0)
  1           0 LOAD_CONST               2 (True)
              3 JUMP_IF_FALSE_OR_POP     9
              6 LOAD_CONST               1 (0)
        >>    9 RETURN_VALUE
>>>
>>> True and 0
0
>>> 0 and True
0
>>>

微笑到:

def exec_and(obj1, obj2):
    if bool(obj1) != False:
        return obj2
    return obj1

使用or,如果第一个表达式为真,它会立即弹出。如果不是,则弹出第二个表达式,现在结果实际上取决于第二个。

>>> dis.dis(lambda : 0 or False)
  1           0 LOAD_CONST               1 (0)
              3 JUMP_IF_TRUE_OR_POP      9
              6 LOAD_CONST               2 (False)
        >>    9 RETURN_VALUE
>>>
>>> True or 0
True
>>> 1 or False
1
>>> False or 1
1
>>>

微笑到:

def exec_or(obj1, obj2):
    if bool(obj1) != True:
        return obj2
    return obj1
于 2014-03-24T00:12:11.017 回答
3

为了支持如下的习语,人们想要andandor评估一个操作数(而不是总是评估Trueor ):False

def foo(self):
    # currentfoo might be None, in which case return the default
    return self.currentfoo or self.defaultfoo()

def foobar(self):
    # foo() might return None, in which case return None
    foo = self.foo()
    return foo and foo.bar()

你当然可以质疑这些成语的价值,尤其是在你不习惯它们的时候。总是可以用显式的if.

作为反对他们的观点,他们怀疑是否有可能并有意考虑全部虚假值,或者只是评论中提到的一个(不允许其他虚假值)。但是,对于使用可能不是Trueor的值的真实性的代码来说,这通常是正确的False。它偶尔但很少导致误解。

于 2014-03-24T00:07:03.743 回答
1

考虑以下用例:

element = dict.has_key('foo') and dict['foo']

如果存在则设置element为,否则设置为。这在编写函数以返回值或失败时很有用。dict['foo']FalseFalse

另一个用例or

print element or 'Not found!'

将这两行放在一起会打印出来(dict['foo']如果存在),否则会打印'Not found!'str()否则我会使用or失败时element0(或False),因为这被认为是错误的,因为我们只打印它并不重要)

这可以简化为

print dict.has_key('foo') and str(dict['foo']) or 'Not found!'

并且在功能上等同于:

if dict.has_key('foo'):
    print dict['foo']
else:
    print 'Not found!'
于 2014-05-20T23:25:07.957 回答