Python 中一些容易忽略的知识点(2)

最近在补 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:返回任意不同种类对象的唯一 ID

    In [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 成功的条件下,才能被调用。一旦有任何异常,就不能被调用。所以,为了确保不触发任何,就会写成第一种形式。

    原文作者:caoqi95
    原文地址: https://www.jianshu.com/p/3e361e783ebe
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞