更新于 

模块、I/O、异常、面向对象

模块

import语句

python的搜索路径

import语句执行之后,
python解释器会按照搜索路径来搜索对应模块,
搜索路径由一系列目录名组成

1
2
import sys
print(sys.path)

[
‘D:\CS_Demo\后端\Python Demo\2023_python_demo’,
‘D:\CS_Demo\后端\Python Demo\2023_python_demo’,
‘D:\PyCharm\PyCharm 2020.3.3\plugins\python\helpers\pycharm_display’,
‘D:\python\python39.zip’,
‘D:\python\DLLs’,
‘D:\python\lib’,
‘D:\python’,
‘D:\python\lib\site-packages’,
‘D:\PyCharm\PyCharm 2020.3.3\plugins\python\helpers\pycharm_matplotlib_backend’
]

搜索路径是何时被确定的?

答: 在Python编译或安装的时候被确定的
也可以通过定义环境变量的方式来确定搜索路径

因此,可以通过手动添加sys.path修改搜索路径

__name__

当A模块引用B模块内变量或方法时,
B模块中会运行的代码不仅仅只有被引用的部分,
事实上,B模块的整个主程序都将运行

如何分辨程序是自身执行还是引用执行呢?

答: name

1
2
3
4
if __name__ == '__main__':
print('自身运行')
else:
print('引用运行')
调用模块内的所有可引用方法
  • dir(model) 获取模块内定义的所有名称的字符串列表
  • getattr(obj, str) 根据字符串名称str获取obj中的某个属性obj.str
1
2
for fun in [i for i in dir(model) if not i.startswith('__')]:
getattr(model, fun)()

目录只有在包含**init.py**文件时才会被认作是一个包:

root_package
init.py
package_A
init.py
AAA.py
BBB.py

package_B
init.py
CCC.py
DDD.py

使用点模块名称获取某个包内的模块时,如:A.B.C,
访问到的每一层包结构都会调用其中的**init.py**

I/O

output

字符串转换
  • str 返回用户易读的表达形式
    1
    2
    3
    4
    5
    6
    s = 'hello\nworld'
    '''
    hello
    world
    '''
    print(str(s))
  • repr 返回解释器易读的表达形式
    1
    2
    s = 'hello\nworld'
    print(repr(s)) # 'hello\nworld'
字符串格式化
固定长度

以下三个方法全是用于创建指定len长度字符串的,
但是在源字符串长度小于目标长度时,
填充的方法不同:

  • rjust(len)
    • 向字符串左侧填充空格
  • ljust(len)
    • 向字符串右侧填充空格
  • center(len)
    • 像字符串两侧填充空格
格式化 format

仅占位 {}

1
"index1:{} index2:{} index3:{}".format("index1","index2","index3")

指定索引 {index}

1
print("index2:{1} index3:{2} index1:{0}".format(1, 2, 3))

指定关键字 {keyword}

1
print('{key2} {key1} {key3}'.format(key1='dog',key2='you',key3='!!!'))

指定索引和格式 {index:format}

1
2
print("{0:2d} {1:3d} {2:4d}".format(10, 10**2, 10**3))
print("Math.pi = {0:0.2f}".format(math.pi))

格式化之前进行附加操作 {!a|!s|!r}

  • !a ascii()
  • !s str()
  • !r repr()
1
print('{!a} {!s} {!r}'.format('index1', 'index2', 'index3'))

传入字典

1
2
team = { "John":"Doctor", "Nancy":"Fighter" }
print("John is our {0[John]:10}, and Nancy is our {0[Nancy]:10}".format(team))

使用参数解构的方式同样也能实现传入字典的功能

1
2
3
4
5
team = {
"John":"Doctor",
"Nancy":"Fighter"
}
print("John is our {John:10}, and Nancy is our {Nancy:10}".format(**team))
zfill() 字符串左侧填充0
1
print('0.1'.zfill(5))  # 000.1

文件

读写文件
1
open(filename, mode)

mode有如下几种选项:

  • r 默认值,只读
  • w 写
  • a 追加
  • r+ 读写
文件操作方法
  • read(size) 读取size长度的字符串/字节对象
  • readline() 读取一行
  • readlines() 读取所有行
  • next() 读取文件下一行
  • truncate([size]) 截取文件
  • write(string) 写入文件
    • string 需要写的内容
    • return 写入的字符串长度
  • writelines(sequence) 写入一个序列字符串列表
  • tell() 文件对象所处索引位置
  • seek(offset, from_what) 移动文件对象索引位置
    • from_what = 0 从首行首字开始移动
    • from_what = 1 从当前位置往后移动
    • from_what = 2 从结尾往前移动-offset个字符
  • close() 关闭释放文件资源
  • flush() 刷新文件内部缓冲
  • fileno() 返回整型文件描述符
    • 用于底层操作
  • isatty() 文件是否连接到一个终端设备

一个根据目录文件引入指定模块的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import importlib
require = open('static/require.txt', 'r')

while True:
try:
model_name = require.readline()
if not model_name:
print('文件读取结束')
break
model_name = str(model_name).replace('\n', '')
model_path = f"static.{model_name}"
globals()[model_name] = importlib.import_module(model_path)
except:
print('文件读取错误')

require.close()

pickle模块

pickle功能
  • 序列化

    • 程序对象 → 文件
    • 程序对象存储到文件
      1
      pickle.dump(obj, file, [,protocol])
  • 反序列化

    • 文件 → 程序对象
    • 使用文件内容创建程序对象
      1
      x = pickle.load(file)

序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pickle
data1 = {
'a':[1, 2.0, 3, 4+6j],
'b':{'string', u'Unicode string'},
'c':None
}
selfref_list = [1, 2, 3]
selfref_list.append(selfref_list)
output = open('static/data.pk1', 'wb')

pickle.dump(data1, output)

pickle.dump(selfref_list, output, -1)
output.close()

反序列化

1
2
3
4
5
6
7
8
9
import pprint, pickle
pkl_file = open('static/data.pk1', 'rb')

data1 = pickle.load(pkl_file)
pprint.pprint(data1)
data2 = pickle.load(pkl_file)
pprint.pprint(data2)

pkl_file.close()

异常

异常捕获
1
2
3
4
try:
....
except 错误类型:
.....

不写就是捕获全部错误:

1
except:

一次捕获多个错误:

1
except (TypeError, NameError, ...):

捕获同时生成错误信息:

1
except TypeError as error:

分类捕获:

1
2
3
4
5
6
except TypeError:
pass
except NameError:
pass
except:
pass

try-except-else:

1
2
3
4
5
6
try:
...
except:
...
else:
# 只有当try下的代码没有异常抛出时才会运行
异常抛出
1
raise Error
1
2
3
4
5
6
7
'''
Traceback (most recent call last):
File "XXXXXXXXXXXX", line 1, in <module>
raise NameError('its not a error, i just like my console be red')
NameError: its not a error, i just like my console be red
'''
raise NameError('its not a error, i just like my console be red')
自定义异常

异常类需要继承自Exception类

1
2
3
4
5
6
7
8
9
10
11
class MyError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)

try:
raise MyError('must be a masochism who wrote this error for himself')
except MyError as e:
# must be a masochism who wrote this error for himself
print(e.value)

当某个模块可能抛出多种异常错误时,
一般为这个包建立一个基础异常类
基于此类创建不同的子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Error(Exception):
def __str__(self):
return repr(self.message)

class InputError(Error):
def __init__(self, expression, message):
self.expression = expression
self.message = message

class TransitionError(Error):
def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message
清理行为
1
2
3
4
5
6
7
8
9
try:
print('执行入口')
raise NameError('name error')
except NameError:
print('有异常时执行')
else:
print('没有异常时执行')
finally:
print("有没有异常都执行")
预定义的清理行为
1
2
3
f = open('xxx','wb')
# 开始进行文件操作
f.close()

当上面文件操作过程中出现错误时,程序会直接退出,无法保证close方法的执行

标准清理行为

python中一些对象定义了标准的清理行为,
一旦系统不需要它,标准清理行为就会执行

如何保证标准清理行为被正确调用?
答: 使用关键词with语句
with语句保证定义了标准清理方法的对象在使用完后指定会正确执行清理方法

1
2
with open('XXX') as f:
# 其他操作

面向对象

类的方法

类方法的第一个参数必须是self
self就是实例自身

init

类在实例化操作时会自动调**init**方法进行初始化操作

def __方法名(params):

只能在类内调用的方法

重写专有方法能实现运算符重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Dog:
def __init__(self):
self.count = 1

# 加法运算符重载
def __add__(self, other):
self.count+=other.count
print(f'dog number: {self.count}')
return self

dog = Dog()
dog += Dog() # dog number: 2
dog += Dog() # dog number: 3
dog += Dog() # dog number: 4
多继承
1
2
class DerivedClassName(Base1, Base2, ...):
pass

当多继承的类调用一个属性或方法时,
会按照如下顺序对属性进行查找:

  • 子类自身中查找
  • 继承参数从左到右进行查找