Python 支持以下基本比较运算符:
| 运算符 | 运算 | 说明 |
|---|---|---|
> |
“大于” | 若a的值严格大于b,则a > b为True
|
< |
“小于” | 若a的值严格小于b,则a < b为True
|
== |
“等于” | 若a的值严格等于b,则a == b为True
|
>= |
“大于或等于” | 若a的值大于b,或a的值等于b,则a >= b为True
|
<= |
“小于或等于” | 若a的值小于b,或a的值等于b,则a <= b为True
|
!= |
“不等于” | 若a == b为False,则a != b为True
|
is |
“同一性” | 当且仅当a和b是同一个对象时,a is b为True
|
is not |
“否定的同一性” | 若a和b不是同一个对象,则a is not b为True
|
in |
“包含测试” | 若a是b的成员、子集或元素,则a in b为True
|
not in |
“否定的包含测试” | 若a不是b的成员、子集或元素,则a not in b为True
|
它们的优先级都相同(高于布尔运算,但低于算术运算或位运算)。
类型不同的对象(数字类型除外)默认永远不会比较为相等。
class的非同一实例也不会比较为相等,除非该class定义了特殊的富比较方法,用来自定义默认的object比较行为。
通过rich comparisons进行自定义将在后续练习中介绍。
想了解这个主题的(更多)细节,请参阅 Python 文档中的值比较。
数字类型(大部分情况下)是这条类型匹配规则的例外。
只要类型可以为比较而隐式转换,integer可以被认为等于float(或者octal等于hexadecimal)。
对于 Python 标准库中的其他数字类型(复数、十进制数、分数),比较运算符只在“讲得通”的地方定义(也就是隐式转换不会改变结果的地方),但如果底层对象无法为了比较而准确转换,就会抛出TypeError。
想进一步了解 Python 进行数字转换的规则,请参阅 Python 文档中的算术转换。
>>> import fractions
# A string cannot be converted to an int.
>>> 17 == '17'
False
# An int can be converted to float for comparison.
>>> 17 == 17.0
True
# The fraction 6/3 can be converted to the int 2
# The int 2 can be converted to 0b10 in binary.
>>> 6/3 == 0b10
True
# An int can be converted to a complex number with a 0 imaginary part.
>>> 17 == complex(17)
True
# The fraction 2/5 can be converted to the float 0.4
>>> 0.4 == 2/5
True
>>> complex(2/5, 1/2) == complex(0.4, 0.5)
True
将数字与NaN(非数字)类型进行任何有序比较,结果都是False。
Python 对NaN的定义有一个令人困惑的副作用:NaN永远不会比较为等于NaN。
>>> x = float('NaN')
>>> 3 < x
False
>>> x < 3
False
# NaN never compares equal to NaN
>>> x == x
False
与数字不同,字符串(str)是按字典序比较的,依据的是它们各自的 Unicode 码位(也就是把str中每个码位传给内置函数ord()所得到的结果,该函数返回一个int)。
如果两个字符串中的所有码位都相同,并且顺序也一致,那么这两个字符串就被认为是相等的。
这种比较是“逐对”进行的:第一个对第一个,第二个对第二个,依此类推。
在 Python 3.x 中,str和bytes不能直接强制转换或比较。
>>> 'Python' > 'Rust'
False
>>> 'Python' > 'JavaScript'
True
# Examples with Mandarin.
# hello < goodbye
>>> '你好' < '再见'
True
# ord() of first characters
>>> ord('你'), ord('再')
(20320, 20877)
# ord() of second characters
>>> ord('好'), ord('见')
(22909, 35265)
# And with Korean words.
# Pretty < beautiful.
>>> '예쁜' < '아름다운'
False
>>> ord('예'), ord('아')
(50696, 50500)
比较运算符可以任意串联,也就是说可以用任意长度、任意组合来使用。
请注意,表达式的求值是从left到right进行的。
举例来说,x < y <= z等价于x < y and y <= z,区别在于y只求值一次。
这两种情况下,一旦发现x < y为False,z就完全不求值。
这通常被称为short-circuit evaluation:如果表达式的真值已经确定,求值就会停止。
Python 中的各种布尔运算符、函数以及比较链都支持Short circuiting。
与包括C、C++、C#和Java在内的许多其他编程语言不同,Python 中像a < b < c这样的链式表达式具有传统的数学解释和优先级。
>>> x = 2
>>> y = 5
>>> z = 10
>>> x < y < z
True
>>> x < y > z
False
>>> x > y < z
False
运算符is和is not测试的是对象的同一性,而不是对象的值。
对象的同一性在创建之后永远不会改变,可以通过id()函数获取。
当且仅当id(<apple>) == id(<orange>)时,<apple> is <orange>的求值结果为True。
<apple> is not <orange>则得出相反的结果。
由于None和NotImplemented都是单例,比较它们时应该始终使用is和is not。
关于这一惯例的更多细节,请参阅 Python 参考文档中的值比较和PEP8。
>>> my_fav_numbers = [1, 2, 3]
>>> your_fav_numbers = my_fav_numbers
>>> my_fav_numbers is your_fav_numbers
True
# The returned id will differ by system and python version.
>>> id(my_fav_numbers)
4517478208
# your_fav_numbers is only an alias pointing to the original my_fav_numbers object.
# Assigning a new name does not create a new object.
>>> id(your_fav_numbers)
4517478208
>>> my_fav_numbers is not your_fav_numbers
False
>>> my_fav_numbers is not None
True
>>> my_fav_numbers is NotImplemented
False
运算符in和not in测试的是成员关系。
如果<fish>是<soup>的成员(也就是<fish>是<soup>的子集,或者包含在<soup>中),<fish> in <soup>的求值结果为True,否则为False。
<fish> not in <soup>返回的是否定结果,也就是<fish> in <soup>的相反结果。
对于字符串和 bytes 类型,当且仅当<name>是<fullname>的子串时,<name> in <fullname>为True。
# A set of lucky numbers.
>>> lucky_numbers = {11, 22, 33}
>>> 22 in lucky_numbers
True
>>> 44 in lucky_numbers
False
# A dictionary of employee information.
>>> employee = {'name': 'John Doe',
'id': 67826, 'age': 33,
'title': 'ceo'}
# Checking for the membership of certain keys.
>>> 'age' in employee
True
>>> 33 in employee
False
>>> 'lastname' not in employee
True
# Checking for substring membership
>>> name = 'Super Batman'
>>> 'Bat' in name
True
>>> 'Batwoman' in name
False
在本练习中,你将实现二十一点的一些规则,比如游戏的玩法和计分方式。
注意:在本练习中,A 表示 ace,J 表示 jack,Q 表示 queen,K 表示 king。
大小王都被去掉。
这里假定使用的是一副标准的 52 张法式扑克牌,不过大多数玩法会把好几副牌洗在一起使用。
在二十一点里,A 算 1 点还是 11 点,由每位玩家自己决定(稍后会详细说明)。
人头牌(J、Q、K)记 10 点,其他牌则按其“牌面点数”(数值)计分。
定义一个 value_of_card(<card>) 函数,参数为 card。
函数应返回传入的牌面字符串的_数值_。
由于 A 可以取多个值(1 或 11),这个函数暂时先把 A 的点数固定为 1。
稍后,你会实现一个函数,在已知现有手牌的情况下判断 A 的点数。
>>> value_of_card('K')
10
>>> value_of_card('4')
4
>>> value_of_card('A')
1
定义一个 higher_card(<card_one>, <card_two>) 函数,参数为 card_one 和 card_two。
就计分而言,J、Q 或 K 的点数都是 10。
函数应返回到计分时点数更高的那张牌。
如果两张牌点数相同,就把两张都返回。
在 return 语句里用逗号,就可以同时返回两张牌:
# Using a comma in a return creates a Tuple. Tuples will be covered in a later exercise.
>>> def returning_two_values(value_one, value_two):
return value_one, value_two
>>> returning_two_values('K', '3')
('K', '3')
A 可以取多个值,所以这个任务里我们把A的点数固定为 1。
>>> higher_card('K', '10')
('K', '10')
>>> higher_card('4', '6')
'6'
>>> higher_card('K', 'A')
'K'
如前所述,A 可以算 1 点,也可以_算 11 点。 玩家会尽量接近 21 点,但不能_超过 21 点(超过就叫“爆牌”)。
定义一个 value_of_ace(<card_one>, <card_two>) 函数,参数 card_one 和 card_two 是在拿到 A _之前_手里已有的一组牌。
你的函数要判断即将拿到的这张 A 算 1 点还是 11 点,并返回该值。
记住:加上这张 A 后,手牌的点数要尽可能高,但_不能_超过 21。
提示:如果手里已经有 A,那么即将拿到的这张 A 只能算 1 点。
>>> value_of_ace('6', 'K')
1
>>> value_of_ace('7', '3')
11
如果玩家最初拿到的两张牌是一张 A(A)和一张十点牌(10、K、Q 或 J),那么他的点数就是 21。
这就叫二十一点手牌。
定义一个 is_blackjack(<card_one>, <card_two>) 函数,参数 card_one 和 card_two 是一组牌。
判断这两张牌是不是二十一点,是就返回布尔值 True,否则返回 False。
注意:点数的_计算_可以有很多种做法。 但如果可以的话,我们希望你去检查手牌**中**(或者某个特定位置上)是否有一张 A 和一张十点牌,而不是去_累加_手牌的点数。
>>> is_blackjack('A', 'K')
True
>>> is_blackjack('10', '9')
False
如果手牌的前两张点数相同(比如两张 6,或者一张 Q 和一张 K),玩家可以选择把它们当成两手牌来打。
这就叫“分牌”。
定义一个 can_split_pairs(<card_one>, <card_two>) 函数,参数 card_one 和 card_two 是一组牌。
判断这手两张牌能否拆分成两对。
如果可以分牌,返回布尔值 True,否则返回 False
>>> can_split_pairs('Q', 'K')
True
>>> can_split_pairs('10', 'A')
False
当最初发到的两张牌总共 9、10 或 11 点时,玩家可以再下一次和原注相同的赌注。 这就叫“加倍”。
定义一个 can_double_down(<card_one>, <card_two>) 函数,参数 card_one 和 card_two 是一组牌。
判断这手两张牌能否“加倍”,可以就返回布尔值 True,否则返回 False。
>>> can_double_down('A', '9')
True
>>> can_double_down('10', '2')
False