abs
, divmod
, pow
and round
:数学基础
这四个数学函数在编程中非常常见,它们被直接放在随时可用的内置函数中,而不是放在 math
模块中。
它们非常简单:
abs
返回一个数字的绝对值,例如:
>>> abs(42)
42
>>> abs(-3.14)
3.14
>>> abs(3-4j)
5.0
divmod
返回除法运算后的商和余数:
>>> divmod(7, 2)
(3, 1)
>>> quotient, remainder = divmod(5327, 100)
>>> quotient
53
>>> remainder
27
pow
返回一个值的指数运算结果:
>>> pow(100, 3)
1000000
>>> pow(2, 10)
1024
round
按照四舍五入原则返回数字:
>>> import math
>>> math.pi
3.141592653589793
>>> round(math.pi)
3
>>> round(math.pi, 4)
3.1416
>>> round(1728, -2)
1700
isinstance
and issubclass
:类型检查type
内置函数可以用于对象的类型检查,就像这样:
def print_stuff(stuff):
if type(stuff) is list:
for item in stuff:
print(item)
else:
print(stuff)
这个函数中检验参数对象是否是 list
类型。
>>> print_stuff('foo')
foo
>>> print_stuff(123)
123
>>> print_stuff(['spam', 'eggs', 'steak'])
spam
eggs
steak
目前看起来,它能运行,但是,实际上存在一些问题。这里有一个例子:
>>> class MyList(list):
... pass
...
>>> items = MyList(['spam', 'eggs', 'steak'])
>>> items
['spam', 'eggs', 'steak']
>>> print_stuff(items)
['spam', 'eggs', 'steak']
当然,items
仍然是一个列表,但是 print_stuff
函数不再识别它了。原因很简单,因为 type(items)
的返回值是 MyList
,不是 list
。
也可以说,函数 type
没有考虑继承问题,如果改用 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
检查一个类是否是另一个类的子类。isinstance
的第一个参数是一个对象,但 issubclass
的第一个参数是另一个类:
>>> issubclass(MyList, list)
True
所以,应该将 print_stuff
函数中的 type
替换为 isinstance
,优化之后,继续测试:
>>> items = ('spam', 'eggs', 'steak')
>>> print_stuff(items)
('spam', 'eggs', 'steak')
如果传入的实参不是列表,则不能输出实参对象类型。对此的一种解决方法就是通过多分支的 if
语句实现。如果只是内置对象还好办一些,尽管如此,分支太多,代码也是丑陋的。
为此,Python 中有一个含有各种内置类型的“类”,可以用它们来测试类的某些“行为”,而不是测试类本身。在我们的例子中,行为是作为其他对象的容器,称之为 Container
:
>>> from collections.abc import Container
>>> items = ('spam', 'eggs', 'steak')
>>> isinstance(items, tuple)
True
>>> isinstance(items, list)
False
>>> isinstance(items, Container)
True # This works!
每个容器对象类型都会在 Container
基类的检查中返回 True
, issubclass
也行之有效:
>>> from collections.abc import Container
>>> issubclass(list, Container)
True
>>> issubclass(tuple, Container)
True
>>> issubclass(set, Container)
True
>>> issubclass(dict, Container)
True
把它添加到代码中,就变成:
from collections.abc import Container
def print_stuff(stuff):
if isinstance(stuff, Container):
for item in stuff:
print(item)
else:
print(stuff)
最后要特别声明:在实际的编程中,不提倡对参数类型进行检查。具体原因,请参阅《Python 大学实用教程》(电子工业出版社)中对“多态”的讲解内容。