python 简明笔记
python 简明笔记
基础内置类型
数值类型
字面量
3.14e-10
3.14E-10
3.14e+10
#八进制
0o123
#十六进制
0xabf
#二进制
0b10101
#进制转换函数
#把一个整数数值转换成三种进制的字符串
hex(I)
oct(I)
bin(I)
#把三种进制的字符串转换成数字
int(str_num, jinzhi)
str_num = "0xff"
int(str_num, 16)
#小数取整
import math
#向下取整
math.floor(num_f)
#向零取整
math.trunc(num_f)
int(num_f)
#四舍六入 五向偶舍入
round(num_f) #保留整数部分
round(num_f, n) #保留小数点后n位
#开平方
import math
math.sqrt(144)
144**0.5
#指数
pow(5,2)
5**2
#随机
import random
#产生一个(0,1)的小数
random.random()
#产生一个[1,3]之间的整数
random.randint(1,3)
#从数组arr中随机挑选一个,返回挑选出的元素
random.choice(arr)
#将数组arr打乱,没有返回
random.shuffle(arr)
集合
不可变对象的无序集合
- 集合只能包含不可变对象,因此集合和字典不能嵌入到集合中,元祖可以。
- 用来过滤重复项
- 借助集合进行顺序无关的等价性测试
- 性质:无序,不重复
s1 = {1, 2, 3} #集合
s2 = {} #字典
x = set("abcd")
y = set("abCD")
print(x | y)
print(x & y)
print(x ^ y) #去掉两个集合的交集
print(x < y) #真子集
print(x <= y) #子集
print(x - y)
#插入一个项目
x.add("EF")
#原地求并集
z.update({1, 2})
#根据值删除一个元素
z.remove(1)
#集合表达式通常需要两个集合,他们基于方法的对应形式往往可以对任何可迭代类型有效
#这些都不是原地修改
z.union([1,2,3,4])
z.intersection([4,5,6])
z.issubset([1,2,3,4,5,6,7,8])
动态类型
每一个对象不仅仅有足够的空间来表示它的值,还包含其他数据结构
- 类型标志符
- 引用计数器
类型属于对象,而不是变量
可原位置修改
- 列表
- 字典
- 集合
#列表拷贝
arr = [1, 2, 3, 4]
arr_temp = arr[:]
#通用拷贝
import copy
arr_temp = copy.copy(arr)
arr_temp = copy.deepcopy(arr)
字符串
- 不可原位置修改
- 调用字符串方法,一般通过返回值来体现变化
############################################
# 字符串
#不允许 + 表达式中混合数字和字符串
#切片 前闭后开
ord('s') == 115
chr(115) == 's'
#若没有逗号,python 会自动拼接相邻的字符串字面量
#原始字符串,防止转义
s = r"\nasdfj\t"
#逆序切片,大下标写在前
s = '0123456789'
print(s[8:2:-2])
#不能在原位置修改
s = s.replace("1", "111")
print(s)
#替换前n个
s = s.replace("1", "111",n)
#替换前3个,否则全部替换
s = s.replace("old", "nwe", 3)
#可原位置于不可原位置修改对象调用函数时,返回值对比
s = "1010101010101"
s = s.replace("1","*****",)
arr = [1,2,3,4,0]
arr.sort()
#按值搜索,返回下标,找不到返回-1
s = "abcdefg"
index = s.find('cde')
#将列表中的字符串穿在一起,并用**分隔
s = "**".join([ "1", "2", "3" ])
#分割字符串,放到列表中
l = s.split("**")
#是否是字母(全部由字母组成)
s.isalpha()
#是否是数字
s.isdigit()
#返回大、小写
s.upper()
s.lower()
#开头、结尾检测
s.endswith("xx")
s.startswith("xx")
#去处空白
s = " 123 "
s = s.lstrip()
print(s)
#格式化输出
s = " %d %s" % (1, "haha")
s = " %(name)s 今天 %(age)d 岁了" % D #D是一个字典
s = " {0} {1}".format(1, "haha")
s = "{name} 今年 {age} 岁了".format(name="nana",age=17)
列表
任意对象的有序集合
############################################
# 列表
L = [1,2,3,4]
#尾部添加
L.append(5)
#尾部迭代添加
L.extend("abc")
#插入
L.insert(1,8)
#索引
L.index(1)
#统计出现数量
L.count(1)
#排序,原地排序
L = [1,67,23,90]
L.sort()
L.sort(reverse=True)
#反转
L.reverse()
#拷贝
L_temp = L.copy()
#清除
L.clear()
#删除i处元素,并返回
L = [1,67,12]
i = 1
L.pop(i)
#删除所有x
x = 1
L.remove(x)
#范围删除
L = [1,67,23,90]
i = 1
j = 3
del L[i]
del L[i:j]
L[i:j] = []
#切片赋值 先删除,然后迭代插入
L = list("123456789")
L[1:4] = [8,8,8]
#列表推导
l = [f(x) for x in range(19)]
字典
- 任何不可变对象都可以作为键(字符串、元祖、数字)
- keys,values,items 都返回视图对象
- 视图对象是可迭代对象,每次只产生一个结果项的对象,而不是在内存中立即产生结果列表
- 视图对象创建后,会随着字典的变化,动态的反应字典的修改
- keys的返回对象,支持集合操作
- 稀疏数据结构使用字典,用元祖作为键
- 字典模拟结构体
- 键的存在性 用 in测试
############################################
# 字典
#这种方式键是字符串
D = dict(name = "qwj" ,age = 19)
keyslist = ['name','age']
valueslist = ['qwj',19]
D = dict(zip(keyslist,valueslist))
D = dict([keyslist,valueslist])
#尝试获取,如果不存在返回default
D.get(key, "default")
#尝试删除,如果key存在,返回对应值,如果不存在返回default
D.pop(key, "default")
#如果key不存在,添加 key:default。如果key存在,返回【key】
D.setdefault(key, "default")
#删除所有键值对
D.popitem()
#浅层拷贝
D1 = D.copy()
#通过键来合并,有相同键,将D1按照D2更新
D1.update(D2)
#获取值
D = dict(zip(keyslist,valueslist))
val = D.get('name', "没有")
#删除键,并返回
D = dict(zip(keyslist,valueslist))
val = D.pop('name', "没有")
#若没有才插入
D = dict(zip(keyslist,valueslist))
D.setdefault('age','nana')
#最简单的异常捕捉
try:
print(D[1])
except:
print("出错了")
else:
print("没出错")
元组
- 任意对象的有序集合
- 元祖不可原位置更改,元祖内部元素不需要是不可变元素
- 与列表相似,元祖应当被看做对象引用的数组
- 不可变性只是限制顶层元素
T = (1,)
T = tuple("hello")
L = list("hello")
S = set("hello")
文件
output = open(r"data", 'w')
output = open('f.bin','rb') # 制文件
Input = open("data", 'r')
Input = open("data") # 默认是读
aString = input.read() # 整个文件读入一个字符串对象/bytes对象
aString = input.read(N) # 试读取N个字符到一个字符串
aString = input.readline() # 取一行(包含\n) 到一个字符串,只能用于文本文件
aList = input.readlines() # 读取整个文件到一个字符串列表 (每行包括换行),只能用于文本文件
output.write(aString) # 将字符串(或者字节序)写入文件
output.writelines(aList) # 将列表内的所有字符串写入文件中
output.close()
output.flush() # 写入的文件可能不会立即从内存移动到磁盘
anyFile.seek(N)
for line in open("data"): pass
#with 文件上下文管理器
with open('txt') as myfile:
for x in myfile:
print(x)
模式
模式 | |
---|---|
r | 默认,读 |
w | 写 |
a | 在文件尾部追加(写)内容 |
b | 处理二进制文件 |
+ | 同时支持读写 |
open('test', mode="w+", encodeing='utf-8')
文件的空行是含有换行符的字符串,而不是空字符串
存储python对象
pickle
import pickle
F = open("datafile.pkl", 'wb')
D = {
"name" : "qwj",
"age" : 17
}
pickle.dump(D, F)
F.close()
F = open("datafile.pkl", 'rb')
E = pickle.load(F)
print(E)
杂记
复合对象
- 列表、字典、元组可包含任何对象
- 字典的键、集合的内容 只能是不可变对象
- 列表、字典、集合可以动态扩容缩小
列表与元祖的异同
- 异
- 列表可以修改顶层元素、元素数量
- 同
- 元素都是指针
- 都是有有序
复制
import copy
x = copy.copy(y) #顶层复制
z = copy.deepcopy(y) #深层递归复制
等价性测试 ==:python递归的比较所有内嵌对象
同一性测试 is:测试两个对象在内存中的位置是否相同
#False
""
[]
{}
None #函数默认返回值
L = [None] * 100
#每个核心类型都有一个内置名
dict
list
str
tuple
int
float
complex
bytes
set
type
#type(x) 返回对象x的类型对象,类型也是一个对象
#类型判断(待测试对象,内置名)
isinstance(obj, list)
语句
while 1:print(x)
while True:
reply = input("输入一个数:")
if reply == "stop" : break
try:
num = int(reply)
except:
print("bad" * 8)
else:
print(num ** 2)
赋值
nana, qwj = 18, 19
#带*的名称可能只能匹配到单个项,但总会将其赋值为一个列表
x, *y = "hello"
*x, y = "hello"
x, *y, z = "hello"
x, y, *z = "hello"
x, *y = "h"
x = y = z = "hello"
命名规则
- 以单一下划线开头的名称(_x)不会被 from module import * 语句导入
- 类名以大写字母开头,模块名以小写字母开头
for _ in range(90):
print(100)
打印 print
- seq 分隔的字符串,默认 " "
- end 结尾的字符串,默认 "/n"
- file 输出流,默认"sys.stdout"
- flush 是否刷新输出缓冲区,默认"false"
重定向
#在python中
import sys
sys.stdout = open('log.txt', 'a')
#在shell 中
# < inputfile 输入重定向
# > outputfile 输出重定向
# 2> errfile 错误重定向
python没有switch、case,可使用字典来近似代替
逻辑
x and y
x or y
not x
三元运算
#选出最大的
x = 10
y = 20
z = x is x > y else y
while、for
while test:
if test: break
statements
else:
statements # 当while没有被break的时候执行else,或者理解break会跳过所有,包括else
for x in object:
if test: break
statements
else:
statements # 当while没有被break的时候
range
arr_1 = list(range(5))
arr_2 = list(range(1,5))
arr_3 = list(range(2,10,2))
[0, 1, 2, 3, 4]
[1, 2, 3, 4]
[2, 4, 6, 8]
enumerate 同时给出偏移量和元素
arr_1 = [1, 3, 5, 7, 9]
for i, x in enumerate(arr_1):
print(i, x)
迭代和推导
可迭代对象
- 一次产生一个结果的对象
- 是序列概念的一种通用化
- 包括实际的序列,以及能按照需求就算的虚拟序列
可迭代对象与迭代器
- 可迭代对象:迭代的调用对象。拥有
_iter_
方法,这个方法会被 iter函数调用
迭代器对象:可迭代对象的返回结果,在迭代过程中提供值的对象。拥有 _next_
方法,这个方法会被 next函数调用,并在结束时触发 StopIteration
- 有些对象即是可迭代对象,也是迭代器对象,他们会在iter调用中返回他们自己
- 迭代器对象通常是临时的,它们在迭代工具内部被使用
for循环、其他迭代工具
- 将可迭代对象传入内置函数iter,并由此拿到一个迭代器对象(可能返回自身)
- iter返回的迭代器对象有着所需的
_next_
方法 - 每次迭代中调用
_next_
方法,并通过捕捉StopIteration
异常来确定何时离开。
for 与 while 的性能
while循环比基于迭代器的for循环运行得更慢,因为迭代器对象在python内部是以C语言速度运行的,而while则是通过python虚拟机运行python字节码。
多次迭代
列表以及很多其他内置对象,由于自身不是迭代器,因此支持多次迭代。
map、filter、zip
- 他们本身就是迭代器对象,因此不能拥有多个位于不同位置的迭代器
# map将每一个可迭代对象传入func函数,并将所有的结果收集起来,返回一个可迭代对象
def func(x):
return abs(x)
arr = [1, -5, 8, -34]
re = map(func, arr)
[1, 5, 8, 34]
def func(x):
if x > 0:
return True
else:
return False
arr = [1, -5, 8, -34]
re = filter(func, arr)
[1, 8]
列表推导
x = [i**2 for i in range(10) if i > 3]
生成器表达式
# 记住了生产规则,但是还没有进行生产
x = (i**2 for i in range(10) if i > 3)
<generator object <genexpr> at 0x7f60c7bce110>
# 通过使用yield语句,用户定义的函数可以被转换成可迭代的生成器函数
def func(x):
for i in range(x):
yield i
x = func(5)
for i in x:
print(i)
帮助
help(list)
help(list.pop)
arr = [1,23,3]
help(arr)
函数
- 默认返回值None
- 函数是运行时创建的
作用域
-
查找顺序: 局部 -> 外层def -> 全局 -> 内置
-
内层不能直接修改外层,但可以读,如要写,使用nolocal和global
-
模块导入之后,全局变量变成模块的属性
-
全局作用域仅限于单个文件,当听到全局时,就应该联想到模块
global
C 语言中,函数可以直接读写全局变量。在python中,函数可以读全局变量,如要要写全局变量,必须使用global 声明一下。
- global 能创建一个不存在的全局变量
- global 声明会将变量映射到外层模块
g_x = 99
def func():
global g_x
global g_x = 111 # 这是错误写法,global只能用来声明
g_x = 100
func()
print(g_x) # 100
nolocal
闭包会将外层def中的变量包入函数中。nolocal 声明一个外层def的变量,便可修改外层def 中的变量
lambad
lambda是一个表达式,而不是语句。lambda是为编写简单函数而设计的
# :之前是参数,:之后是返回值
lambda x : x**2
lambda x, y=10, z=100 : x + y + z
参数
不可变参数: 本质上传入了值
可变参数: 本质上传入了指针
- 默认参数必须在最右侧
参数顺序
-
定义时
- 一般参数
- 默认参数
- *name
- keyword-only
- **name
-
调用时
- 基于位置的参数
- 关键字参数
- *iteration
- **dict
记录函数调用状态
# 以记录函数调用次数为例子
def maker():
count = 0
def func(x):
nonlocal count
count += 1
print(x, count)
return func
f = maker()
def func(x):
func.count +=1
print(x, func.count)
func.count = 0
函数注释
def func(a: "spam", b: (1,100), c: float) -> int:
return a + b + c
def func(a: "spam" = 4, b: (1,100) = 5, c: float = 6) -> int:
return a + b + c
map
对每一个元素都进行一个操作,并把其结果(return值)收集起来。放在一个可迭代对象中。
def inc(x): return x + 10
arr = [1, 2, 3, 4]
I = map(inc, arr)
filter
依次传入元素,若以该元素为参数的函数返回True,则将该元素保留,最终返回包含全部元素的可迭代对象
list(filter((lambda x: x>0), range(-5,8)))
reduce
from functools import reduce
re = reduce((lambda x,y : x+y), [1,2,3,4,5])
re == 10
# 返回结果,并不返回可迭代对象
标准推导语法
# x,y,z 是嵌套关系,并不是并列(像zip那样)
[ f(x,y,z) for x in iterable1 if condition1
for y in iterable2 if conditoin2
for z in iterable3 if condition3
]
res = [ x+y for x in [0,1,2] if x > 1
for y in [100,200,300] if y > 200
]
res == [302]
生成器函数
生成器将产生一些列值的时间分散到每一次循环迭代中去
def func(N):
for x in range(N):
yield x**2
f = func(4) # f是一个迭代器对象
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
❯ python try.py
0
1
4
9
Traceback (most recent call last):
File "/home/orange/code/python/try.py", line 10, in <module>
print(next(f))
StopIteration
生成器表达式
是单遍迭代对象
G = (x**2 for x in range(100))
G is iter(G) #true
模块
import执行时,会逐行运行在目标文档中的语句从而构建其中的对象
import 步骤
- 找到模块文件
- 编译字节码(.pyc文件,如果需要的话)
- 执行模块的代码来创建其定义的对象
python会把已加载的模块存储到一个名为sys.modules的表中,并在每次导入操作的开始检查该表。如果模块不存在,则启动三个步骤。
字节码集中存放在 __pycache__
子目录中,并在文件名中加入python版本号
模块搜索路径
- 程序主目录
- PYTHONPATH目录 (环境变量)
- 标准库目录
- 任何.pth 文件中的内容,文本文件一行一行列出目录(如果存在的话)
- 第三方拓展应用的 site-packages 主目录
- sys.path 里面存放着所有的路径,可以修改
from module import xxx
from module import *
from module import func as mfunc
from module2 import func as m2func
import m as my_m
import 和 from 是赋值语句
- import 将整个模块对象赋值给一个单独的名称
- from 将一个或多个名称赋值给另一个模块中的同名对象
# small.py
x = 1
y = [1,2]
# main.py
from small import x,y
# 等价于 x = small.x y = small.y
x = 100
y[0] = 99
import m
print(m.x) #1
print(m.l) #[99,2]
# small.x == 1
# small.y== [99,2]
模块中的函数,修改全局变量,永远修改的是自己模块中的全局变量
重新加载
reload 会在原位置修改模块对象,reload 并不会删除并重新创建模块对象
import module
from imp import reload
reload(module)
模块包
python代码的目录被称为包,包导入是把计算机上的目录变成另一个python命名空间,其属性对应于目录中所包含的子目录和模块文件。
# dir0/dir1/dir2/mod.py
import dir1.dir2.mod
from dir1.dir2 import x
# dir0 位于搜索路径中,或者没有dir0就是顶层py文件所在的目录,即main.py 与dir1在同一文件夹下
#说明
# dir0/dir1/dir2/mod.py
import dir1.dir2.mod
#dir1和dir2中必须含有一个 __init__.py文件,而dir0不需要
#dir0必须在搜索路径中
#__init__.py 中的python代码会在第一次导入一个路径的时候被自动执行,所以他们也被用作执行包的初始化步骤的钩子
import x.y.mym as mylib
mylib.func()
❯ tree
.
├── main.py
└── x
├── __init__.py
├── __pycache__
│ └── __init__.cpython-310.pyc
└── y
├── __init__.py
├── mym.py
└── __pycache__
├── __init__.cpython-310.pyc
└── mym.cpython-310.pyc