小狸笔记 - 面向对象编程 Python 速览笔记

小狸笔记 - 面向对象编程 Python 速览笔记

参考教程

(强推)Python面向对象编程五步曲-从零到就业【上】_哔哩哔哩_bilibili

(强推)Python面向对象编程五步曲-从零到就业【中】_哔哩哔哩_bilibili

(强推)Python面向对象编程五步曲-从零到就业【下】_哔哩哔哩_bilibili

学前阶段

电脑基础知识

机器语言:直接由 01 组成
汇编语言:由一些助记符代替 01
高级语言:最容易阅读
编译型:整个重新翻译,内容不变不用重翻译
解释性:每次都要一字一句地翻译

Python 安装

常用操作系统
image-20231028140535102
用户通过壳来操作内壳,从而控制硬件
壳(shell)分为有操作界面和无操作界面
Linux:
1、apt 工具安装
如 mkdir 创建文件夹
Apt-get 从某个地方找到软件下载并安装
Python-version 找版本
Sudo apt-get install python 3.6
Sudo 超级管理员权限
Which python 3.6 查看安装位置
Python 使用的默认解释器,进入解释器交互模式
Exit/ 退出模式
Python 版本进入对应的版本 python
2、编译 Python 源码安装
image-20231028142558062
Mac os:直接下载包双击
Windows:进入官网-downloads-安装
用 python 要进入 python 的安装目录
命令提示符会先在当前的目录找,找不到去环境变量找
所以添加环境变量:
系统变量中 Path 中添加 Python 路径
可以新建 PythonRoot 变量,指向 Python 安装目录
再将 PythonRoot 变量添加到 Path 中的值中

  1. X 可以直接安装时添加环境

image-20231028144118116

Scripts 中包含 pip 等工具

编程方式

1、命令提示符中写 python 进入,exit()退出
2、编写代码文件 test. Py
运行 python 文件. Py
3、IDLE 官方的编写器
4、Pycharm

Pycharm 软件使用

from css import test

从 css 文件夹中导入 test 文件

重构可以同步修改所有文件里的对应文件链接
删除可以安全删除,防止影响
Ctrl+/ 注释代码
Ctrl+alt+L 自动格式化代码
Ctrl+鼠标左键 查看代码来源
打断点 打断点的那一行不会运行

Python 运行机制

image-20231028174659412

会先编译成一个中间结果的字节码,再解释执行
.pyc 就是编译好的字节码
.py 发生修改就要重新编译

image-20231029165544551

Import 经常作为工具,所以 import 才会持久化. Pyc

基础阶段

注释

# 注释

image-20231029171940962

中文乱码问题

# encording=utf-8
 python2解决中文乱码

image-20231030085006929
image-20231030085942757

变量

a = 1
a,b = 1,2
a = b = 1

命名规范:
只能字母数字下划线
驼峰标识,首字母小写
不可用关键字

关键字列表:
Import keyword
Print (keyword. Kwlist)

变量区分大小写
变量名使用前要赋值

数据类型

数据类型是值拥有的,不是变量有的
image-20231031103506506
image-20231031103618913
image-20231031103644434
查看数据类型

type(a)

类型转换

int(a)
str(b)

image-20231031112327993
静态类型:int a = 10
a 永远是 int 类型
动态类型:后面出现 char a
a 变为 char 类型

Python 是动态类型

Python 不会自动转换类型(强类型)

运算符

算数运算符

+ 数值相加、列表重载、字符串拼接
- 数值相减
* 数值相乘
** 求幂运算
/ 数值相除
// 整除运算(取整)
% 求余运算
= 赋值符号

复合运算符

+= -= *= /= %= **=  //=

比较运算符

> < != >= <= == is

比较运算符返回 bool
Is 是用来比对唯一标识(id)

5 < num < 20 链式比较

逻辑运算符

not  and  or

Bool 非 0 非空当作真
存在短路运算符
Print(1 and 3) 得到 3
Print(1 or 3) 得到 1
Print(0 or flase) 得到 false

输入

Python 2

content = raw_input("请输入内容")
 所有输入内容全是字符串
content = input("请输入内容")
 所有输入内容当作代码:
  abd当作变量,1+1当作2
eval(raw_input("aaa")) = input

Python 3

raw_input ->  input("aaa")
input    ->  eval(input("aaa"))

输出

image-20231031161803885
Python 3

print ("aaa")
#格式化输出
print ("name:%s, age:%c"%(name, age))
print ("name:{0}, age:{1}". format (name, age))
print (f'name:{name}, age:{age}')
#输出到文件
f = open ("test","w")
print ("xxxxx", file = f)
import sys
f = open ("test","w")
print ("xxxxx", file = sys. stdout)
#不自动换行
print ("abc", end="")
#使用分隔符分割
print ("1","2","3", sep="&")
#停顿5秒
from time import sleep
sleep (5)
#立即打印
#字符串会先到缓冲区中 ,如果有换行就立即打印,而 sleep 会阻止立即打印,而 flush 能让字符串无论是否有回车都立即打印
print ("aaa", end="", flush=True)

格式符补充

%[(name)][flags][width][. preception]typecode
#[]可省略
print ("name%d, age%d" % (name, age))
#name
print ("name%(ms) d, age%(es) d" % ({"es": age,"ms": name}))
#flags
print ("%10 d" % age)
# %-d 表示左对齐,默认右对齐
# % d 左侧空格,与负数对其,只能一个
# %0 d 零来补充,如%02 d
#width表示占用的宽度
#. perception
print ("%. 2 f")
#小数点后两位

image-20231031201401373

  • G/g 自动转换

B 二进制
O 八进制
X 十六进制

流程控制

If
If age >= 18:
 Print ("good")

通过缩进实现代码块
Bool 非 0 非空即为真

If age >= 18:
 Print ("good")
Else:
    Print ("not")
If a > 0:
    ...
Else:
    If b > 0;
    ...
 Else:
        If c > 0:
            ...
        Else:
            ...
If a > 0:
    ...
Elif b > 0;
    ...
Elif c > 0:
    ...
Else:
    ...
If not (a > 0):
    Exit ()

Elseif -> elif
无 switch…. Case

While
While a > 0:
    Print ("aaa")
While a > 0:
    Print ("aaa")
Else:
    Print ("finish")

没有 do…while…

For
Notice = "abcd"
For i in notice:
    Print (i)
Notice = ["aaa","bbb","ccc"]
Notice = range (1,101)

通常用于遍历集合
Notice 取出一个元素放给 i
I 可用人任何新的变量名
Range (1,101) 生成 1-100 列表

For i in notice:
    Print (i)
Else:
    Print ("finish")

不满足(循环结束后运行 else)

For i in notice:
    Print (i)
    Break
Else:
    Print ("finish")

循环中途退出就不执行 else

Result = ""
For i in notice:
    Result = c + result
Print (result)

字符串倒序输出

For i in range (1,6):
    Print (i)

循环 5 次:i = 1,2,3,4,5

Break

结束所有循环

Continue

结束本次循环,进入下次循环

Exit
Exit ()

退出程序

Pass

空语句,保持代码完整性

If a > 0:
    Pass
Else:
    Pass
While a > 0:
    Pass

数据类型

数值

image-20231106164829514

Int 和 float 运算,int 变为 float

函数
内建函数
Abs (a)   绝对值
Max (a, b, c)  最大值
Min (a, b, c)  最小值
Round (a)  四舍五入
Round (a[, 2]) 保留 2 为小数
Pow (a, 2)  a 的 2 次方
Math 模块函数
Import math
Math. Ceil (a) 向上(大)取整
Math. Floor (a) 向下(小)取整
Math. Sqrt (a) 开平方
Math. Log (a, b) b 的多少次方等于 a
随机函数
Import random
Random. Random ()  生成[0,1)之间的随机数
Seq = [1,2,3,4]
Random. Choice (seq) 随机选择一个数
Random. Uniform (x, y) 生成[x, y]之间的随机小数
Random. Randint (x, y) 生成[x, y]之间的随机整数
Random. Randrange (x, y, z) [x, y)之间步长为 z 的随机数,y 默认 None,z 默认 1
三角函数
Import math
Math. Pi = 180 角度/180*pi=弧度
Math. Sin (a)  
Math. Cos (a)
Math. Tan (a)
Math. Asin (a) 反正弦
Math. Acos (a) 反余弦
Math. Atan (a) 反正切
Math. Radians (a) 角度 -> 弧度
Math. Degrees (a) 弧度 -> 角度
Bool
True  -> 1
False -> 0
字符串
基本方式
'aaa'
"aaa"
'''aaa'''
"""aaa"""
\t (Tab) \'  \"  \n
Name = "a"\
"b"

末尾加上\ 表示续行

Name = ("a"
"b")
用括号也可以续上
'''aaa
Bbb'''
"""aaa
Bbb"""

三个引号可换行使用

R'a'
R"a"
R'''a'''
R"""a"""

原始字符串,里面是什么就输出什么

Name = '我是 “hello” '

单引号和双引号混合使用可以避免转义

拼接
'str 1' + 'str 2'
'str 1'   'str 2'

可用 + 连接或在同一行放在一块

"我是%s,%d"%("123", 123)
"abc"*3

字符串多倍输出

切片
Name = "H  e  l  l  o"
		0  1  2  3  4
	   -5 -4 -3 -2 -1
Name[2]    l
Name[-2]   l
name[1:3] [1,3) el
Name[起始: 终止: 步长]
Name[0: len (name): 1] len 表示全部长度 (4)
Name[::]   取默认值,全部顺序输出
Name[::-1]   倒序输出
name[0:4:1]
name[4:0:-1]
Name[-1:-4:-1]

使用方式:

Find ("abc","a")  内建函数
"abc". Find ("a")  对象方法

函数

Len (name)  字符个数 (转义符算一个)

👇num = name. Xxx (‘a’)

查找
Find (sub, start=0. End=len (str))
	查找索引 (没找到-1)
Rfind (sub, start=0. End=len (str))
	查找索引 (从右往左)
Index (sub, start=0, end=len (str))
	查找索引 (没找到报错)
Rindex (sub, start=0, end=len (str))
	查找索引 (从右往左, 没找到报错)
Count (sub, start=0, end=len (str))
	数个数
转换
Replace (old, new[, count])
	替换 (count 可选个数, 结果为返回值)
Capitalize ()
	字符串首字符大写
Title ()
	每个单词首字符大写 (不是字母就分割)
Lower ()
	每个字符都小写
Upper ()
	每个字符都大写
扩充
Ljust (6,"x")
	用 x 填充到 6 个长度, 原字符串靠左
Rjust (6,"x")
	用 x 填充到 6 个长度, 原字符串靠右
Center (6,"x")
	用 x 填充到 6 个长度, 原字符串靠中 (偏左)
缩减
Lstrip (chars)
	从左移除字符集里包含的字符,默认空白
Lstrip (chars)
	从右移除字符集里包含的字符,默认空白
	空白:\n \t space
分割
Split (sep, maxsplit)
	以 seq 识别为分隔符,最大分割 max 次
    Maxsplit 省略则全分割
Partition (seq)
	从左以 seq 识别为分隔符
    返回元组 ('左侧','分隔符','右侧')
    如果没有则全部在左侧
Rpartition (seq)    
	从右以 seq 识别为分隔符
Splitlines (keepends)
	按照换行符 (\r \n) 拆分保存到列表
    Keepends = True 保留换行符 (默认 x)
Join (iterable)
 将可迭代 iterable 用对象连起来
    '-'. Iterable (['a','b','c'])
     -> 'a-b-c'
判断
Isalpha ()
	是否全为字母
Isdigit ()
	是否全为数字
Isalnum ()
	是否全为数字或字母
Isspace ()
	是否全为空白符
	包括空格\缩进\换行\回车
       Sapce\tab\n  \r
Startswith ()
	是否以某个前缀开头
	(prefix, start=0, end=len (str))
	需要判断的字符串, 起始位置, 结束位置
Endswith ()
	是否以某个尾缀结尾
"aaa" in "aaabbbccc"
"ddd" not in "aaabbbccc"
列表

(有序、可变)

name = [“a”,“b”,“c”]
name = []
name = ['a','b', True,['c']]

列表生成式

name = range (99)
	生成 0-99
name = range (1,99,1)
	生成 1-99,步长默认为 1

列表推导式(从一个到另一个)

a = [12345]
b = []
for i in a
	b.append (i ** 2)
b = [i**2 for i in a]
	1,4,9,16,25
b = [1 for i in a]
	1,1,1,1,1
b = [i for i in a for j in a]
	1,2,3,4,5,... (*5)
b = [i for i in a if i%2==0]
	2,4

常用操作
增加

list. xxx ()
.append (object)
	末尾追加一个 object
.insert (index, object)
	在 index 前面插入 object
.extend (iterable)
	列表中添加另一个可迭代的序列
list*2
	['1','2']
	->['1','2','1','2']
list 1+list 2list 2 追加到 list 1(list 2 只能是列表)
	. append ()可为字符串等可拆的

删除

del list[2]
	删除索引为 2 的元素
del list
	删除整个列表
list. pop (2)
	删除索引为 2 的元素, 返回索引值
	空白默认移除最后一个元素 (-1)
list. remove (object)
	从左往右删除内容为 2 的元素
nums = [1,2,2,2,3,4,2]
for i in nums
	if i == 2:
		nums. remove (2)
-> [1,3,4,2]
每次 remove 之后都会重排这个列表,所以通过索引会漏掉,不能用

修改

name[2] = 3
	索引为 2 的元素修改为 3

查询

num = range (10)
num[2]
num[-1]
num. index
	(value, start=None, stop=None)
	获取元素值为 value 的索引
	#
	遍历显示所有元素的索引值:
	错误:
		xs = ['a','a','b']
		for i in xs:
			print (xs. index (v))
		->0,0,2
		每次都从头开始遍历,出错
	正确 1:
		xs = ['a','a','b']
		ind = 0
		for i in xs:
			print (xs. index (v, ind))
			ind+=1
		->0,1,2	
		每次都从 ind+1 开始,正确
	正确 2:
		造一个索引列表
		ind = [0,1,2]
		ind = range (3)
		ind = range (len (xs))
num. count (value)
	查找元素为 value 的个数
num[start:stop: step]
	[start, stop)
num[::-1]
通过枚举对象遍历:
['a','b','c','d']
->[(1,'a'), (2,'b'), (3,'c'), (4,'d')]
newList (enumerate (oldList))
#
for tupleVal in enumerate (newList):
	[(1,'a')]->(1,'a')
		转换为元组
	print (tupleVal[0])
	print (tupleVal[1])
		把每个元组中的第 12 个元素取出
	或:
	idx, val = tupleVal
->
for idx, val in enumerate (newList)
for idx, val in enumerate (newList, 3)
	索引值从 3 开始
可迭代对象
	按照某种顺序逐个访问集合中的每一项
	1、能用 for i in ...
	2import collection
		isinstance (x, collection. Iterable)
		x 是否有 Iterable 特性
迭代器
	可以记录遍历位置的对象
	1、能用 next ()
	2import collection
		isinstance (x, collection. Iterator)
	3、迭代器也是可迭代对象
		也可用于 for i in ...
迭代器特点:
	只有迭代到某个元素才处理
		可不存在可被销毁
		用于遍历大型或无限集合
	提供统一的访问集合的接口
		iter (Iterable)
	访问简单
		next ()
	l = [1,2,3,4]
	it = iter (l) #创建迭代器it
	print (next (it)) #1
	print (next (it)) #2
	print (next (it)) #3
	for v in it:
		print (v) #1 2 3 4 5
	使用完就不能再重复用,只能重新建

判定

'a' in "abc"
'a' not in "bcd"
#
1 in [1,2,3,4,5]
1 not in [2,3,4,5]

比较

python 2

cmp (a, b)
	a>b    1
	a=b    0
	a<b    -1

python 3

"abc" > "aaa"
"abc" == "abc"
#
[1,2,3] == [1,2,3]
[2,4,3] > [2,2,4] #比较第一个不同的

排序

s=[('b', 1), ('a', 2)]
sorted
	(itearable, key=None, reverse=False)
	可迭代对象, 关键字, 降序=False (默认升)
	返回排序好的列表
	元组:默认按照元组第一个元素排
		get=sorted (s)
		get=sorted (s, reverse=True)
		按照第二个元素排:
		def getKey (x):
			return x[1]
		get=sorted (s, key=getKey)
	不改变原本
	对任何可迭代对象适用
list. sort (key=None, reverse=False)
	改变原本列表
	只能对列表操作
	def getKey (x):
		return x[1]
	s.sorted (key=getKey)

乱序

import random
random. shuffle (s)
	直接改变本身

反转

s.reverse ()
	改变列表本身
news = [::-1]
	不改变本身
元组

有序不可变集合

t = (1) #会被识别为int
t = (1,)
t = (1,2,3)
t = ('a',[1,2], 3)
t = tuple ([1,2,'a']) #列表转换为元组

增加、删除、修改(x)
获取

t[3]
t[-1]
t[1:4] #[1,4)
t[1:4:-1]
t.count (2)
	计算 2 的个数
t.index (2)
	获取对应的索引,不在会报错
len (t)
	长度
max (t)
min (t)

判定

1 in (1,2,3)
1 not in (2,3,4)

比较

cmp ((3,3), (2,3)) # >
cmp (tuple, list) # >
	不同类型时会比对类型的英文
> = <

拼接

(1,2,3)*3
(1,2,3)+(4,5)
	不同类型不能相加连接

拆包

a, b = (1,2) #a =1, b=2
a, b = (b, a) #交换两个值
字典

无序的键值对的集合

{key: value}
d = {'name': 'xs','age': 12}
print (d['name'])
print (d['age'])
d = dict. fromkeys (seq, value)
	将有序的 seq 转换为 key, 分别赋值 value
d = {1:2,3:4}. fromkeys
	会将原有的字典覆盖掉 (无意义)

key 不能重复(相同时后值覆盖前值)
key 必须是不可变类型

num = [1,2,3]
id (num)
num. append (4)
id (num)
# 两个 id 相同,因为 list 可变
a=10
id (a)
a=20
id (a)
# 两个 id 不同,因为 a 不是可变的

通过 key 唯一表示对应的索引值

增加

d = {'name': 'sz'}
d['age': 19]

删除

d = {'name': 'sz'}
del d['name']
d.pop ('name'[, default]) 
	弹出键值对
		有则返回对应的值
		没有则返回 default
		无设置 default 则报错
d.popitem ()
	< python 3.6
		将目前的字典按照 key 进行排序
		a 最小,再删除最小的键值对
	> python 3.6
		删除最后一个 (最后添加的)键值对
	返回对应的键值对
d.clear ()
	清空字典
del d
	删除字典

修改

d['name']='sz'
d.update ('age'=20,'sex'='boy')
	有则修改,无则添加

查询

print (d['age'])
	无则报错
d.get ('age'[, 666]) 
	无则返回 666,或 None
d.setdefault ('age'[, 666])
	无则设定该值为 666 并返回 666
d.keys ()
	获取所有的键
d.values ()
	获取所有的值
d.items ()
	获取所有的键值对
a = d.xxx ()
	python 2 中直接获取列表
		a 不随 d 改变
	python 3 中获取的是 view objects
		a 随 d 改变
		用 list (d.xxx)转换为列表
for i in d.keys ():
	print (d[i])
for k, v in d.items ():
	print (k, v)

计算

len (d)
	计算键值对的个数

判定

'name' in d
'age' not in d
	判定 key
集合

不可随机访问的,不可重复的元素集合

可变集合
s = {1,2,3}
s = set ("abc")
s = set ({'name': 'sz','age': 19})
	# 只会用 key 生成集合
s = set (x for x in range (0,10))
s = {x for x in range (0,10)}
	# 推导式
不可变集合
不可用{}
s = frozenset ("abc")
s = frozenset ({'name': 'sz'})
	# 只会用 key 生成集合
s = frozenset (x for x in range (0,10))
	# 推导式
s = {} 会被识别为字典
其中元素为可变时会提示不是可哈希
元素相同时会合并为一个 (可用于列表去重)

单一集合操作

增加:
s.add (4)
#
删除:
s.remove (3) #改变本身 ,返回 error
s.discard (3) #返回None
s.pop () #随机删除 ,返回错误
s.clear () #清空
del s #删除
#
查询:
1for 集合
	for i in s:
		print (i)
2、迭代器
	its = iter (s)
	print (next (its))
3for 迭代器
	its = iter (s)
	for v in its:
		print (v)

集合间操作

交集:
intersection (Iterable)
	print (s 1. intersection (s 2))
	以前面的 (s 1)类型为准, s 1 为可变则可变
&
	print (s 1 & s 2)
	以前面为准
intersection_update (Iterable)
	s 1. intersection_update (s 2)
	计算完赋值给前面的
	前面的 (s 1)必须为可变的
intersection (“abc”)
	匹配字符
	匹配列表、字符串的字符、字典的键
	会先把接收的对象转化为可哈希的集合
	所以该对象必须为可哈希的
		intersection ([1,2,3]) #√
		intersection ([1,2,[3,4]]) #x
并集:
union ()
	s 1. union (s 2)
|
	s 1 | s 2
	是否可变以左侧为主
update ()
	s 1. update (s 2)
	s 1 和 s 2 合并后给 s 1
差集:
difference ()
	s 1 = {1,2,3}
	s 2 = {3,4,5}
	s 1. difference (s 2)
	# s 1 - s 2 = {1,2}
-
	s 1 - s 2
difference_update ()
	s 1, difference_update (s 2)
	结果给 s 1
判定:
s 1. isdisjoint (s 2) # 不相交
s 1. issupperset (s 2) # s 1 包含 s 2
s 1. issubset (s 2) # s 1 包含于 s 2
时间日历

时间戳:从 0 时区的 1970 年 1 月 1 日 8 时 0 分 0 秒到只当日期时间的秒数(浮点数)

time

获取时间戳

import time
time. time ()

获取时间元组

time. localtime ()
-> time. struct_time (
	tm_year=2014,
	tm_mon=6,
	tm_mday=30,
	... (时间元组)
)
time. localtime (time. time)
	将时间戳转换为时间元组

image.png
获取格式化时间

time. ctime (time. time ())
-> Wed Sep 6 07:47:25 2017
	将秒转换为格式化时间
time. asctime (time. localtime ())
	将时间元组转换为格式化时间

格式化日期字符串 <–> 时间戳

时间元组->格式化日期
time. strftime (格式字符串, 时间元组)
time. strftime (%Y-%m-%d %H:%M:%S”, time. localtime ())
-> 2011-11-11 11:11:11
#
常用格式符
%y 两位数的年份表示 ( 00-99 )
%Y 四位数的年份表示 (000-9999 )
%m 月份 ( 01-12 )
%d 月内中的一天 ( 0-31)
%H 24 小时制小时数 ( 0-23 )
%I 12 小时制小时数 ( 01-12 )
%M 分钟数 ( 00=59 )
%S 秒 ( 00-59 )
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天 (001-366)
%p 本地 AM 或P.M 的等价符
%U 一年中的星期数 (00-53)星期天为星期的开始
%w 星期 (0-6),星期天为星期的开始    ...
格式化日期->时间元组
time. strptime (日期字符串, 格式符字符串)
time. strptime ("11-11-11 11:11:11",%y-%m-%d %H:%M:%S”)
时间元组->时间戳
time. mktime (时间元组)

获取当前 CPU 时间

统计代码执行耗时
start = time. clock ()
for i in range (0,10000)
	print (i)
end = time. clock
print (end-start)

休眠(暂停)

time. sleep (1) #休眠一秒
calendar
import calendar
print (calendar. month (2017,6)) a

image.png

datetime

要用里面具体的某个类

import datetime
获取日期
print (datetime. datetime. now ())
print (datetime. datetime. today ())
-> 2017-11-11 13:39:59.534278
单独获取当前日期
t = datetime. datetime. now ()
t.year
t.month
t.day
t.hour
t.minute
t.second
计算 n 天之后的日期
t = datetime. datetime. now ()
t 1 = t + datetime. timedelta (days=7)
计算时间差
first = datetime. datetime (
		2017,11,11,12,30,30)
second = datetime. datetime (
		2017,11,13,12,30,30)
delta = second - first
print (delta. total_seconds ())

函数

用法
def pFunc ():
	print (1)
	print (2)
	print (3)
	...
#
pFunc ()
传参

传一个参数

def test (i)
	print (i*2)
#
test (3)
传多个参数
def test (i, j)    -> i, j 形参
	print (i*j)
test (2,3)        -> 2,3 实参
test (j=3, i=2)    -> 关键字操作

传元组 (多个元素的和)

def test (t)
	result = 0
	for v in t:
		print (v)
		result += v
test ((1,2,3))
test ((1,2,3,4,5))

不定参数

*转换为元组
def test (*t)
	result = 0
	for v in t:
		print (v)
		result += v
test (1,2,3)
test (1,2,3,4,5)
#
**转换为字典
def test (**t)
	print (t)
test ('name'='sz','age'=18)

装包拆包

装包:把传递的参数,包装成一个集合
拆包:把集合参数,再次分解成独立的个体
#
元组:  *args = 1,2,3,4
     -> args = (1,2,3,4)
     加了 * 表示拆包后
     #
	装包:
	def test (*args): # args 表示多个参数的意思
		print (args) -> (1,2,3,4)
	拆包:
		print (*args) -> 1,2,3,4
字典:  **kwargs = "name": "sz","age":18
        kwargs = {"name": "sz","age": 18}

缺省参数

def test (a=1, b=0):
	print (a, b)
#
test ()
test (1,2)

值传递和引用传递

值传递:
def change (num):
	print (num)
#
b = 10 
	->创建一块内存空间
	  把 10 放入这块空间 (000110)
	  b 等于这块空间的地址 (b=000110)
change (b)
	->函数获取到 b 对应的值 10
	  新开辟一个空间放入值 10 (000222)
	  num 等于这块空间的地址 (num=000222)
	  对 num 的操作都不影响 b 的值

image.png

地址传递:
向 num 传递 b 的地址,使得 num 也指向原来的地址 (000110)

image.png

Python 中只有引用 (地址)传递
(根据数据类型是否可变判断)

Python 中当不可变的类型 (数字 10)发生改变之后 (变为 666), 会重新开辟一个新的空间赋值成 666 并把 num 指向新的地址
#
def change (num):
	num = 666
b = 10 # b (000110): 10
change (b) # num=b (000110): 10
		  # 10!=666 且不可变开辟新空间
		  # num (000333): 666

image.png

若传递的为可变的, 则对应变化
def change (num):
	num = [4,5,6]
b = [1,2,3] # b (000110): [1,2,3]
change (b) # num=b (000110): [1,2,3]
		  # (000110):[1,2,3] -> [4,5,6]
		  # b=num (000110): [4,5,6]

image.png

返回
def summ (a, b):
	return = a + b
#
summ (1,2)
	return 之后就不再执行
	只返回一次
	若想返回多个数值可包装成数组、列表...
		return (a+b, a*b)
		c, d = summ (1,2)
使用描述
def test ():
	"""帮助文档"""
命令提示符中: help (test)

image.png
image.png

偏函数

写一个参数比较多的函数时,有些参数大部分情况都是同一个值,则可创建偏函数指定要使用的函数的某个参数

def test 1 (a, b, c, d=1):
	print (a+b+c+d)
def test 2 (a, b, c, d=2):
	test 1 (a, b, c, d)
调用 test 2 时 d=2, 否则 d=1
import functools
newFunc = functools. partial (test 1, c=5)
functools. partial (函数, 偏参数=偏爱值)
newFunc (1,2)
	-> 相当于写了新函数 test 1 (a, b, c=5, d=1)
int ("10010", base=2) #2进制转换
#
import functools
int 2 = functools. partial (int, base=2)
之后调用 int 2 即可默认转换为 2 进制
高阶函数
def test (a, b):

a, b 是形参,也是变量
传递函数,就是指给变量赋值
函数本身也可以作为数据传递给另外一个变量
函数 test 的参数 a 接收的是另外一个函数
则函数 test 是高阶函数

例如:
qwq = ([{"name": 'sz','age': 19},
		{"name": 'ac','age': 13},
		{"name": 'tr','age': 15}])
#
result = sorted (qwq)
	报错,无法字典与字典比较,不知道哪个好
#
def getKey (x):
	return x['age']
		分别传入字典,取出对应字典 age 的值
#
result = sorted (qwq, key=getKey)
	这个就是高级函数
def caculate (num 1, num 2, caculateFunc):
	print (caculateFunc (num 1, num 2))
def jiafa (a, b):
	return a+b
def jianfa (a, b):
	return a-b
#
calculate (6,4, jianfa)
calculate (6,4, jiafa)
返回函数

是指个函数内部,它返回的数据是另外一个函数,把这样的操作称为“返回函数”

def getFunc (flag)
	def sum (a, b, c):
		return a+b+c
	def jian (a, b, c):
		return a-b-c
	if flag == "+"
		return sum
	elif flag == "-"
#
res = getFunc ("+") #返回一个函数
result = res (1,2,5) #调用加法这个函数
匿名函数

没有名字的函数

lambda 参数 a,b... : 表达式 (返回值)
只能写一个表达式,不能直接 return
return = (lambda x, y:x+y)(1,2) #返回1 +2
或
newFunc = lambda x, y:x+y
print (newFunc (4,5))
应用:
qwq = ([{"name": 'sz','age': 19},
		{"name": 'ac','age': 13},
		{"name": 'tr','age': 15}])
#
sorted (qwq, key=lambda x: x['age'])
闭包

在函数嵌套的前提下,内层函数引用了外层函数的变量,外层函数又把内层函数当作返回值进行返回
image.png

test () 嵌套了函数 test 2 ()
test 2 () 中使用了外层函数 test ()中的变量 b
	或者用了传进来的参数 c
test () 将整个内部函数 test 2 ()返回出去
def test ():
	a = 10
	def test 2 ():
		print (a)
	return test 2 ()
newFunc = test ()
newFunc ()
	->变成 print (10)

应用场景:外层函数,根据不同的参数生成不同作用功能的函数
例如:根据不同的配置信息生成不同分割线

应用 1def line_config (content, length):
	def line ():
	print ("-"*(length//2)
	+ content + "-"*(length//2))
	return line
line 1 = line_config ("aaa", 40)
line 2 = line_config ("bbb", 20)
line 1 ()
line 2 ()
应用 2:
a>10 时返回相加函数,否则返回相减函数
def config (a, b, c)
	if a>10:
		def summ (b, c)
		return summ ()
	else
		def cutt (b, c)
		return cutt ()
res 1 = config (11,3,4)
	返回 summ (3,4)
res 2 = config (9,7,5)
	返回 cutt (7,5)

注 1:闭包中要修改引用的外部变量,要用 nonlocal 声明,否则会当作时闭包内新定义的变量

def test ():
	num = 10 #-> 外部 num:10
	def test 2 ():
		num = 666 #-> 内部新 num:666
		print (num)
	print (num) #-> 外部 num:10
	test 2 () #-> 内部 num:666
	print (num) #-> 外部 num:还是 10
	内部完全独立于外部
#
def test ():
	num = 10 #-> num:10
	def test 2 ():
   ->>> nonlocal num
		num = 666 #-> num:666
		print (num)
	print (num) #-> num:10
	test 2 () #-> num:666
	print (num) #-> num:变为 666
	(nonlocalglobal)

注 2:闭包中引用了一个后期会发生变化的变量时要注意

def test ()
	a=1
	def test 2 ()
		print (a)
	a=2
	return test 2
newFunc = test () 
	-> newFunc = test 2
		a = 2
newFunc () #-> 执行 print (a)
	输出 2,只有当定义的函数被调用的时候才会确定值
	之前都是以普通的变量表示名称而存在
def test ()
	funcs = []
	for i in range (1,4)
		def test 2 ()
			print (i)
		funcs. append (test 2)
	return funcs
newFunc = test () #-> newFunc = funcs
	-> newFunc=[test 2, test 2, test 2]
		      =[print (i), print (i), print (i)]
		i = 3
newFunc [0]()
newFunc [1]()
newFunc [2]()
	结果全部是 3: 执行的时候已经循环完毕, i 始终为 3

image.png

要跟随改变:
def test ()
	funcs = []
	for i in range (1,4)
		def test 2 (num)
			def inner ():
				print (num)
			return inner
		funcs. append (test 2 (i))
		-> 每次循环:
			调用并运行 test 2 (i)
			此时 test 2 = inner,
				i 为对应的 i
			相当于运行 inner ()
			相当于运行 print (变化 i)print (变化 i) 加入列表
	return funcs
	-> 返回[print (1), print (2), print (3)]

image.png

只需要知道:
def test (i)
	def inner (i):
	return inner
#
test (i) return inner
	看两个 def: test (i) return inner (i)
	相当于: test = inner
只要调用、执行了 test (i)
就看成执行了 inner (i)
装饰器

在函数名与函数体不改变的前提下,给一个函数附加一些额外代码

# 功能代码
def fss ():
	print ("发说说")
def ftp ():
	print ("发图片")
# 逻辑代码
if a==1:
	fss ()
else:
	ftp ()
#
添加登录验证:
1、直接在逻辑代码中添加 (不推荐)
	if a==1:
		print ("login")
		fss ()
	else:
		print ("login")
		ftp ()
	逻辑代码很多,所以冗余度大,复用性差
2、直接在功能代码中修改
	def fss ():
		print ("login")
		print ("发说说")
	def ftp ():
		print ("login")
		print ("发图片")
	将登录功能提取出来:
	def login ():
		print ("login")

开放封闭原则:
已经写好的代码不要修改
新增的功能在原先基础上单独扩展
单一原则:
单一的功能函数只执行他对应的功能
不要参杂其他功能

def fss ():
	print ("发说说")
def ftp ():
	print ("发图片")
#
def login (func)
	print ("login")
	func ()
#
if a==1:
	login (fss)
else:
	login (ftp)
但是这样会改变原来的逻辑代码
那怎样不改变逻辑代码呢?
def login (func)
	print ("login")
	func ()
#
def fss ():
	print ("发说说")
def ftp ():
	print ("发图片")
#
fss = login (fss)
ftp = login (ftp)
#
这样不行,因为这个时候已经执行了一遍
所以使用闭包:
def login (func)
	def inner ():
		print ("login")
		func ()
	return inner
#
fss = login (fss)
	= inner () #传入func =fss
	= print ("login")
	  func ()
	= print ("login")
	  fss ()
不使用闭包,代码将在给新函数赋值的时候调用,如果使用闭包,则可以避免调用,安全将函数“改名”
此时称 login 为装饰器:在原有函数的基础上添加一些小功能
语法糖写法:
def login (func)
	print ("login")
	func ()
def fss ():
	print ("发说说")
def ftp ():
	print ("发图片")
fss = login (fss)
ftp = login (ftp)
#
变为:
def login (func)
	print ("login")
	func ()
@login
def fss ():
	print ("发说说")
@login
def ftp ():
	print ("发图片")
#
注:@login
	def fss ()
相当于:
	def fss ()
	fss = login (fss)
#
装饰器的执行时间:当写 @login 时就已经执行了

总结: https://www.bilibili.com/video/BV1v4411B7Zv/?p=167
image.png

注意事项 :
1 、多个执行器可叠加执行
从上至下装饰
从下至上执行

image.png

2 、参数传递
def aaa (func):
	def inner ():
		print ("a")
		func ()
	return inner
@aaa
def bbb (num)
	print (num)
bbb (123)
#
错误,应为
def aaa (func):
	def inner (n): <-
		print ("a")
		func (n) <-
	return inner
#
对于多个参数,可用不定长参数
def aaa (func):
	def inner (*args,**kwargs):
		print (args, kwargs)
		func (*args,**kwargs)
	return inner
def bbb (num 1, num 2, num 3)
	print (num 1, num 2, num 3)
bbb (111,222, num 3=666)
-> (111,222){'num 3'=666}
   111,222,666
3 、返回值
def aaa (func):
	def inner (n):
		print ("a")
		res = func (n)
		return res
	return inner
@aaa
def bbb (num)
	print (num)
	return (num) <-
bbb (123)
bbb (n)= aaa (bbb)(n)
      = inner (n)
      = print ("a")
        res = bbb (n)
        return res
      = print ("a")
        print (n)
        return n

只需要保证闭包 inner ()中的格式和被装饰的函数的格式相同

4 、带参数的装饰器
def aaa (func):
	def inner ():
		print ("-"*30)
		func ()
	return inner
@aaa  # bbb=aaa (bbb)
def bbb ():
	print ("666")
#
如果要传其他字符:
def getaaa (char)
	def aaa (func):
		def inner ():
			print ("-"*30)
			func ()
		return inner
	return aaa
@getaaa ("*")
def bbb ():
	print ("666")
相当于用一个函数包着装饰器
	def getaaa (char)
		装饰器
		return 装饰器
	  @getaaa ("*")
	= @aaa 且 char="*"
生成器

生成器是一种特殊的迭代器
特点:
节省内存,用时再取
能记录状态,用 next ()访问下一状态
具有可迭代特性,可 for … in …

l = [i for i in range (1,100) if i % 2==0]
iter (l)
	一次性生产很多数,不好

创建方式

表达式生成
l = (i for i in range (1,100) if i % 2==0)
print (next (l))
print (l.__next__())
#
函数生成
def test ():
	print ('0')
	yield 1
	print ('a')
	yield 2
	print ('b')
	yield 3
	print ('c')
	yield 4
	print ('d')
	yield 5
	print ('e')
包含 yield
g = test () -> 什么都不生成
print (g) -> 什么都没有
print (next (g)) -> 执行到 yield 1
				打印 '0' 1 (返回值/状态值)
print (next (g)) -> 执行到 yield 2
				打印 '0' 1 'a' 2
每次 next 都会让程序继续执行,直到下一个 yield 后暂停,返回该 yield 值,只有 next 会执行
yield 5 之后再 next 就会报错 (找不到下个 yield)

send ( ) 方法

def test ():
	print ("xxx")
	res 1 = yield 1
	print (res 1)
	res 2 = yield 2
g = test ()
print (g.__next__()) -> xxx 1
print (g.__next__()) -> xxx 1 None 2
其中 res 1 = yield 1 的值为 None
相比 send () 可以额外给 yield 传值
	指定上一次被挂起的 yield 语句的返回值
例如
第一次: print (g.send (None)) -> xxx 1
	第一次不能发非空的值, 只能传 None
第二次: print (g.send ("aaa")) -> xxx 1 aaa 2

关闭生成器

def test ():
	print ('0')
	yield 1
	print ('a')
	yield 2
	print ('b')
g = test ()
g.close ()

注意:
1、发现 return 立即终止

def test ():
	print ('0')
	yield 1
	return 10
	print ('a')
	yield 2
	print ('b')
-> 0 1 StopIteration (10)

2、用 for in 会运行所有代码

def test ():
	print ('0')
	yield 1
	print ('a')
	yield 2
	print ('b')
g = test ()
for i in g:
	print (g) -> 0 1 a 2 b (没有报错)
for i in g: -> 第二次没有效果 (只能遍历一次)
	print (g)
递归函数

函数 A 内部再继续调用函数 A

9!
def jiecheng (n)
	if n == 1:
		return 1
	return n * jiecheng (n-1)
jiecheng (9)
函数作用域
命名空间. 函数 ()

image.png
image.png

def fun 1 ():
	global a <-
	a = 6
	def fun 2 ()
		nonlocal a <-
		a=77

全局变量通常命名:g_name

文件使用

打开文件:给文件搭建操作管道(文件句柄)
文件管道 = open (“文件”,“模式”)
f = open ("a.txt","r")
定位位置:定位操作指针
关闭文件:关闭管道
f.close ()
(管道可能有读取、读、写)

打开
f = open ("a.txt","r")
相对路径:相对于当前目录的文件 "a.txt"
模式:
	r: 只读, 不在会报错, 指针在开头 (默认模式)
	w: 只写, 不在会创建, 指针在开头, 覆盖全部
	a: 追写, 不在会创建, 指针在结尾
	添加 b: 二进制格式操作读写
	添加+: 以读写模式打开
		r+: 读写, 不在会报错, 指针在开头, 覆盖部分
1: 图片转移一半
f = open ("a.jpg","rb")
print (f.read ())
f.close
t = open ("new. jpg","wb")
t.write (f.read ()[0: len (f.read ())//2])
t.close ()
读写
定位:
f.seek (偏移量,[0,1,2])
	0: 文件流最前端, 偏移量为 0/正数
	1: 当前指针位置
	2: 文件流末尾, 偏移量为 0/负数
	注: 1/2 只对二进制文件有效 ("rb")
f.tell ()
	查看文件指针位置
读:
f.read (a)
	读取两个字符,默认留空读完
f.readline (a)
	读取一行数据 (带回车)
f.readlines ()
	文件按换行符处理, 处理好的每一行组成列表
	("\n"算作两个字符)
for... in...
	f=open ("a.txt","r")
	for i in f: -> 直接对 f 本身遍历
		print (i)
	g=f.readlines ()
	for i in f: -> 对行列表遍历
		print (i)
f.readable ()
	可读判定, 返回 true
用哪种呢:
	文件大:
		readline 按行加载
		for in 对 f 本身遍历
	文件小:
		用. read (). readlines ()
		(都加载到内存中, 提高速度)
写:
f.write ("abc")
	写入"abc"数据, 返回这个字符串长度
f.writable ()
	可写判断, 返回 true
关闭
f.close ()
	关闭文件,可以释放系统资源
	清空缓冲区的数据内容到磁盘文件
	f.write ()只会写入到缓冲区
f.flush ()
	立即将缓冲区的内容写入到文件中
	并清空缓冲区

文件操作

import os
重命名:
os. rename ("b.txt","bb. txt") #改文件名
os. rename ("aaa","bbb") #改文件夹名
os. renames ("one/one. txt","two/two. txt")
删除:
os. remove ("xx 2. jpg")
	删除文件, 不存在会报错
os. redir ("two")
	不能删除非空目录
os. removedirs ("one/ones")
	递归删除: 连 one 也删除
创建文件夹
os. mkdir ("s")
	创建新文件夹 (只能创建一级目录)
os. mkdir ("s", 0 o 777)
	数字模式权限 (默认八进制 777 对应用户可读可写)
获取当前目录:
os. getcwd ()
修改默认目录:
os. chdir ()
获取目录内容的列表:
os. listdir ("a") #获取a文件夹
os. listdir ("./") #获取所在文件夹
os. listdir ("../") #获取父级文件夹

案例 1:

复制文件到新的文件里
import os
os.chdir("files") 
	重新导航到files文件夹里
source_file = open("d.txt","r",encording="utf-8")
dst_file = open("d-bat.txt","a",encording="utf-8") 
	需要保持编码一致
一起读取:
content = source_file.read()
det_file.write(content)
分段读取:
while True:
	content = source_file.read(1024)
	if len(content)==0:
		break
	print("-----",content)
	dst_file.write(content)
结束:
source_file.close()
dst_file.close()

案例 2:

按照不同的文件后缀分到不同文件夹中
import os
import shutil
path ="files"
if not os.path.exists(path):
	exit()
os.chdir(path)
file_list=os.listdir("./")
for file_name in file_list:
	index = file_name.rfind(".")
	if index == -1:
		continue
	extension = file_name[index + 1:]
	if not os.path.exists(extension):
		不存在目录
		os.mkdir(extension)
	shutil.move(file_name,extension)

案例 3:

列举整个文件目录及所有文件并写入文件
def listFiles(dir,file):
	file_list = os.listdir(dir)
	for file_name in file_list:
		if os.path.isdir(file_name):
			file.write(file_name+"\n")
			listFiles(file_name,file)
		else:
			file.write("\t",file_name)
		file.write("\n")
f = open("list.txt","a")
listFiles("files",f)

核心阶段

经典类
新式类

类名:大驼峰,首字母大写
class Money:
	pass
	变量:可以改变的量值
		不同位置不同访问权限
	属性:属于某个对象的特征
		只能用变量名访问
		属性加到类:类属性
		属性加到对象:对象属性
	判定变量还是属性:
		是否存在宿主
实例化一个对象:
Money()
赋值给一个变量来控制它
one = Money()
print(one)
	 -> object at xxx
one.__class__
	 -> 有一个属性找到对应的类
Money.__name__
	 -> Money类的类名:Money(固定的)
xxx.__name__
	 -> 还是Money

image.png

属性

对象的属性
增加
class Person:
	pass
p=Person()
p.age = 18
	增加一个对象的属性
p.__dict__
	 -> 查看对应的所有属性和值
查询
print(p.age)
	没有这个属性的时候报错
修改
p.age = 18
p.age = 19
	存在就修改,不在就添加
	修改后会重新开辟一个位置并重新指向
p.name=['a','b']
p.name=['c','s']
	修改后会重新开辟一个位置并重新指向
p.name.append('a')
	先访问再追加a,不另外开辟空间
	(查看id确定有无开辟)
删除
对于变量:
num=10
del num
	 -> 报错:未使用的时候是相当于无定义
print(num)
类似的,对于属性:
p.age = 18
del p.age
print(p.age)
类的属性

同一个类的不同对象不能互相访问
万物皆对象,类本身也是一个对象
类是描述对象的
纸的说明书本身也是纸

增加
类名.类属性 = 值
或者:
class hello:
	age = 18
	类属性 = 值
不能通过对象增加
查询
hello.age
也可以通过对象访问属性
也可以修改对象的类:
class a:
	sex=10
class b:
	age=11
c=a()
c.sex
	-> 10
c.__class__=b
c.age
	-> 11
通过对象访问的属性优先从自己身上找
没有再去类身上找
修改
hello.age = 22
类名.属性 = 新值
不能通过对象修改:
对象会认为添加一个新的属性
删除
del 类名.属性
不能通过对象删除
属性的内存存储
class Money:
	pass
one=Money()
one.__dict__={"nkame":"sz"}
	将one的__dict__设置为字典
对象可以修改__dict__属性
实际上属性添加在对象的__dict__属性中
类也有__dict__属性,只不过是不可修改的
限制对象属性
class Person:
	__slots__=["age"]
		 -> 只对象允许添加age属性
	pass
p1=Person()
p2=Person()
方法
class Person:
	def eat2(self):
		print(1)
p=Person()
p.eat2()

对象是由类实例化出来的
此时称:
类 -> 类
对象 -> 实例
类和实例都是 -> 对象

类方法、实例方法、静态方法

实例方法:第一个参数接收实例
类方法:第一个参数接收类
静态方法:第一个参数什么也不接收

class Person:
	def aaa(self):
		print("实例方法")
	@classmethod
	def bbb(cls):
		print("类方法")
	@staticmethod
	def ccc():
		print("静态方法")
p=Person()
p.aaa
	 -> 调用p的实例方法
Person.aaa
	 -> 缺少实例参数self,报错

所有方法都是存在类里面,不是存在对象里
也是存储在类的__dict__字典里面
对应的字典存储方式:{“函数名”:“函数”}

实例方法
class Person:
	def aaa(self):
		print("实例方法")

调用时自动将实例传递到第一个参数里面
其他调用:

func=Person.aaa
func("hello")
	 -> 传递“hello”给self
当作本质函数调用
类方法
class Person:
	@classmethod
	def bbb(cls):
		print("类方法")

调用:
调用时自动将类传递到第一个参数里面

Person.bbb()
p=Person()
p.bbb()
	 -> 都是自动传递类参数

如果时继承的类则传递的是继承的子类

class A(Person):
	pass
A.bbb()
	 -> A类继承了Person类,传递A而不是Person
静态方法
l=[1,4,2,3]
sorted(l)
类方法:
list.sort(l)
实例方法:
l.sort()
如果不想使用类或者实例,则使用静态方法
class Person:
	@staticmethod
	def ccc():
		print("静态方法")

可以使用类或者对象随意访问,不会自动传递第一个参数

不同类型的方法访问变量

实例方法可以访问该实例和对应类的变量
类方法只能访问类的变量,不能访问实例的
静态方法还是可以访问到类的变量的,但是不能访问实例的变量,通常不访问变量

补充
类的补充

类:
创建类对象的类 Type
手动创建类:

def run(self):
	print(self)
xxx = type("Dog",(),{"count":0,"run":run})
类名称是Dog,可以通过xxx来找到这个类

image.png
元类的查询:

Person.__metaclass__
	 -> 查询元类
如果找不到就去父类找元类
没有就去模块找元类
如果还没有就通过type创建元类
__metaclass__ = xxx
class Animal:
	__metaclass__ = xxx
	pass
class Person(Animal):
	__metaclass__ = xxx
	pass

类的说明文档:

class Person:
	"""
	类的描述、作用、构造函数,类的属性描述
	Attributes:
		count:int 代表是人的个数
	"""
	def run(self,distance,step):
		"""
		这个方法的作用效果
		:param distance:参数的含义,参数的类型int,是否有默认值
		:param step:
		:return:返回的结果的含义(时间),返回数据的类型int
		"""
		print("hello")
		return distance
help Person

生成项目文档:
内置模块 pydoc

cmd:
cd 项目路径
python -m pydoc 文件
	 -> 输出 文件.py 的所有注释
python -m pydoc -p 1234
	 -> 在本地电脑开启1234端口
b
	 -> 开启端口情况下输入b
		 可查看所有模块的相关注释文档
q
	 -> 退出本地服务器
python -m pydoc -w

第三方模块
Sphinx epydoc doxygen

属性的补充

私有化属性
只有伪私有的效果

x
	 -> 公有属性
		 类内部访问
		 子类内部访问
		 模块其他位置访问
		 跨模块访问:
			 import形式导入
			 from 模块 import *形式导入

image.png

_y
	 -> 受保护的属性
	  -> 公开访问
		 类内部访问
		 子类内部访问
      -> 强行访问:
		 模块其他位置访问
	  -> 添加__all__=["_a"]
		 跨模块访问
__y
	 -> 私有属性
		 除了类的内部访问
	 -> 添加__all__=["_a"]
		 其他地方都访问不了

伪私有:

Animal._Animal__x
	 -> 可以用来访问私有属性
私有属性的应用场景
class Person:
	初始化对象的私有值
	def __init__(self):
		self.__age=18
		 -> 自动添加属性对象属性age=18
	设置数值的方法
	def setAge(self,value):
		if isinstance(value,int) and 0<value<200:
			self.__age=value
		else:
			print("你输入的数据有问题")
	获取数值的方法
	def getAge(self,value):
		return self.__age
	 -> 实现通过内置方法设置和访问私有值
其他情况
class_
	 -> 取系统的变量名,为了做区分
__class__
	 -> 一般为系统内置的
只读属性
方法 1

部分公开:

私有化禁用读写,再公开读的操作
class Person(object):
	 -> 首先继承object
	def __init__(self):
		self.__age= 18
	 -> 设置为私有属性
	@property
	def age(self):
		return self.__age
	 -> 提供一个方法暴露给外界
		 外界相当于只能通过函数来获取数值
p1=Person()
p1.age
	 -> 直接获取对应的值
p1.age = 19
	 -> 会报错

使用 property 优化

@property
	 -> @property主要作用就是可以以使用属性的方式来使用这个方法
		 可以将一些属性的操作方法关联到某一个属性中
使用函数
class C(object):
	def getx(self): return self._x
	def setx(self, value): self._x = value
	def delx(self): del self._x
	x = property(getx, setx, delx,"I'm the 'x' property.")
使用装饰器
class C(object):
	@property
	def x(self):
		"I am the 'x' property."
		return self._x
	@x. setter
	def x(self,value):
		self._x = value
	@x.deleter
	def x(self):
		del self._x

相关概念:

经典类:没有继承object
新式类:继承object
python2默认不继承,python默认继承
class Person(object):
	pass
Person.__bases__
	 -> 查看父类
建议都写上object保证兼容性

property 在新式类的使用方法:

方法1class erson(object)
	def __init__(self):
		self.__age = 18
	def get_age(self):
		return self.__age
	def set_age(self):
		self.__age = value
	age = property(get_age,set_age)
p=Person()
p.age
	 -> 18
p.age=90
	 -> p.age
class Person(object)
	def __init__(self)
	@property
	def age(self):
		return self.__age
	@age.setter
	def age(self,value):
		self.__age=value
p=Person()
p.age
	 -> 18
p.age = 10
	 -> 可以设置

property 在经典类的使用方法:
只能使用获取方法,其他写入方法、删除方法均无效

方法 2
上面的方法还是可以绕开来访问
p1._Person__age = 999
pq.__dict__["_Person__age"] = 999
class Person:
	def __setattr__(self.key,value):
		print(key,value)
	 -> 当使用 实例.属性 = 值
		 给一个实例增加或修改一个属性都会调用这个方法
		 在这个方法内部才会真正把这个属性以及对应的数据
		 存储到__dict__字典中
		if key=="age" and key in self.__dict__.keys():
			print("是只读属性,不可创建")
		else:
			self.__dict__[key] = value
			(不能用self.key=value,否则会死循环)
	 -> 通过实例.属性=值时调用这个函数判断,不允许添加或修改age属性
内置特殊属性
类属性:
__dict__:类的属性
__base__:类的所有父类组成的元组
__doc__:类的文档字符串
__name__:类名
__module__:类定义所在的模块
私有方法
def __run():
	pass
内置特殊方法
调用操作
class Person:
-
快捷创建:
	def __init_(self,n,a):
		self.name = n
		self.age = a
p1 = Person("sz",18)
	 -> 直接通过对象创建方法创建数值
-
格式化输出对象:
	def __str__(self):
		return "姓名%s,年龄%d"%(self.name,self.age)
print(p1)
	 -> 直接打印对象时会自动找str属性并通过str属性返回值格式化输出
print(str(p1))
	 -> 直接找到p1对象的str属性并打印字符串本身
-
直接获取对象的本质信息
	def __repr__(self):
		print("aaaa")
print(repr(p1))
	 -> 将p1本质信息输出
		 注意:repr后可通过eval还原
-
使对象具备当作函数来调用
	def __call__(self,*args,**kwargs):
		print("xxx")
	pass
p = Person()
p()
	 -> 直接调用__call__方法
-
使用偏函数简化输入参数:
使用函数实现:
	def createPen(p_color,p_type):
		print("颜色%s,类型%s"%(p_color,p_type))
	import functools
	gangbiFunc = functools.partial(createPen,p_type="钢笔")
	gangbiFunc("红色")
		 -> 直接默认类型是钢笔,免去输入钢笔和输入"p_color="
使用类实现:
	class PenFactory:
		def __init__(self,p_type):
			self.p_type = p_type
		def __call__(self,p_color):
			print("类型%s,颜色%s"%(self.p_type,p_color))
	gangbiF = PenFactory("钢笔")
	gangbiF("红色")
索引操作

将实例对象可以以一个字典或以一个列表进行操作

class Person:
	def __init__(self):
		self.cache={}
	def __setitem__(self,key,value):
		self.cache[key]=value
	def __getitem__(self,item):
		return self.cache[item]
	def __delitem__(self,key):
		del self.cache[key]
p = Person()
p["name"]="sz"
print(p["name"])
del p["name"]
切片操作
class Person:
	def _init__(self):
		self.items = [1, 2, 3, 4, 5, 6, 7, 8]
	def __setitem__(self, key, value):
		self.items[key] = value
		或者:
		if isinistance(key,slice):
			self.items[key.start: key.stop: key.step] = value
	def __getitem__(self, item) :
		print("getitem", item)
	def __delitem__(self, key) :
		print("delitem", key)
p=Person()
p[0:4:2]=["a","b"]
	 -> 将对应的第0个和第2个值修改了
		 ["a", 2, "b", 4, 5, 6, 7, 8]
比较操作
class Person:
	def __init_(self,age, height):
		self.age = age
		self.height = height
	def __eq__(self,other):
		return self.age == other.age
p1 = Person(18,190)
p2 = Person(18,180)
print(p1 == p2)...
	 -> = 通过__eq__来判定对象之间是否相同或者不相同,是用的哪个比较
	def __ne__(self,other):
		return self.age != other.age
	 -> !=
	def __gt__(self,other):
		pass
	 -> >
	def __ge__(self,other):
		pass
	 -> >=
	def __lt__(self,other):
		pass
	 -> <
	def __le__(self,other):
		pass
	 -> <=
	如果只定义了一个比较没有定义另一边(反向操作)
		比如定义了p1>p2,而没有定义p1<p2
		则运算p1<p2时仍然会调用p1>p2
		参数会自动调换(self和other调换)
import functools
@functools.total_ordering
class Person:
	def __lt__(self, other):
		pass
	def __eq__(self, other):
		pass
通过导入参数库,当运算>=时自动通过<==来运算(可同时调用参数)
布尔操作
class Person:
	def __init__(self):
		self.age = 10
	def __bool__(self):
		return self.age >=18
	pass
p = Person()
if p:
	print("xx")
	 -> 根据__bool__的返回值判断p为真还是假
遍历操作
方式1:
class Person:
	def __init__(self):
		self.result = 1
	def __getitem__(self):
		self.result += 1
		if self.result >= 6:
			raise StopIteration("停止便利")
		return self.result
	pass
p = Person()
for i in p:
	print(i)
方式2:
class Person:
	def __init__(self):
		self.result = 1
	def __iter__(self):
		self.age = 1 
			->初始化迭代器 
				使其可以重复使用
		return self
	def __next__(self):
		self.result += 1
		if self.result >= 6:
			raise StopIteration("停止便利")
		return self.result
	pass
p = Person()
for i in p:
	print(i)
 -> 相当于首先通过 iter(p) 计算出里面的迭代器
	 本质就是调用这个__iter__来获取
	 之后会使用 next() 来获取下一个数据
注意:
	l=[1,2,3]
	变成迭代器:iter(l)

判断是否为迭代器

import collections
print(isinstance(p,collections.Iterator))
 -> 是否迭代器:只有当都存在 iternext 的时候才是迭代器
print(isinstance(p,collections.Iterable))
 -> 是否可迭代对象:存在 iter 的时候是可迭代的
可迭代一定可以用 for in 访问,for in 访问的不一定可迭代对象
描述器

描述一个属性操作的对象
限制输入的内容

方式1:property
class Person:
	def _init__(self):
		self.__age = 10
	def get_age (self) :
		return self.__age
	def set_age(self, value) :
		if value < 0:
			value = 0
		self.__age = value
p = Person()
p.age = 10
print(p.age)
del p.age
方式2:
class Person:
	def _init__(self):
		self.__age = 10
	def get_age (self) :
		return self.__age
	def set_age(self, value) :
		if value < 0:
			value = 0
		self.__age = value
class Person:
	age = Age()
-
p = Person()
p.age = 10
print(p.age)
del p.age
自动调用Age()中包含的增删改查来实现

不能顺利转换的场景:
一个实例属性的正常访问顺序:
实例对象自身的 dict 字典
对应类对象的,dict 字典
如果有父类, 会再往上层的 dict 字典中检测
如果没找到, 又定义了 getattr 方法, 就会调用这个方法
而在上述的整个过程当中
是如何将描述器的_get__方法给嵌入到查找机制当中?
通过 __getattribute__ 这个方法进行实现
如果实现了描述器方法 get 就会直接调用
如果没有,则按照上面的机制去查找
这个方法当有 get 方法时系统会自动使用这个方法
属性调用优先级:
资料描述器:
实现了 get set
非资料描述器:
只实现了 get
优先级:资料描述器>实例属性>非资料描述器

类的存储问题
class Age(obiect):
	def __get__(self,instance, owner):
		return instance.v
	def __set__(self,instance, value) :
		instance.v=value
	def __delete__(self,instance) :
		del instance.v
 -> instance是Person对象
	 Age对象是共享的
	 只有不同的Person实例才能存储不同的数据
class Person(object):
	age = Age()
p = Person()
p.age = 10
print(p.age)
del p.age

image.png

装饰器
def check(func):
	def inner () :
		print("登录验证")
		func()
	return inner
@check
def fashuoshuo () :
	print("发说说")
fashuoshuo = check(fashuoshuo)
fashuoshuo()
 -> 使用语法糖来装饰器

使用类来实现:

class check:
	def __init__(self, func):
		self.f = func
	def __call__(self,*args, **kwargs):
		print("登录验证")
		self.f()
@check
def fashuoshuo():
	print("发说说")
fashuoshuo = check(fashuoshuo)
fashuoshuo()

生命周期

监听对象的生命周期
class Person:
	def __new__(cls,*args, **kwargs):
		print("新建了一个对象,但是,被我拦截了")
		用于创建对象时给这个对象分配内存的方法
		通过拦截这个方法可以修改对象的创建过程
			比如单例设计模式
	def __init__(self)
		将new方法创建好的对象传递进来
		附加一些东西
		print("初始化方法")
		self.name = "sz"
	def del__(self):
		print("这个对象被释放了“)
	pass
p = Person()
print(p)
案例:计数创建的实例有多少个
class Person:
	__personCount = 0
	def __init__(self) :
		print("计 + 1")
		Person.__personCount += 1
	def __del__(self):
		print("计 - 1")
		self.__class__.__personCount -= 1
	@staticmethod
	def log():
		print("当前的人的个数是%d个" % Person.__personCount)
	或者:
	@classmethod
	def log(cls):
		print("当前的人的个数是%d个" % cls.__personCount)
-
p = Person()
p2 = Person()
del p
Person.log()
内存管理机制
存储方面

无论是什么均属于对象,不存在基本数据类型
所有对象都会在内存开辟一个空间进行存储
对于整数和短小的字符,Python 会进行缓存,不会创建多个相同的对象
容器对象(列表、元组、字典),存储其他对象仅仅是其他对象的引用,而不是其他对象本身

垃圾回收方面
引用计数器

通过被引用数来确定是否应该把他删除

查看被引用数
import sys
sys.getrefcount(对象)
 -> 得出的结果会大1

+1 的情景:
被创建
被引用
被作为参数传入一个函数中 p1=Person()
传入一个函数中会+2 p2=p1
有两个属性引用这个参数
作为一个元素存储在容器中 L=[p1]
-1 的场景:
对象的别名被显式销 del p1
对象的别名被赋予新的对象 p1=123
一个对象离开它的作用域
一个函数执行完毕
对象所在的容器被销毁或从容器中删除

循环引用问题 (内存泄漏

P -> pet pet 被引用+1
D -> master master 被引用+1
pet -> master master 被引用+1
master -> pet pet 被引用+1
删除 P -> pet 、D -> master
此时:
pet -> master master 被引用=1
master -> pet pet 被引用=1
但是已经没有 P、D 可以引用 pet 和 master
导致这些内存已经没有使用但是无法释放
导致内存泄露
image.png

class Person:
	pass
class Dog:
	pass
p = Person()
d = Dog()
p.pet = d
d.master = p
del p
del d
删除 P,d之后,对应的对象无法释放掉
import objgraph
objgraph.count()
	可以查看,垃圾回收期,跟踪的对象个数
objgraph.count("Person")
	垃圾回收器所跟踪的这个Person类所创建的对象
	此时可以使用这个查看是否还有这些剩下的未清理的
	但是仍然无法消除这些

所以 Python 是有两套内存管理机制并存
内存管理机制=引用计数器机制+垃圾回收机制
垃圾回收机制专门用来对付循环应用问题

垃圾回收机制

怎样找到“循环引用”:
1、收集所有的“容器对象”, 通过一个双向链表进行引用
2、针对于每一个“容器对象", 通过一个变量 gc_refs 来记录当前对应的引用计数
3、对于每个"容器对象”,找到它引用的“容器对象", 并将这个"容器对象"的引用计数 -1
4、如果一个"容器对象”的引用计数为 0, 就代表这玩意可以被回收了, 肯定是"循环引用
非容器对象是不能引用其他对象的
垃圾回收机制主要是针对容器对象
image.png
对于一些比较长寿的对象
减少这些对象的“检测频率”
设计了一套机制:分代回收
image.png
代数越高则对应的检测频率越低

垃圾回收时机

自动回收

import gc

image.png
并且达到垃圾回收阈值
手动回收

gc.collect()
	 -> 收集所有的垃圾

在 Python 2 中只要一个对象实现了 del 方法,则不再自动回收
通过手动破坏循环引用:
强引用:能触发引用数自动+1 的引用
弱引用:引用数保持不变

p=Person()
d=Dog()
p.pet=d
d.master=weakref.ref(p)

image.png

import weakref
weakref.WeakValueDictionary("dog":d1)
实例:计算器
class Caculator:
   def __say(self,word):
   	#1 创建一个播报器对象
   	speaker = win32com.client.Dispatch("SAPI.SpVoice")
   			#2,通过这个播报器对象,直接,播放相对应的语音字符串就可以
   	speaker.Speak(word)
   def __create_say_zsq(word=""):
   	def __say_zsq(func):
   		def inner(self, n):
   			self.__say(word + str(n)):
   			return func(self, n)
   		return inner
   	return __say_zsq
   def __check_num_zsq(func):
   	def inner(self, n) :
   		if not isinstance(n, int):
   			raise TypeError("类型有问题")
   		return func(self, n)
   	return inner
   @__check_num_zsq
   @__create_say_zsq
   def __init__(self, num):
   	self.__result = num
   @__check_num_zsq
   @__create_say_zsq("加")
   def jia(self,n):
   	self.__result += n
   	return self
   		 -> 链式编程
   @__check_num_zsq
   @__create_say_zsq("减")
   def jian(self, n):
   	self.__result -= n
   	return self
   @__check_num_zsq
   @__create_say_zsq("乘")
   def cheng(self,n):
   	self.__result *= n
   	return self
   def show(self):
   	self.__say("计算的结果是:%d" % self.__result)
   	print("计算的结果是:%d" % self.__result)
   @property
   def result(self):
   	return self.__result
c1 = Caculator(2)
cl.jia(6)
cl.jian(4)
c1.cheng(5)
c1.show()
c1.result
cl.jia(6).jian(4).cheng(5).show()

语音播报:

import win32com.client
创建一个播报器对象
speaker = win32com.client.Dispatch("SAPI.SpVoice")
通过这个播报器对象,直接播放相对应的语音字符串就可以
speaker.Speak("我的名宇是sz")

面向对象三大特性

封装

1、
image.png
2 、
image.png

继承

1、
image.png
2、
image.png

class Animal:
	pass
class xxx:
	pass
class Dog(Animal,xxx):
	pass

image.png
3、
image.png

资源的继承

不能继承:
私有的属性
私有的方法
可以继承:
公有属性、方法
受保护的属性、方法
内置方法

资源的使用

image.png
Python 2.2 之前:MRO
image.png
1、ABC
2、ABDCE
3、ABDC
Python 2.2:MRO 改进(不是广度优先)
image.png
1、ABC - Object
2、ABDCE - Object
3、ABCD - Object
Python 2.2 之后:Merge 算法
image.png

资源的覆盖

优先级比较高的可以覆盖优先级比较低的
优先级比较高的先被访问,导致其他的无法访问,导致覆盖
可以写一个优先级比较高的来重写
image.png
继承的子类创建的对象使用该子类的对象方法和类方法的时候,调用的类(cls)是该子类,调用的对象(self)是该子类的对象
子类调用父类的方法基础上新增内容
比如在父类的初始化__init__方法基础上再新增一些初始化内容

资源的累加

子类比父类增加自己独有的资源

class B:
	def __init__(self):
		self.b = 2
		self.xxx = "123"
class A:
	def __init__(self):
		B.__init__(self)
			 -> 调用父类的方法
		super (A, self).__init__(self)
			 -> 调用 B 的对象方法则传 self (对象)
				 调用 B 的类方法则传 A()
		super ().__init__()
			 -> 相当于 super (A, self)
			 -> 上面两种 super 不要混合使用
		self. a = 5

image.png
Super 不是上级节点, 而是 MRO 链条的上一个节点

多态

一个类调用时的多种形态
在继承的前提下使用不同的子类调用父类的同一个方法,产生不同的功能
在子类中重写方法
Python 没有真正的多态

补充
抽象类和抽象方法

不能创建实例,不能直接调用

import abc
设置类的元类: abc. ABCMeta
使用装饰器修饰抽象方法:@abc. abstractmethod
class Animal (object, metaclass=abc. ABCMeta):
	@abc. abstractmethod
	def jiao (self):
		pass
	@abc. abstractclassmethod
	def test (cls):
		pass
class Dog (Animal):
	def jiao (self):
		print ("hello")
	def test (self):
		print ("yyy")
抽象类不能直接调用
所有的子类必须实现父类中的所有抽象方法
实例

image.png

class Animal :
	def __init__(self, name, age=1):
		self. name = name
		self. age = age
	def eat (self) :
		print ("%s 在吃饭"% self)
	def play (self):
		print ("%s 在玩"% self)
	def sleep (self):
		print ("%s 在睡觉"% self)
class Person (Animal) :
	def __init__(self, name, pets, age=1):
		super (Person, self).__iit__(name, age)
		self. pets = pets
	def yang-pets (self) :
		for pet in self. pets:
			pet.eat ()
			pet.play ()
			pet.sleep ()
	def make_pets_work (self) :
		for pet in self. pets:
			pet.work ()
	def __str__(self):
		return "名字是{},年龄{}岁的人".format (self. name, self. age)
class Cat (Animal):
	def work (self):
		print ("%s 在提老鼠"% self)
	def __str__(self):
		return "名字是 0,年龄小岁的小猫".format (self. name, self. age)
class Dog (Animal) :
	def work (self):
		print ("%s 在看家”% self)
	def __atr__(self):
		return "名字是{},年龄{}岁的小狗".format (self. name, self. age)
d = Dog ("小黑", 18)
c = cat ("cat", 19)
p = Person ("sz",[d, c], 18)
p.yang_pets ()
p.make_pets_work ()

代码设计原则

S

image.png

O

image.png

L

image.png

I

image.png

D

image.png

后续

包含异常处理和 Python 库与包的安装

  • 25
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值