最近在补 Python 进阶的内容,学习资源来自:Python 进阶,是《Intermediate Python》的中译本。这里面的一些内容,对于我来说是比较容易忽略的知识点。
对象自省(Inrospection)
在 Python 中,对象自省也是其强项之一。自省指的是在运行时判断一个对象的类型的能力。下面可以看看 Python 中一些常用的自省能力。
dir
:返回一个列表。用来查看对象所拥有的属性和方法。In [6]: a = 1 In [7]: dir(a) Out[7]: ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', .....]
type
:返回一个对象的类型。In [9]: a = "hello" In [10]: type(a) Out[10]: str
id
:返回任意不同种类对象的唯一 IDIn [11]: name = "caoqi95" In [12]: id(name) Out[12]: 1875152854352 In [13]: age = 23 In [14]: id(age) Out[14]: 1572630272
Python 中还有很多其他方法用于自省。有需要的话,可以看看文档说明。
解析式(Comprehension)
解析式是 Python 独有的特性。其是可以从一个数据结构构建另一个新的数据结构序列的结构体。一共有 3 种类型,包括列表,字典和集合解析式。
列表解析式
列表解析式很常见,如下所示:multiples = [i for i in range(30) if i % 3 is 0]
其可以简化
for
循环的代码:squared = [] for i in range(10): squared.append(i) # 简化 squared = [i**2 for i in range(10)]
字典解析式
字典解析式最常用的就是快速兑换字典的键和值:{v:k for k, v in some_dict.item()}
集合解析式
它们跟列表推导式也是类似的。 唯一的区别在于它们使用大括号{}
。 如下所示:squared = {x**2 for x in [1, 1, 2]}
异常处理
通常在一些代码中见到的都是单个错误的处理,如下所示:
try:
file = open('test.txt', 'rb')
except IOError as e:
print('An IOError occurred. {}'.format(e.args[-1]))
其实,还可以同时处理多个错误,下面有 3 种方法可以用来处理多个异常。
- 把所有可能发生的异常都写在一个元祖里:
try: file = open('test.txt', 'rb') except (IOError, EOFError) as e: print("An error occurred. {}".format(e.args[-1]))
- 每个异常都起一个
except
:try: file = open('test.txt', 'rb') except EOFError as e: print("An EOF error occurred.") raise e except IOError as e: print("An error occurred.") raise e
- 捕捉所有异常:
try: file = open('test.txt', 'rb') except Exception: raise
对于异常处理,除了 try:.... except:....
语句外,还有其他语句。
-
finally
从句try: file = open('test.txt', 'rb') except IOError as e: print('An IOError occurred. {}'.format(e.args[-1])) finally: print("This would be printed whether or not an exception occurred!")
finally
从句后面的代码不管异常是否触发,都将会被执行。通常可以用来处理一些善后工作。 -
try/else
语句try: print('I am sure no exception is going to occur!') except Exception: print('exception') else: # 这里的代码只会在 try 语句里没有触发异常时运行, # 但是这里的异常将 *不会* 被捕获 print('This would only run if no exception occurs. And an error here ' 'would NOT be caught.') finally: print('This would be printed in every case.')
如果想在没有触发异常的时候执行一些代码,可以很轻松地通过一个
else
从句来实现。其中else
从句只会在没有异常的情况下执行,而且它会在finally
语句之前执行。
for – else 结构
我们一般见到的 for
循环会如下所示,但其实它还会有 else
结构。
for i in range(10):
print(i)
下面来看看 for
循环的 else
结构:
for i in range(2, 10):
if i > 10: # 此条件在整个循环范围外,因此不会 break
break
else:
print('Hello World')
for i in range(2, 10):
if i > 5: # 会 break,未完全执行完整个循环
break
else:
print('Hello World')
可以看出,在 for
循环中,如果没有从任何一个 break
中退出,则会执行和 for
对应的 else
。即 else
后面的代码只会在循环正常结束的时候执行。
建议避免在生产环境中使用
for...else
结构,因为其本身的歧义以及和try....else/finally
完全相反的运作方式,会影响可阅读性。
open 函数
我们都是到 open
函数的用法如下:
with open('file_name', 'r+') as f:
data = f.read()
其实可以写成下面的形式:
f = open('file_name', 'r+')
data = f.read()
f.close()
为什么都使用第一种形式,而不是第二种形式?这是有原因的。首先,open
函数返回的是一个文件句柄,从操作系统托付给 Python 程序。在处理完成之后,需要归还这个文件句柄,这样才不会超过使用句柄的次数上限。其次,close()
之后在文件 read 成功的条件下,才能被调用。一旦有任何异常,就不能被调用。所以,为了确保不触发任何,就会写成第一种形式。