模块与调试#

1. 基本操作#

1.1. 导入#

模块就是程序,任何以 .py 为扩展名的文件均是 python 模块,都可用 import 导入

# 方法 1
import time as t
t.sleep(1)
# 方法 2 (导入整个包,可直接使用包中的模块)
from time import sleep
sleep(1)
# 重新导入
import imp
imp.reload(模块名)

1.2. 查看路径和帮助#

# 方法 1
import os
os.__file__
#方法 2
import sys
sys.path

2. 模块的制作#

2.1. 头文件#

import 会执行对象的全部代码,为使其中的部分代码在导入时不被调用,必须加入头文件。

当模块调用自身的name方法,执行的是字符串 '__main__',当调用其他模块的 __name__,执行的是字符串’调用模块名’。添加 if __name__=='__main__': 可使下面的代码只有在调用时执行,被导入时不执行。

# 模块末尾往往会添加
def main():
  pass
if __name__=='__main__':
  main()

2.2. 起始文件#

  1. 创建 1 个存放相关模块的文件夹,文件夹的名字即包(Package)的名字

  2. 在文件夹中创建 1 个起始文件 __init__.py,内容可为空,也会写入 __all__ 方法。

  3. __all__=[] 中的元素,可被 from xxx import * 导入,其中的元素可是’类名’,也可是’方法名’,但均是 str

# setup.py 的编写
from setuptools import setup, find_packages

setup(name='package',
      description='',
      version='',
      author='',
      py_modules=['package.module'])

find_packages()

# __init__.py
__version__ = ''

3. 异常#

3.1. 异常的捕获#

在编写函数的时候,需要处理错误输入,并给出错误信息,这个时候需要编写异常函数。

  • 有异常处理的函数,在异常处理后会继续执行

  • 没有异常处理的函数,将停止执行后面的代码,并将异常传递给外层函数。

异常类型

OSError

文件打开异常

TypeError

类型异常

NameError

名称异常

FileNotFoundError

未找到文件

Exception

所有异常的父类

在编写实用函数的时候,Python 有一个吸引人的地方,就是赋予 None 的返回值以特殊意义。在某些情况下,这似乎是有道理的。例如,如说我想要一个帮助函数,用一个数字除以另一个数字。在除以 0 的情况下,返回 None 似乎很自然,因为结果是未定义的。返回 None 表示特殊含义的函数容易出错,因为在条件表达式中,None 和其他值(如零、空字符串)都会被评价为 False 。故使用异常的方法更为合理。

def careful_divide(a, b):

    try:
        return a / b
    except ZeroDivisionError as e:
        raise ValueError('Invalid inputs')


x, y = 5, 2

try:
    result = careful_divide(x, y)
except ValueError:
    print('Invalid inputs')
else:
    print(f'Result is {result:.1f}')

3.2. 异常的自定义#

raise 语句可用于来引发异常,若后面没有关键字,则引发相应异常。异常类的名字可自定义,但必须继承自 ErrorException

class InputException(Exception):

    def __init__(self, length, atleast):
        super().__init__()
        self.length = length
        self.atleast = atleast


def main():
    try:
        s = input('输入:')
        if len(s) < 3:
            raise InputException(len(s), 3)
    except InputException as result:
        print(f'输入的长度是{result.length},长度至少应是{result.atleast}')
    else:
        print('没有异常发生')


main()

3.3. 迭代异常#

Python 在生成器中提供了 throw() 方法来处理频繁使用 yield 部分的异常,但这种方法会破坏可读性。推荐构建类,并使用 __iter__() 方法来处理还有循环和 yield 的部分。

class Timer:

    def __init__(self, period):
        self.current = period
        self.period = period

    def reset(self):
        self.current = self.period

    def __iter__(self):
        while self.current:
            self.current -= 1
            yield self.current

4. 消除 if#

4.1. 嵌套 if#

在函数内使用 returnraise 等语句提前在分支内结束函数。

def buy_fruit(nerd, store):
    """去水果店买苹果

    - 先得看看店是不是在营业
    - 若有苹果的话,就买 1 个
    - 若钱不够,就回家取钱再来
    """
    if store.is_open():
        if store.has_stocks("apple"):
            if nerd.can_afford(store.price("apple", amount=1)):
                nerd.buy(store, "apple", amount=1)
                return
            else:
                nerd.go_home_and_get_money()
                return buy_fruit(nerd, store)
        else:
            raise MadAtNoFruit("no apple in store!")
    else:
        raise MadAtNoFruit("store is closed!")

改写成

def buy_fruit(nerd, store):
    if not store.is_open():
        raise MadAtNoFruit("store is closed!")

    if not store.has_stocks("apple"):
        raise MadAtNoFruit("no apple in store!")

    if nerd.can_afford(store.price("apple", amount=1)):
        nerd.buy(store, "apple", amount=1)
        return
    else:
        nerd.go_home_and_get_money()
        return buy_fruit(nerd, store)

4.2. 重叠 if#

# 对于新用户,创建新的用户资料,否则更新旧资料
if user.no_profile_exists:
    create_user_profile(
        username=user.username,
        email=user.email,
        age=user.age,
        address=user.address,
        # 对于新建用户,将用户的积分置为 0
        points=0,
        created=now(),
    )
else:
    update_user_profile(
        username=user.username,
        email=user.email,
        age=user.age,
        address=user.address,
        updated=now(),
    )

改写成

if user.no_profile_exists:
    profile_func = create_user_profile
    extra_args = {'points': 0, 'created': now()}
else:
    profile_func = update_user_profile
    extra_args = {'updated': now()}

profile_func(
    username=user.username,
    email=user.email,
    age=user.age,
    address=user.address,
    **extra_args
)

5. 命令行#

5.1. 查询#

  • 上个变量返回值: _

  • 包路径: python3 -m site

5.2. 查看#

  • JSON: python -m json.tool [file].json

  • 服务器: python3 -m http.server 8888

5.3. 文件处理#

  • 创建 tar: python3 -m tarfile -c [file].tar [folder]

  • 解压 tar: python3 -m tarfile -e [file].tar [new_file]

  • 创建 gz: python3 -m gzip [folder]

  • 解压 gz: python3 -m gzip -d [file].gz

  • 创建 zip: python3 -m zipfile -c [file].zip [folder]

  • 解压 zip: python3 -m zipfile -e [file].zip [file]