三、Python速览
- 原始字符串
print(r'C:\some\name')
原始字符串还有一个微妙的限制:一个原始字符串不能以奇数个 \ 字符结束
- 以下切片操作会返回列表的浅拷贝
squares[:]
- append() 方法
可以在列表末尾添加新元素
四、其他流程控制工具
- 循环
for i in range(5):
print(i)
a = ['Mary', 'had', 'a', 'little', 'lamb']
for i in range(len(a)):
print(i, a[i])
pass 语句
match 语句
match status:
case 400:
return "Bad request"
case _:
return "Something's wrong with the internet"
“变量名” _ 被作为 通配符 并必定会匹配成功
定义函数
def fib(n):
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
函数内的第一条语句是字符串时,该字符串就是文档字符串,也称为 docstring
默认值只计算一次。默认值为列表、字典或类实例等可变对象时,会产生与该规则不同的结果。
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
输出结果如下:
[1]
[1, 2]
[1, 2, 3]
不想在后续调用之间共享默认值时,应以如下方式编写函数:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
最后一个形参为 **name 形式时,接收一个字典
*name 形参接收一个元组
- 特殊参数
函数定义中未使用 / 和 * 时,参数可以按位置或关键字传递给函数。
standard_arg(2) //按位置传递参数
standard_arg(arg=2) //按关键字传递参数
def pos_only_arg(arg, /):
def kwd_only_arg(*, arg):
def combined_example(pos_only, /, standard, *, kwd_only):
- lambda表达式
def make_incrementor(n):
return lambda x: x + n
- 文档字符串
第一行应为对象用途的简短摘要。
文档字符串为多行时,第二行应为空白行,在视觉上将摘要与其余描述分开。
def my_function():
"""Do nothing, but document it.
No, really, it doesn't do anything.
"""
pass
print(my_function.__doc__)
五、数据结构
- 列表
list.insert(len(a),x) = append(x)
list.remove(x)
list.pop()
list.sort()
list.reverse()
- 用列表实现堆栈
pop() append()
- 用列表实现队列
popleft() append()
- 列表推导式
squares = []
for x in range(10):
squares.append(x**2)
squares = [x**2 for x in range(10)]
l = [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
- 嵌套的列表推导式
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
transposed = [[row[i] for row in matrix] for i in range(len(matrix[0]))]
#外层循环是 for i in range(len(matrix[0])),它遍历了原始矩阵的每一列的索引。内层循环是 for row in matrix,它遍历了原始矩阵的每一行。
- 集合
创建空集合只能用 set(),不能用 {},{} 创建的是空字典
a = set('abracadabra')
b = set('alacazam')
a-b a+b a&b a^b
- 字典
tel = {'jack': 4098, 'sape': 4139}
tel['guido'] = 4127
对字典执行 list(d) 操作,返回该字典中所有键的列表
在字典中循环时,用items()
方法可同时取出键和对应的值:
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
print(k, v)
在序列中循环时,用 enumerate()
函数可以同时取出位置索引和对应的值:
for i, v in enumerate(['tic', 'tac', 'toe']):
print(i, v)
逆向循环序列时,先正向定位序列,然后调用 reversed()
函数:
for i in reversed(range(1, 10, 2)):
print(i)
使用 set()
去除序列中的重复元素
- 比较运算符
in not in 用于执行确定一个值是否存在(或不存在)于某个容器中的成员检测
is is not 用于比较两个对象是否是同一个对象
and or
六、模块
Python 把各种定义存入一个文件,在脚本或解释器的交互式实例中使用。这个文件就是 模块 ;模块中的定义可以导入到其他模块或主模块。
其文件名是模块名加后缀名.py
。在模块内部,通过全局变量 __name__
可以获取模块名(即字符串)
- 导入模块
import fibo
fibo.fib(1000)
from fibo import fib, fib2
fib(500)
from fibo import *
fib(500)
import fibo as fib
fib.fib(500)
from fibo import fib as fibonacci
fibonacci(500)
- 以脚本方式执行模块
python fibo.py <arguments>
这项操作将执行模块里的代码,和导入模块一样,但会把 __name__ 赋值为 "__main__"
。 也就是把下列代码添加到模块末尾:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
这个文件既能被用作脚本,又能被用作一个可供导入的模块,因为解析命令行参数的那两行代码只有在模块作为“main”文件执行时才会运行
- dir()函数
内置函数 dir()
用于查找模块定义的名称。返回结果是经过排序的字符串列表
- 包
包是一种用“点式模块名”构造 Python 模块命名空间的方法
例如,模块名 A.B 表示包 A 中名为 B 的子模块
例如一个包的架构:
导入包时,Python 搜索 sys.path 里的目录,查找包的子目录。
必须要有
__init__.py
文件才能让 Python 将包含该文件的目录当作包来处理。这可以防止具有通用名称的目录如 string 在无意中屏蔽后续出现在模块搜索路径中的有效模块。
在最简单的情况下,init.py 可以只是一个空文件,但它也可以执行包的初始化代码或设置 all 变量。
import sound.effects.echo
from sound.effects import echo
from sound.effects.echo import echofilter
- 从包中导入 *
如果包的 init.py 代码定义了列表 all,运行 from package import * 时,它就是被导入的模块名列表。
__all__ = ["echo", "surround", "reverse"]
如果没有定义 all,from sound.effects import * 语句 不会 把包 sound.effects 中所有子模块都导入到当前命名空间;该语句只确保导入包 sound.effects
- 相对导入
可以用 import 语句的 from module import name 形式执行相对导入
下面的导入语句使用前导句点表示相对导入中的当前包和父包
from . import echo
from .. import formats
from ..filters import equalizer
注意,相对导入基于当前模块名。因为主模块名永远是 "main",所以如果计划将一个模块用作 Python 应用程序的主模块,那么该模块内的导入语句必须始终使用绝对导入。
包还支持一个特殊属性 __path__
。在包的 __init__.py
中的代码被执行前,该属性被初始化为一个只含一项的列表,该项是一个字符串,是 init.py 所在目录的名称
七、输入与输出
输出格式
- 格式化字符串字面值
f'Results of the {year} {event}'
# 将 pi 舍入到小数点后三位
print(f'The value of pi is approximately {math.pi:.3f}.')
print('We are the {} who say "{}!"'.format('knights', 'Ni'))
print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam
#使用关键字参数名引用值
print('This {food} is {adjective}.'.format(
food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible.
'{:-9} aaabbbb votes {:2.2%}'.format(var1, var2)
- 旧式字符串格式化方法
print('The value of pi is approximately %5.3f.' % math.pi)
The value of pi is approximately 3.142.
读写文件
open(filename, mode, encode)
f = open('workfile', 'w', encoding="utf-8")
mode
的值包括 'r' ,表示文件只能读取;'w' 表示只能写入(现有同名文件会被覆盖);'a' 表示打开文件并追加内容,任何写入的数据会自动添加到文件末尾。'r+' 表示打开文件进行读写。mode 实参是可选的,省略时的默认值为 'r'
在mode
后面加上一个 'b' ,可以用 binary mode 打开文件with open
在处理文件对象时,最好使用 with
关键字。优点是,子句体结束后,文件会正确关闭,即便触发异常也可以。而且,使用 with
相比等效的 try
-finally
代码块要简短得多:
with open('workfile', encoding="utf-8") as f:
read_data = f.read()
# We can check that the file has been automatically closed.
f.closed
True
- 文件对象的方法
f.read(size)
可用于读取文件内容并返回字符串(文本模式),或字节串对象(在二进制模式下)。
size 是可选的数值参数。省略 size 或 size 为负数时,读取并返回整个文件的内容
f.readline()
从文件中读取单行数据
for line in f:
print(line, end='')
f.write(string)
把 string 的内容写入文件,并返回写入的字符数。
f.tell()
返回整数,给出文件对象在文件中的当前位置
f.seek(offset, whence)
可以改变文件对象的位置
- 使用JSON
只需一行简单的代码即可查看某个对象的 JSON 字符串表现形式:
import json
x = [1, 'simple', 'list']
json.dumps(x)
'[1, "simple", "list"]'
dumps()函数还有一个变体dump()
,将对象序列化为text file。因此,如果 f
是text file 对象,可以这样做:
json.dump(x, f)
# 解码对象
x = json.load(f)
八、异常
- 异常的处理
try 语句的工作原理如下:
首先,执行 try 子句 (try 和 except 关键字之间的语句)。
如果没有触发异常,则跳过 except 子句,try 语句执行完毕。
如果在执行 try 子句时发生了异常,则跳过该子句中剩下的部分。 如果异常的类型与 except 关键字后指定的异常相匹配,则会执行 except 子句,然后跳到 try/except 代码块之后继续执行。
如果发生的异常与 except 子句 中指定的异常不匹配,则它会被传递到外部的 try 语句中;如果没有找到处理程序,则它是一个 未处理异常 且执行将终止并输出如上所示的消息。
try:
this_fails()
except ZeroDivisionError as err:
print('Handling run-time error:', err)
- 触发异常
raise 语句支持强制触发指定的异常
唯一的参数就是要触发的异常。这个参数必须是异常实例或异常类
raise ValueError # shorthand for 'raise ValueError()'
如果只想判断是否触发了异常,但并不打算处理该异常,则可以使用更简单的 raise 语句重新触发异常:
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise
- 异常链
如果一个未处理的异常发生在 except 部分内,它将会有被处理的异常附加到它上面,并包括在错误信息中
try:
open("database.sqlite")
except OSError:
raise RuntimeError("unable to handle error")
如果存在 finally 子句,则 finally 子句是 try 语句结束前执行的最后一项任务。不论 try 语句是否触发异常,都会执行 finally 子句
九、类
Python 的类有点类似于 C++ 和 Modula-3 中类的结合体
- 作用域
global
语句用于表明特定变量在全局作用域里,并应在全局作用域中重新绑定;
nonlocal
语句表明特定变量在外层作用域中,并应在外层作用域中重新绑定。
- 类定义:
在实践中,类定义内的语句通常都是函数定义
当(从结尾处)正常离开类定义时,将创建一个 类对象
三种对象类型
- Class 对象
类对象支持两种操作:属性引用和实例化。
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
#属性引用
obj.name
# 类的 实例化
#实例化操作会创建一个空对象
x = MyClass()
# __init__() 创建带有特定初始状态的自定义实例 eg:
def __init__(self):
self.data = []
# __init__() 方法还可以有额外参数,提供给类实例化运算符的参数将被传递给 __init__()
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart
x = Complex(3.0, -4.5)
x.r, x.i
(3.0, -4.5)
实例对象
实例对象所能理解的唯一操作是属性引用。 有两种有效的属性名称:数据属性和方法。方法对象
调用 x.f() 其实就相当于 MyClass.f(x)
f定义为:
def f(self): return 'hello world'
- 类和实例变量
class Dog:
kind = 'canine' # class variable shared by all instances
def __init__(self, name):
self.name = name # instance variable unique to each instance
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind # shared by all dogs
'canine'
>>> e.kind # shared by all dogs
'canine'
>>> d.name # unique to d
'Fido'
>>> e.name # unique to e
'Buddy'
self.后面的变量相当于private
而直接定义在类里面的数据是共享的。
方法的第一个参数常常被命名为 self。 这也不过就是一个约定: self 这一名称在 Python 中绝对没有特殊含义。但是要注意,不遵循此约定会使得你的代码对其他 Python 程序员来说缺乏可读性,而且也可以想像一个 类浏览器 程序的编写可能会依赖于这样的约定。
方法可以通过使用 self 参数的方法属性调用其他方法:
class Bag:
def __init__(self):
self.data = []
def add(self, x):
self.data.append(x)
def addtwice(self, x):
self.add(x)
self.add(x)
- 继承
当基类定义在另一个模块中的时候
class DerivedClassName(modname.BaseClassName):
(对 C++ 程序员的提示:Python 中所有的方法实际上都是 virtual 方法。)
有一种方式可以简单地直接调用基类方法:
即调用 BaseClassName.methodname(self, arguments)
Python 也支持一种多重继承。
- 私有变量
大多数 Python 代码都遵循这样一个约定:带有一个下划线的名称 (例如 _spam) 应该被当作是 API 的非公有部分 (无论它是函数、方法或是数据成员)。
由于存在对于类私有成员的有效使用场景(例如避免名称与子类所定义的名称相冲突),因此存在对此种机制的有限支持,称为 名称改写。 任何形式为 __spam 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为 _classname__spam,其中 classname 为去除了前缀下划线的当前类名称。 这种改写不考虑标识符的句法位置,只要它出现在类定义内部就会进行。
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable) #在构造函数中调用了私有方法 __update
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
# 将 update 方法赋值给私有方法 __update
__update = update
- 伪结构体
from dataclasses import dataclass
@dataclass
class Employee:
name: str
dept: str
salary: int
john = Employee('john', 'computer lab', 1000)
john.dept
'computer lab'
john.salary
1000
- 迭代器
iter()
s = 'abc'
it = iter(s)
it
<str_iterator object at 0x10c90e650>
next(it)
'a'
next(it)
'b'
next(it)
'c'
next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
- 生成器
生成器 是一个用于创建迭代器的
十、标准库简介
- 操作系统接口
一定要使用 import os 而不是 from os import * 。这将避免内建的 open() 函数被 os.open() 隐式替换掉
import os
os.getcwd() # Return the current working directory
'C:\\Python311'
os.chdir('/server/accesslogs') # Change current working directory
os.system('mkdir today') # Run the command mkdir in the system shell
import shutil
shutil.copyfile('data.db', 'archive.db')
'archive.db'
shutil.move('/build/executables', 'installdir')
'installdir'
- 字符串模式匹配
import re
re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'
- 互联网访问
smtplib 用于发送邮件
import smtplib
server = smtplib.SMTP('localhost')
server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
"""To: jcaesar@example.org
From: soothsayer@example.org
Beware the Ides of March.
""")
server.quit()
- 性能测量
from timeit import Timer
Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
0.57535828626024577
Timer('a,b = b,a', 'a=1; b=2').timeit()
0.54962537085770791
- 多线程
import threading, zipfile
class AsyncZip(threading.Thread):
def __init__(self, infile, outfile):
threading.Thread.__init__(self)
self.infile = infile
self.outfile = outfile
def run(self):
f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
f.write(self.infile)
f.close()
print('Finished background zip of:', self.infile)
background = AsyncZip('mydata.txt', 'myarchive.zip')
background.start()
print('The main program continues to run in foreground.')
background.join() # Wait for the background task to finish
print('Main program waited until background was done.')
- 日志记录
import logging
logging.debug('Debugging information')
logging.info('Informational message')
logging.warning('Warning:config file %s not found', 'server.conf')
logging.error('Error occurred')
logging.critical('Critical error -- shutting down')
十二、虚拟环境和包
相当于一个容器,nbcs
应用程序有时需要特定版本的库,可以创建一个 virtual environment,一个目录树,其中安装有特定Python版本,以及许多其他包。
用于创建和管理虚拟环境的模块称为 venv
#创建虚拟环境,确定放置的目录
python -m venv tutorial-env #创建 tutorial-env 目录
# 创建虚拟环境后,您可以激活它。
tutorial-env\Scripts\activate.bat #Windows上
source tutorial-env/bin/activate #Unix上
- pip的使用
python -m pip uninstall
python -m pip show
python -m pip list
python -m pip freeze
requirements.txt
install -r
python -m pip install novas
python -m pip install requests==2.6.0
python -m pip install --upgrade requests
# 显示包的版本信息、位置等
python -m pip show requests
#显示已安装的所有包
python -m pip list
#输出已安装的包到指定文件,可供install -r命令使用
python -m pip freeze > requirements.txt
python -m pip install -r requirements.txt