WTFPython
摘录一些wtfpython有趣的例子.
Be careful with chained operations
在 python 中, 针对链式比较操作符, 可以等价认为将每个操作符两侧的表达式两两比较, 再通过 and 进行合并. 下述例子中表达式等价.
False == False in [False] # False
(False == False) and (False in [False])
Keep trying... *
def one_more_func(): # A gotcha!
try:
for i in range(3):
try:
1 / i
except ZeroDivisionError:
# Let's throw it here and handle it outside for loop
raise ZeroDivisionError("A trivial divide by zero error")
finally:
print("Iteration", i)
break
except ZeroDivisionError as e:
print("Zero division error occurred", e)
one_more_func()
# Iteration 0
在 finally中使用 break、continue、return, 会打断并丢弃临时保存的异常信息.
Evaluation time discrepancy
array = [1, 8, 15]
# A typical generator expression
gen = (x for x in array if array.count(x) > 0)
array = [2, 8, 22]
list(gen) # [8]
生成器表达式对 in 子句在声明时计算并保存对象的引用, 对 if 子句在运行时计算并寻找对象.
在复制 gen 对象后, gen 对象本身保存了对原始 array 对象的引用.
在实际遍历gen对象时, if子句中使用到的array对象会在当前上下文寻找, 并且访问到是修改过后的array对象.
array_3 = [1, 2, 3]
array_4 = [10, 20, 30]
gen = (i + j for i in array_3 for j in array_4)
array_3 = [4, 5, 6]
array_4 = [400, 500, 600]
list(gen) # [401, 501, 601, 402, 502, 602, 403, 503, 603]
但是在上述例子中, 生成器gen 只保存了对 array_3的引用, 对array_4是在运行时通过寻找上下文. 对应的解释在pep-289 中可见.
Only the outermost for-expression is evaluated immediately, the other expressions are deferred until the generator is run.
Let's see if you can guess this?
a, b = a[b] = {}, 5
a
# {5: ({...}, 5)}
根据python-assignment-statements里的规则, 赋值语句在计算出最右边的expression_list后, 按从左到右的顺序赋值给左侧的target_list
所以上述例子可以简单的转换为如下
expression_list = {}, 5
a, b = expression_list
a[b] = expression_list
Lossy zip of iterators *
>>> numbers = list(range(7))
>>> numbers
[0, 1, 2, 3, 4, 5, 6]
>>> first_three, remaining = numbers[:3], numbers[3:]
>>> first_three, remaining
([0, 1, 2], [3, 4, 5, 6])
>>> numbers_iter = iter(numbers)
>>> list(zip(numbers_iter, first_three))
[(0, 0), (1, 1), (2, 2)]
# so far so good, let's zip the remaining
>>> list(zip(numbers_iter, remaining))
[(4, 3), (5, 4), (6, 5)]
zip 在 python 的近似实现如下
def zip(*iterables):
sentinel = object()
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
elem = next(it, sentinel)
if elem is sentinel: return
result.append(elem)
yield tuple(result)
zip 在消费numbers_iter中的值 3 后, 在对first_three进行消费时被终止. 此时numbers_iter的 3 相当于被丢弃
Midnight time doesn't exist?
from datetime import datetime
midnight = datetime(2018, 1, 1, 0, 0)
midnight_time = midnight.time()
noon = datetime(2018, 1, 1, 12, 0)
noon_time = noon.time()
if midnight_time:
print("Time at midnight is", midnight_time)
if noon_time:
print("Time at noon is", noon_time)
在 3.5 以前的版本, 如果datetime.time对象表示的是 UTC 下的午夜时间, 对象会被认为是 Flase