Python学习打卡日记,日期加上学习的主题命名好了~
已经学习完成,接下来只需要将内容整理成方便复习的样子。
1. 基础语法
1.1 变量创建与赋值
1.1.1 变量的类型
- 整形
- 浮点型
- 布尔型
- 字符串型
1.1.2 变量标识符的命名
通俗命名规则:
- 模块和包名:小写
- 函数名:尽量全小写,单词之间用‘_’隔开
- 类名:首字母大写,驼峰原则
- 常量名:全大写,单词之间用‘_’隔开
1.1.3 变量的声明和赋值
删除变量时,只是删除了栈里的,堆里的对象没被删除,最后被Python的垃圾回收器处理掉。
链式赋值:
- x = y = 123
系列解包赋值:
- a, b, c = 1, 2, 3
- a, b = b, a
同一运算符判断:
- is 判断两个标识符是不是引用同一个对象,也即比较ID地址
- == 用于判断引用变量引用对象的值是否相等,也即对比两个堆中的value
- 【-5,256】会缓存这部分数,因此值相等的时候,地址(ID)也是一样
- is 要比 == 效率要高
1.1.4 变量的转换与打印
- round(),去掉小数位
- 时间的获取:time.time()
- 返回值为以秒为单位,小数点后面的单位为微秒
1)格式化字符串
F-String (Python 3.6+)
age = 15
result = f"小明今年{age}岁了!"
print(result)
output:小明今年15岁了!
format()
result = "你好{},小明今年{}岁了!".format(name,age)
output:你好老王,小明今年15岁了!
2)格式化数字
pi = 3.1415926
# 对 pi 进行格式化
# 格式:“:” + “填充、对齐” + “符号” + “宽度” + "." + "位数" + "f"
result = f"圆周率{pi:.4f}是一个无限不循环小数"
# 设置小数点后四位显示
result = f"圆周率{pi:50.4f}是一个无限不循环小数"
# 设置小数点后四位显示 且占50位空间
result = f"圆周率{pi:+50.4f}是一个无限不循环小数"
# 设置小数点后四位显示 且占50位空间 加“+”号
result = f"圆周率{pi:<.4f}是一个无限不循环小数"
# 设置小数点后四位显示 向左对齐
# 向右对齐使用 > 居中显示使用 ^
result = f"圆周率{pi:*<50.4f}是一个无限不循环小数"
# 设置填充,超出实际宽度的部分进行填充,这里是用“*”填充
result = f"圆周率{pi:.2%}是一个无限不循环小数"
# 以百分号形式展示 :.0% 表示不要小数位
result = f"圆周率{pi:#b}是一个无限不循环小数"
# 表示为二进制 :b 加了
#/显示0## 表示为十六进制 :x
1.1.5 变量的逻辑运算符
基本运算符
-
Python不支持自增和自减
-
and:与
-
or:或
-
not:非
-
优先级:常规数学运算,如果优先级错误,直接加小括号
-
/ % //
-
< > = ≥ ≤ == ≠
-
and or not
-
=
-
1.1.6 变量的作用域与拷贝
全局变量:
- 在函数和类定义之外声明的变量
局部变量:
- 函数里定义的变量
- 函数执行完即消失
- 局部变量与全局变量同名时,优先使用局部变量,使用全局变量前声明 global variable
- 局部变量的引用比全局变量快,优先考虑使用
浅拷贝和深拷贝
浅拷贝:
-
不拷贝子对象的内容,只是拷贝子对象的引用
-
拷贝了栈里的变量标识符,并且拷贝了该变量指向的堆里的对象的地址,因此作出的部分更改会
-
copy.copy()
-
只拷贝引用
深拷贝: -
会连子对象的内容也全部拷贝一份,对子对象的修改不会影响源对象
-
拷贝了栈里的变量标识符,拷贝了该变量指向的堆里的对象,并且拷贝了堆里对象所指向的所有子对象
-
copy.deepcopy()
-
全部拷贝到新的内存变量
nonlocal global
- nonlocal 声明外层的局部变量
- global 声明全局变量
LEGB 规则
Python在查找一个名字时,按照该顺序查找:
- Local - Enclosed - Global - Built in
- 局部变量 - 闭包 - 全局变量 - Python保留字
短路现象
指python在执行 或 or 的时候,它在运行到or前为真值的时候,即停止运行后面的代码
1.2 函数创建
1.2.1 基础函数
If 与 Else
- If 是 流程控制语句,用来判断
- 条件满足则执行语句
- 为分支语句,在Python中主要使用冒号与缩进
- Else 是 不满足 If 条件时,执行的备选代码块
- Elif 是 If 的额外判断情况,如果情况比较多的话,建议使用Switch
随机数获取
- 首先导入 Import random
- 生成随机数 random.randint(start, end)
随机整数,rand int
- 这里的上下限都是包含在生成范围内的
画图函数
Range方法
- range(value)
# 生成一个有序整数列表
a = list(range(100))
print(a)
$ [0,1,2,3,...,99]
- range(start, end)
# 设置起始范围与终点范围
a = list(range(3,6))
print(a)
$ [3,4,5]
- range(start,end,step)
# 设置步长
a = list(range(0,100,20))
print(a)$ [0, 20, 40, 60, 80]
For循环及While循环
for item in nums:
<code stock>
while <code stock>:
<code block>
- 调试时,代码当前高亮表示即将被执行
1.2.2 函数用法与底层分析
- 可重用的程序代码块
- 注重逻辑的一致性,也即功能单一
函数大致分为:
- 内置函数
- 标准库函数
- 第三方函数
- 用户自定义
如何创建自定义函数?语法如下:
- def funcName(para1, para2):
- Code block
函数也是一个对象,在def语句后初始化一个对象,对象具有 ID 、 类型 、 值 三要素。因此也同样,初始化后 ID 绑定到函数名,也即标识符上。
- 实参与形参必须一一对应
- 调用前定义函数
- 无参数也必须保留圆括号
- 形式参数无需声明变量类型,也不需要指定返回值类型
1.2.3 形参、实参
形参:
- 在函数定义时,圆括号内自己设置的参数,只在函数执行过程中生效,其余时间失效
- 属于函数,无法被外部调用
- 值需要在调用时,从外部传入
实参:
- 在调用函数时,传递值给函数的变量
- 可以被函数内部调用,但不建议
- 一般只传递值
1.2.4 返回值详解
返回值:调用函数后,返回的值
- 使用return 语句
- 无需预先定义
- 返回的变量类型、数量不受限制
- 调用函数时需要保证有变量接收
- 执行 return 后立马结束函数
1.2.5 函数底层
Python中一切皆对象:
- 函数定义时,系统创建了对应的对象
- 小括号代表调用
- 变量名存在堆里,也叫做函数标识符,函数的ID、值和类型也即函数对象在堆里
- 函数可以作为参数传递,高阶函数的用法
- 函数被调用时,会生成栈帧,stack frame,这里面存放局部变量。
1.2.6 参数的传递
传递可变对象:
- Python中一切皆对象,因此参数的传递都是对象地址的传递
- 可变实参跟形参对应一个对象时,对形参更改后,不创建对象拷贝,直接修改这个对象,因而原本的可变实参也发生对应的变化
传递不可变对象:
- 字符串、数字、元组都是不可变对象
- 传参数时同样是传入对象的地址
- 但因实参不可变,因此在对形参更改时,创建实参的拷贝并执行更改操作
引用的本质,栈内存和堆内存以及内存示意图
- 栈里放变量,对象存放在堆里。
- 对象为上面三类,变量存放的为对象地址。
1.3 内置函数
1.3.1 eval 函数
用法如下:
很有意思的函数,可以用于动态更新代码
递归函数
就是自己调用自己罢了,套娃,但是记得加上终止条件,一般都是迭代条件。
1.3.2 不可变对象包含可变对象
参数的传递:
- 传递不可变对象时为浅拷贝
- 因此当不可变对象中包含可变对象时,对可变对象部分的修改会影响源数据
1.3.3 参数的类型
- 位置参数:根据位置、个数跟参数匹配
- 默认值参数:如果传入参数不足时默认参数使用默认值,默认参数必须放在最后
- 命名参数:在调用函数传参的时候,加上参数的名称,直接赋值
- 可变参数:定义函数时,传入参数可以为可变对象
- 强制命名参数:带星号的’可变参数’后面增加新的参数,必须是 ‘强制命名参数’
1.3.4 lambda 表达式和匿名函数
lambda para1, para2, para3, …:
1.3.5 嵌套函数
- 设置内置嵌套函数可以降低内部重复代码
- 很有意思
第一章完结,第二章为字符串相关。
2. 字符串操作
2.1 字符串
- 字符串不可修改
- 只能复制部分或者增加形成新的字符串
- Python不支持单字符类型,单字符也是作为一个字符串使用的
- Python3直接使用Unicode编码,默认为16位Unicode编码
- 使用内置函数ord()可以把字符转换成对应的Unicode码
- 使用内置函数chr()可以把十进制数字转换成对应的字符
字符串驻留
- 当标识符仅包含下划线、字母和数字时,会启用字符串驻留机制
- 可以节省内存空间
2.2 可变字符串
如确实需要原地修改字符串,使用io.StringIO对象或者array模块
- import io
- str_new = io.StringIO(str)
- str_new.seek(7) # 移动指针到第几个字符的位置
- str_new.write(stringNum) # 写入新的字符串
- .replace(str1, str2) 本质上创建了一个新的字符串,原有的字符串是不可变的
- 对原有的字符串进行更改需要重新进行赋值
- 在对字符串进行拼接时,尽量使用list对象存储,再用.join(),效率相比+好很多
- +号拼接时会生成新的对象
2.3 字符串截取
# 获取字符串中某段字符
string_show = "abcedfghijklmn"
# 截取字符串中第二个与第三个,语法
[start:end:step]string_show[1:3:1]
# 编号从0开始# 字符串倒置
string_show[::-1]
# 查找并替换字符,输出
“abcdffghijklmn”string_show.replace("e","f")
2.4 字符串分割
- str() 可以将其他数据类型转换成字符型
- 使用 [] 提取字符
# .split(string,'code')
string_show = '1,2,3,4,5,6'
a = string_show.split(',')
print(a)
output: [1,2,3,4,5,6]
2.5 字符串方法
- 查找方法
- len()
- .startswith(str) 查看是否以某字符串开头
- .endswith(str) 查看是否以某字符串结尾
- .find(str) 查找字符串第一次出现的index
- .rfind(str) 查找字符串最后一次出现的index
- .count(str) 查找字符串出现的次数
- .isalnum() 所有字符全是字母或数字
- .strip() 去除首尾字符信息,不填的话去掉空格符
- .lower() 将字符串中的字母改为小写
- .upper() 将字符串中的字母改为大写
- .capitalize() 产生新的字符串,首字母大写
- .title() 产生新的字符串,每个单词首字母大写
- .swapcase() 产生新的字符串,大小写转换
- .center(num, str) 以多少个字符显示,填充指定字符,并居中
- .ljust() 同上,左对齐
- .rjust() 同上,右对齐,默认以空格填充
第二章完结,第三章为Python List相关。
3. Python数组操作
3.1 序列介绍
- 序列是一种数据储存方式,一款连续的内存空间
- 常用的序列结构有:字符串、列表、元组、字典、集合
- 列表:可以存储任意类型
- 元组:存储完后,元素不可变
- 集合:不允许出现相同元素
- 字典:存储键值对,键不允许重复
序列也是一个对象,标识符与序列对象的ID相链接;
序列的列表里存储的是地址,也就是值对象的ID;
3.2 List列表和下标
- 列表的下标表示他们的顺序,从 0 开始
- 列表可以使用负数下标,-1表示最后一个
- 对List进行取值,可以使用,注意的是,不包含结尾下标值
a = [1,2,34,5]
# a[start:end:step]
print(a[1:2:1])
output: [1]
- 对 List 对象进行反序
a = [1,2,3,4,5]
# [::-1]
print(a[::-1])
output: [5,4,3,2,1]
# .reverse() 在原List上直接进行了操作
a.reverse()
print(a)
output: [1,2,3,4,5]
- 查找Index
# List查询的语法为下面所示,可以指定查询的开始下标与结束下标
List.index("what do you want to find", start, end)
# 查找a这个list中元素“H”的位置eg:
a = ['a','H','H','v']
print(a.index('H'))
# 从这个例子中可以看出,只返回查询到的第一个下标
output: 1
3.3 List函数方法
- 判断字符是否在 List 中
# in / not in
a = [1,2,3,4,5]
print(4 in a)
output: True
- 使用 len() 得到 List 长度
# len(a)
a = [1,2,3,4,5]
print(len(a))
output: 5
- 使用 + 拼接 List
# +
a,b = [1,2,3],[2,3,4]
print(a+b)
output: [1,2,3,2,3,4]
- 使用 * 重复某个列表
# *
a = [1,2,3] * 3
print(a)
output: [1,2,3,1,2,3,1,2,3]
- 获取最大最小元素,对字符串List使用该方法时,会比较字符串内首个字符的大小进行排序
# max() min()
a = [1,2,3]
print(max(a))
print(min(a))
output: 31
- List 排序
# .sort()
a = [1,3,2,4]
a.sort()
print(a)
output: [1,2,3,4]
- 获取List中某个元素的第一个下标
# .index(value)
a = ['a','b','c','d']
print(a.index('b'))
# 此时有两个'b',返回第一个'b'的下标
output: 1
- 获取某个元素在列表中出现的次数: a.count(“a”)
# .count('code')
a = ['a','b','c','d']
b = a.count('a')
print(b)
output: 1
- List 快速交换 List 中两个位置的值
# a[x],a[y] = a[y],a[x]
a = [1,2,4,3,5]
a[2], a[3] = a[3], a[2]
print(a)
output: [1,2,3,4,5]
- List 连接成为字符串,注意不能包含 数字
# a = ''.join(a),前面的‘’中输入的为分隔符
a = ['1','2','3','4','5']
a = '*'.join(a)
print(a)
output: '1*2*3*4*5'
- .append(value),追加
- .insert(index, value),插入,注意不要去使用负数下标
- .extend([value1, value2, value3]),追加多个元素,形式为列表
# 是否加[],结果完全不一样,对于数字来说,必须要加上[]# 不加[]
a = [1,2,3,4,5]
s = 'hello'
a.extend(s)
print(a)
output: [1,2,3,4,5,'h','e','l','l','o']
# 加[]a = [1,2,3,4,5]
s = 'hello'
a.extend([s])
print(a)
output: [1,2,3,4,5,'hello']
- .pop() 移除 List 最后一个元素,有返回值
- .pop(index) 移除指定 index 位置的元素
- del List[index] 与上述效果相同,移除指定 index 位置的元素
- .remove(value) 移除指定的值,多个重复值时指第一个值
- .clear() 清除列表中所有元素
List 的 Slice 操作
- 跟字符串部分差不多
- [start: end: step]
- 可以是用负数进行检索
List排序
- 原地排序
- .sort(reverse = True) 括号内代表降序
- 打乱顺序
- random.shuffle(List)
- 生成新的列表并排序
- newList = sorted(List)
- List 逆序返回迭代器对象,不对原数组做操作
- reverseObj = reversed(List)
- newList = List(reverseObj)
3.4 List创建与推导式
- 列表推导式:
- 字典推导式,也可以添加 if 语句
- 集合推导式:
- 生成器推导式(返回的是生成器)
- 可迭代对象:也即可以被循环访问
列表的操作
列表的操作
3.5 不可变序列-元组
- 排序只能使用内置的 sorted 生成新的元组
- 将多个 List 连接成为 zip对象,list()处理后,每个元素均为元组对象
- newTuple = zip(ListA, ListB, ListC)
- newList = list(newTuple)
生成器推导式创建元组
- 生成器推导式生成的不是列表也不是元组,而是一个生成器对象
- 语法格式举例: (x for x in range(5))
- 可以使用 .next() 方法对生成器对象进行单个访问
- Tuple: 定义式使用 ()
- 定义时可以不需要括号
# 元组不可修改,不可增删,只能查询值与index
mytuple = (1,2,3)
# 但有index,加减成为新元组
a = 1,2,3,4
b = 3,4,5,6
c = a + b
print(c)
output: 1,2,3,4,3,4,5,6
- 可以使用max(),min()
# 可以使用上述函数得到最大最小值
a = 1,2,3,4,5
max(a)
min(a)
output: 51
- 可以被截取,如[::-1]
# 截取得到的元组是新元组
a = 1,2,3,4
a[::-1]
a[1:3]
output: (4,3,2,1)
(2,3)
- 有 .index() 方法,取得元素在元组里的下标
# 获取元组中元素的下标
a = 1,2,3,4
a.index(value)
output: None
- 元组值可以分别同时赋值给多个元素
# 赋值说明
t = (1,2,3)
a,b,c = t
print(a)
print(b)
print(c)
output: 1
2
3
3.6 字典
- 最简单的为 dictA = {key1: value1, key2: value2}
- dictB = dict(key1 = value1, key2 = value2)
- dictC = dict( [(key1, value1), (key2, value2)] )
- dictD = dict(zip(keyListA, valueListB))
- 可以用 None 创建空值
字典元素的访问
- dict[key]
- .get(key, ‘异常提示’) 不存在则抛出异常 None
- .items() 获得所有键值对
- .keys() / .values()
字典基础
- 创建字典
d = {} # 空字典
d = {key1: value1, key2: value2}
# 字典 Dict 是一种可变容器类型,可以保存任意对象
# 字典中的元素与键值对 key-value 的方式存储
d = {"北京": 22, "上海": 24}
# 字典的 键 必须是 唯一的不能重复
# 字典中的 键 必须是 不可变类型
- 字典的增删改查
# 增加元素
d[key] = valued.update({key: value})
# 删除元素
d.pop(key)d.clear
# 更改元素
d[key] = new_value
# 查找元素
d.get(key, -1)d.setdefault(key, -1)
字典补充
# 字典可以判断某个值是否在key中
dicta = {1:2, 3:4, 5:6}
dicta = dict(key1=value1,key2=value2)
print(if 3 in dicta)$ true
# 如果需要判断某个值是否在value中,需要使用.values()方法
# 字典遍历,字典是可迭代对象# 遍历字典的 key
d = {"小王": 86, "小红": 92, "小明": 85}
for i in d:
print(i) # 小王 小红 小明
print(d[i]) # 86 92 85
# 或者用 .keys() / .values
for i in d.keys():
print(i)
for i in d.values():
print(i)
# 访问字典的键值对 .items()
for i,j in d.items():
print(i) # 键
print(j) # 值
字典实现底层原理
- 字典通过键去查找元素
- 本质上是散列表,也就是稀疏数组(总是含有空白元素),数组的每个单元叫做bucket,每个bucket有两部分,一个是见对象的引用,一个是值对象的引用
- 下面的存储内容只是示例,真实存储的为键对象的地址以及值对象的地址
- 如果存取都是这样的方式,那么效率不仅低的可怕,甚至有些数据都查找不到,以及空间占用太恐怖了吧
- 最好不要同时遍历字典以及执行删除操作,否则可能导致扩容,次序发生变化
3.7 集合
- 无序可变,元素不能重复
- 本质是字典,只有键对象
- 使用
{}
创建对象,使用.add()
添加元素 - 使用
set()
,将列表、元组等可迭代对象转成集合,如果存在重复项,则只保留一个 .remove()
删除指定元素.clear()
清除所有元素- 集合的相关运算
3.8 zip序列解包
- x, y, z = List[1:4]
- a, b, c = dictA # 获得的是键
- 加上 .values() / .items() 可以获得相应的值
使用 zip() 并行迭代
- 就是多重同时访问,用完即停
第三章完结,第四章为Python类相关。
4. Python类
4.1 类对象的定义及属性
使用 “class 类名:”,实际上,当解释器执行 class 语句时,就会创建一个类对象。
- 新建的类是type下面的一个模板
- 类对象贼有意思
4.1.1 类的定义-类和对象的关系
- 对象就像是一个物品
- 类就是制造这个物品的模具
但一切都是对象,因此类本身也是对象
- 类的本质是将行为和状态打包在一起
class Student:
def __init__(self,name,score): # self必须在第一个参数位
self.name = name
self.score = score
def say_score(self): # self必须在第一个参数位
print(f"{self.name}的分数是{self.score}?")
s1 = Student("谁",18)
s1.say_score()s1.age = 32
s1.salary = 35200
print(f"{s1.name}的工资是:{s1.salary},也不大才{s1.age},分数才{s1.score},不知道走了什么狗屎运!")
out:谁的分数是18?谁的工资是:35200,也不大才32,分数才18,不知道走了什么狗屎运!
- 需要注意的是,在init左右两边各有两条下划线,否则会报错。
构造函数 init()
在调用类定义对象时,先执行了__new__()方法创建对象,再执行构造函数__init__()初始化对象。
- 要点为:名称固定,第一个参数必须为self,在类里定义的函数都必须加上self
- 实例属性往往是名称与形参一样
- Python中的 self 相当于C++中的 Self 指针,Java和 C# 中的 this 关键字
4.1.4 类属性
- 类属性属于类,可以被所有实例对象共享
- 在这里类属性 count 被调用了几次取决于初始化过几次
- 栈堆图详解
- 实例对象中只存储实例属性、以及方法的引用地址,类属性与方法的对象都存在类里
私有属性和私有方法
- 需要用 “下划线 类名 下划线 下划线 私有属性” 或者 “下划线 类名 下划线 下划线 私有方法” 调用
- 私有方法在定义的时候,前面加俩下划线
@property 装饰器
将一个方法转为属性调用
4.1.3 实例属性
- 实例属性一般在 构造函数 中定义
- 可以用 对象.实例属性 的方法调用
- self 不需要传参,解释器自己会传参
- dir(Obj) 可以获得对象所有的属性和方法
- pass 空语句
- isinstance(Obj, Class) 判断对象是否属于该类
- 类对象的类型就是 Class type
4.1.5 类方法
- 类方法与实例函数的区别在于,该方法可以被所有实例对象共同调取,也可以被类本身直接调取;
静态方法
与类完全无关的方法,放在类里的函数
del析构函数和垃圾回收机制
上述析构方法,用于实现对象被销毁时所需要的操作,
- 释放对象占用的资源
- python实现自动的垃圾回收,当对象没有被引用时(引用计数为0),由垃圾回收器调用析构函数;
- del 方法本质上是调用析构函数
call方法和可调用对象
- 定义了 call 方法的对象,称为可调用对象,即该对象可以像函数一样被调用。
- 最好带返回值
- 可以直接使用 Obj() 的形式调用
Python中没有方法重载
重载也不是个好东西啊,容易导致效率低下
4.2 面向对象
4.2.1 面向对象与面向过程区别
Python支持面向过程、面向对象、函数式编程,Python中一切皆对象。
面向过程到面向对象,编程思维的转变
4.2.2 面向对象的三大特征
- 封装
- 继承
- 多态
封装
- 隐藏对象的细节,对外只提供必要的方法,将细节封装起来,只对外暴露“相关调用方法”
继承
- 继承可以让子类具有父类的特征,提高代码的重用性
- 设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或改进已有的算法
代码复用的重要手段
-
定义的时候,在小括号里加上父类,可以多重继承
-
继承了父类的所有属性,但不能直接用父类的私有属性
-
如果没有指定父类,那么所有的类的父类都是Object
-
子类初始化范例,通过调用父类的方法进行初始化父类方法的继承与重写
父类的重写比较常见
class Person():
def __init__(self,name,age):
self.name = name
self.age = age
def say_age(self):
print("我就是个无情的测试语句")
class Student(Person):
def __init__(self,name,age):
Person.__init__(self,name,age)
def say_age(self):
print("shwta")s1 = Student("Qiu mouren",22)
s1.say_age()s2 = Person("WoJiuShuo",300)
s2.say_age()
>>>python c:/Users/ZekShawn/Desktop/test.pyshwta
我就是个无情的测试语句
Object 根类
所有的自定义类包含了Object根类的属性
- 类的方法也是属性,只不过方法的类型为method
class A:
pass
class B(A):
pass
class C(B,A):
pass
print(C.mro())
>>>python c:/Users/ZekShawn/Desktop/test.py
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
重写 str 方法
class Person(): # 默认继承根类
def __init__(self,name,age):
self.name = name
self.age = age
def say_age(self):
print("我就是个无情的测试语句")
def __str__(self):
print("测试是否被重写")
return f"Name is {self.name}, and no other message!"
p = Person("swd",22)
print(p)
>>>python c:/Users/ZekShawn/Desktop/test.py
测试是否被重写Name is swd, and no other message!
多重继承
自左往右,如果子类里没有该方法,又被调用时
获得父类定义,直接调用父类方法
4.2.3 类的多态
-
指同一个方法调用由于对象不同产生不同的行为
-
运算符可以重载
重载 + 运算 -
常用函数也可以重载
特殊属性
对于Python中的对象,有一些特殊的属性
示例如下:
class Person(): # 默认继承根类
def __init__(self,name,age):
self.name = name
self.age = age
def say_age(self):
print("我就是个无情的测试语句")
def __str__(self):
print("测试是否被重写")
return f"Name is {self.name}, and no other message!"
class Student(Person):
def __init__(self,name,age):
Person.__init__(self,name,age)
def say_age(self):
super().say_age()
pass
p = Student("swd",22)
p.say_age(
print(p.__dict__)
>>>python c:/Users/ZekShawn/Desktop/test.py
我就是个无情的测试语句{'name': 'swd', 'age': 22}
4.2.4 类的组合
- 组合也可以实现一个类拥有另一个类的方法和属性
- 面向对象可以帮助更好的构建程序的实现逻辑
有时候两者之间存在联系,却不能直接继承,比如下例中的手机与CPU
- 如下图所示,可以将一个对象传入另一个对象的属性
- 接着从其中一个对象属性调用另一个对象的方法
4.3 设计模式
4.3.1 工厂模式
- GOF23种设计模式
- 工厂模式主要实现了创建者和调用者的分离
# 测试工厂模式
# GOF(Group Of Four)23
class CarFactory:
def createCar(self,brand):
if brand == "Benci":
return Benci()
elif brand == "BMD":
return BMD()
elif brand == "BYD":
return BYD()
else:
return "Sorry, there's no this kind of brand!"
class Benci:
pass
class BMD:
pass
class BYD:
pass
factory = CarFactory()
c1 = factory.createCar("Benci")
c2 = factory.createCar("BYD")
print(c1,c2)
>>>python c:/Users/ZekShawn/Desktop/test.py
<__main__.Benci object at 0x000001E6693BA280><__main__.BYD object at 0x000001E6693C3430>
4.3.2 单例模式
核心就是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。
单例模式
# 测试单例模式
# GOF(Group Of Four)23
class mySimple:
__obj = None # 类属性
__init_flag = True
def __new__(cls, *args, **kwargs):
if cls.__obj == None:
cls.__obj = object.__new__(cls)
return cls.__obj
def __init__(self,name):
if mySimple.__init_flag:
self.name = name
mySimple.__init_flag = False
a = mySimple("sw")
b = mySimple("wd")
print(a.name)
print(b.name)
print(a)
print(b)
>>>python c:/Users/ZekShawn/Desktop/test.py
swsw<__main__.mySimple object at 0x0000027D2C4B3610><__main__.mySimple object at 0x0000027D2C4B3610>
工厂模式的工厂对象转化为单例模式
# 测试工厂模式
# GOF(Group Of Four)23
class CarFactory:
__obj = None
__init_flag = True
def createCar(self,brand):
if brand == "Benci":
return Benci()
elif brand == "BMD":
return BMD()
elif brand == "BYD":
return BYD()
else:
return "Sorry, there's no this kind of brand!"
def __new__(cls):
if cls.__obj == None:
cls.__obj = object.__new__(cls)
return cls.__obj
def __init__(self):
if CarFactory.__init_flag:
CarFactory.__init_flag = False
class Benci:
pass
class BMD:
pass
class BYD:
pass
factory1 = CarFactory()
factory2 = CarFactory()
c1 = factory1.createCar("Benci")
c2 = factory2.createCar("BYD")
print(c1,c2)
print(factory1,factory2)
>>>python c:/Users/ZekShawn/Desktop/test.py
<__main__.Benci object at 0x0000027F74493580><__main__.BYD object at 0x0000027F744931F0>
<__main__.CarFactory object at 0x0000027F74493610><__main__.CarFactory object at 0x0000027F74493610>
太棒啦,如果你看了我前面的文章,那么恭喜你,学完Python的入门知识了,加油吧少年。
- 总觉得上面的这段话好中二啊,哈哈哈哈,不过学完了确实很舒服。头疼,走了不少弯路,估计过段时间整理一下我的学习历程分享给电脑这端的你。
评论区