any
和all
的功能和简单,却更容易重写你的逻辑片段,使其更加Pythonic。它们接收一个迭代器,其中元素为布尔值。就像名字一样,all只有在全为真的时候返回True,而any只要有一个为真就返回True。
很容易将原来的for循环判断改为简短的语句。例如:1,使用all改写
def validate_responses(responses):
for response in responses:
# Make sure that `id` exists
if 'id' not in response:
return False
# Make sure it is a string
if not isinstance(response['id'], str):
return False
# Make sure it is 20 characters
if len(response['id']) != 20:
return False
# If everything was True so far for every
# response, then we can return True.
return True
使用all:
def validate_responses(responses):
return all(
'id' in response
and isinstance(response['id'], str)
and len(response['id']) == 20
for response in responses
)
例如,使用any改写:
def contains_palindrome(words):
for word in words:
if word == ''.join(reversed(word)):
return True
# Found no palindromes in the end
return False
使用any
def contains_palindrome(words):
return any(word == ''.join(reversed(word)) for word in words)
这4个函数太过常用,以至于放在了内置模块而不是math
模块。效果很简单, abs
返回数字的绝对值。如abs(-1)
的值为1
divmod
返回除法后的(商,余数)。如divmod(7,2)
7除2的结果为(3,1)
商3余1。 pow
计算指数。pow(2,10)
2的10次方。 round
返回舍入后的数字。(结果值会舍入至最接近的 10 的负 ndigits 次幂的倍数;如果与两个倍数同样接近,则选用偶数。)
>>> import math
>>> math.pi
3.141592653589793
>>> round(math.pi)
3
>>> round(math.pi, 4)
3.1416
>>> round(1728, -2)
1700
你可能已经知道用type
检查类型:
def print_stuff(stuff):
if type(stuff) is list:
for item in stuff:
print(item)
else:
print(stuff)
但这存在一个问题,如果我们继承自list
实现一个自定义的类,上面的代码就会失效。
>>> class MyList(list):
... pass
...
>>> items = MyList(['spam', 'eggs', 'steak'])
原因很简单,现在的type
是Mylist
了。这明显违反了继承的原则,子类应该可以被当作父类使用。这时候就可以用isinstance
来检查类型了:
>>> class MyList(list):
... pass
...
>>> items = ['spam', 'eggs', 'steak']
>>> type(items) is list
True
>>> isinstance(items, list)
True # Both of these do the same thing
>>> items = MyList(['spam', 'eggs', 'steak'])
>>> type(items) is list
False # And while `type` doesn't work,
>>> isinstance(items, list)
True # `isinstance` works with subclasses too.
类似的,issubclass
检查一个类是不是另一个类的子类。
>>> issubclass(MyList, list)
True
可以用isinstasnce
修改我们的print_stuff
函数,实现对list
子类的支持。但如果想对其它容器也提供支持,则需要是使用抽象的容器类:from collections.abc import Container
(所有容器类,如list,set都是该类的子类)
from collections.abc import Container
def print_stuff(stuff):
if isinstance(stuff, Container):
for item in stuff:
print(item)
else:
print(stuff)
众所周知,Python被称为“鸭子类型”语言。这意味着Python代码通常倾向于检查对象是否可以满足我们正在寻找的某些行为,而不是关心对象来自的确切类。
Python中的有些东西可以被调用,如函数或类,而有的不行,如整数:
>>> def magic():
... return 42
...
>>> magic() # Works fine
42
>>> class MyClass:
... pass
...
>>> MyClass() # Also works
<__main__.MyClass object at 0x7f2b7b91f0a0>
>>> x = 42
>>> x() # Doesn't work
TypeError: 'int' object is not callable
如何检查一个对象是否可被调用?只需要查看是否实现了__call__
特殊方法。
>>> def is_callable(item):
... return hasattr(item, '__call__')
...
>>> is_callable(list)
True
>>> def function():
... pass
...
>>> is_callable(function)
True
>>> class MyClass:
... pass
...
>>> is_callable(MyClass)
True
>>> is_callable('abcd')
False
我们的is_callable()
几乎和内置的callable
功能一样。
>>> callable(list)
True
>>> callable(42)
False
顺便说一句,这些“特殊方法”是Python的大多数语法和功能的工作原理:
x()
等价于x.__call__()
items[10]
等价于items.__getitem__(10)
a + b
等价于a.__add__(b)
几乎每个python行为都有一个潜在的“特殊方法”,或者它们有时被称为“dunder方法”,定义在背后。更多内容见参考文档: python data modelsorted
可以对传入的可迭代对象进行排序,返回排序后的对象。
>>> items = (3, 4, 1, 2)
>>> sorted(items)
[1, 2, 3, 4]
它有两个参数key
和reverse
。 key
用于确定排序的标准。 reverse
是个布尔值,表示是否反转。
>>> items = [
... {'value': 3},
... {'value': 1},
... {'value': 2},
... ]
>>> sorted(items, key=lambda d: d['value'])
[{'value': 1}, {'value': 2}, {'value': 3}]
>>> names = ['James', 'Kyle', 'Max']
>>> sorted(names, key=len) # Sorts by name length
['Max', 'Kyle', 'James']
list.sort()
和sorted
很像,但只能对列表使用。
reversed
reversed
是一个函数,它接收任何序列类型并返回一个生成器,该生成器以相反的顺序生成值。
>>> items = [1, 2, 3]
>>> x = reversed(items)
>>> x
<list_reverseiterator object at 0x7f1c3ebe07f0>
>>> next(x)
3
>>> next(x)
2
>>> next(x)
1
>>> next(x)
StopIteration # Error: end of generator
>>> for i in reversed(items):
... print(i)
...
3
2
1
>>> list(reversed(items))
[3, 2, 1]