Python纯基础笔记,本人复习Python知识点
1:解释器和编译器
计算机不能直接理解任何机器语言以外的语言,将其它语言翻译成机器语言的工具就叫编译器。
编译器翻译的方式有两种:一是编译,另外一个是解释。两种方式的区别在于翻译时间节点的不同。当编译器以解释方式运行的时候,也称之为解释器。
编译型语言源代码经过编译器,生成最终可执行的文件,交付操作系统,再由操作系统交付给CPU;解释型语言源代码交付解释器,由解释器逐行解释每一句源代码,解释一句执行一句。
编译型语言:程序在执行之前需要有一个专门的编译过程,把程序编译成为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了,程序执行效率高,依赖编译器,跨平台性能差些,速度更快,如C,C++。
解释型语言:解释型语言编写的程序不能进行预先编译,以文本方式存储程序代码,会将代码一句一句直接运行。在运行程序时,必须先解释再运行。解释型语言的跨平台性更好,但速度相对差些。
2:Python特点
1:Python是完全面向对象的语言:
函数、模块、数字、字符串都是对象,在Python中一切皆对象;
完全支持继承、重载、多重继承;
支持重载运算符,也支持泛型设计;
2:Python拥有一个强大的标准库,Python语言的核心只包含数字、字符串、列表、字典文件等常见类型和函数,而由Python标准库提供了系统管理、网络通信、文本处理、数据库接口、图形系统、XML处理等额外功能;
3:Python社区提供了大量第三方模块,使用方式与标准库类似。他们的功能覆盖科学计算、人工智能、机器学习、web开发、数据库接口、 图形系统多个领域。
3:算术运算符
+、-、*、/、//取整除、%取余数、**幂
在Python中,*运算符还可以用于字符串,计算结果就是字符串重复指定次数的结果。如’-’ * 50,输出50个’-’;
同级运算符是从左至右计算;
可以用()调整计算的优先级;
使用交互式方式,如果查看变量内容,直接输入变量名即可,不需要使用print函数;
使用解释器执行,如果输出变量的内容,要用print(变量名);
Python可以根据等号右侧的值,自动推导出变量中存储数据的类型,所以在Python中定义变量时不需要指定类型;
数据类型可以分为数字型和非数字型;
数字型:整型int,浮点型float,布尔型bool(非0即真),复数型complex(主要用于科学计算)
非数字型:字符串string,列表list,元组tuple,字典dict
使用type()函数可以查看一个变量的类型。
不同类型变量之间的计算:
(1)数字型变量之间可以直接计算
如果变量时bool型的,在计算时True对应的数字是1,False对应的数字是0;
(2)字符串变量之间使用’+'拼接字符串,拼接字符串的方法有五种:
"+"号;
直接连接 s= “hello”“world”;
用逗号,连接 print(“hello”, “world”);
格式化字符 s= “%s %s” % (s1, s2);
join函数 s= " “.join([s1, s2]),输出hello world,中间有空格;
标准输出的重定向
(3)字符串变量可以和整数使用”*"重复拼接相同的字符串;
(4)数字型变量和字符串之间不能进行其他计算;
但将数字型变量用str()方法转化为字符串就可进行计算。
s1 = "hello"
n = 20
s = s1 + str(n)
print(s)
# 输出结果为:hello20
V = 12.88
b = True
print(s1 + str(n) + str(V) + str(b))
# 输出结果为:hello2012.88True
或者格式化:
s = "%s %d %.2f" % (s1, n ,V)
# 输出为:hello 20 12.88
4:格式化字符串
格式化字符串 | 含义 |
---|---|
%s | 字符串 |
%d | 有符号十进制整数,%06d表示输出的整数显示6位数,不足的地方用0补齐 |
%f | 浮点数,%.2f表示小数点后只显示两位 |
%% | 输出% |
5:标识符
标识符是程序员定义的变量名、函数名;
标识符可以由字母、下划线和数字组成;
不能以数字开头;
不能与关键字重名;
6:关键字
关键字是在Python内部已经使用的标识符;
import keyword
print(keyword.kwlist)
# 查看Python中的关键字
Python中的标识符是区分大小写的
7:驼峰命名法
小驼峰命名法:第一个单词以小写字母开始,后续单词的首字母大写;
大驼峰命名法:每一个单词的首字母都采用大写字母,如FirstName
8:逻辑运算
逻辑运算符可以把多个条件按照逻辑进行连接,变成更复杂的条件。Python中的逻辑运算符包括:与and/或or/非not三种。
and:两个条件同时满足,返回True,只要有一个不满足,就返回False;
or:两个条件只要有一个满足,返回True,两个条件都不满足,返回False;
not:
a = False
if not a: (这里因为a是False,所以not a就是True,等于if True,所以会输出hello)
print("hello")
random库:random.choice([“剪刀, 石头,布”]),从列表中随机选择一项
random.randint(a, b),返回[a,b]之间的整数,包括a和b
random.randint(20,20),返回结果永远为20
random.randint(20,10),错误写法
9:运算符
算术运算符:+ - * / // % **
比较(关系)运算符 == != > < >= <=
逻辑运算符 and or not
赋值运算符
运算符的优先级
赋值运算符:
赋值运算符 | 实例 |
---|---|
= | c=a+b |
+= | c+=a等价于c=c+a |
-= | c-=a |
*= | c*=a |
/= | c/=a |
//= | c//=a |
%= | c%=a |
**= | c**=a |
运算符的优先级:
由高到低:
**(幂运算符)
* / % // (乘、除、取余数、取整除)
+ - (加减)
<= < >= > (比较运算符)
== != (等于运算符)
= %= /= //= -= += *= **= (赋值运算符)
not and or (逻辑运算符)
循环
程序的三大流程:
顺序–从上向下,顺序执行代码
分支–根据条件判断,决定代码的分支
循环–让特定代码重复执行
除非需求的特殊要求,否则循环的计数都从0开始
break和continue:
break某一条件满足时,退出循环,不再执行后续重复的代码。
continue某一条件满足时,不执行本次循环中的后续代码,只跳过此次循环。
print()函数:
在默认情况下,print函数输出内容之后,会自动在内容末尾增加换行;
如果不希望末尾增加换行,可以在print函数输出内容的后面增加 print(“hello”, end="")
打印九九乘法表代码:
row = 1
while row <= 9:
col = 1 # 每次外部循环开始前,都将col置为1
while col <= row:
print("%d * %d = %d " % (col, row, col*row))
col +=1
print("")
row += 1
字符串中的转义字符:
转义字符 | 描述 |
---|---|
\ | 反斜杠 |
’ | 单引号 |
" | 双引号 |
\n | 换行 |
\t | 横向制表符 |
\t 在控制台输出一个制表符,协助在输出文本时垂直方向保持对齐
\n 在控制台输出一个换行符
函数
函数:把具有独立功能的代码块组织为一个小模块;在需要的时候调用,函数的使用包含两个步骤:
定义函数–封装独立的功能
调用函数–享受封装的成果
函数的作用:在开发程序时,使用函数可以提高编写的效率以及代码的重用
函数名称的命名应该符合标识符的命名规则:
(1)可以由数字、下划线和数字组成
(2)不能以数字开头
(3)不能与关键字重名
函数的文档注释:
在开发中,如果希望给函数添加注释,应该在定义函数的下方,使用连续的三对引号。
**函数的参数:**参数可以增加函数的通用性,针对相同的数据处理逻辑,能够适应更多地数据:
(1)在函数内部,把参数当作变量使用,进行需要的数据处理
(2)函数调用时,按照函数定义的参数顺序,把希望在函数内部处理的数据,通过参数传递
形参和实参:
形参:定义函数时,小括号中的参数,是用来接受参数用的,在函数内部作为变量使用。
实参:调用函数时,小括号中的参数,是用来把数据传递到函数内部用的。
函数的返回值:
在程序开发的时候,会希望一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理。
返回值是函数完成工作后,最后给调用者的一个结果。
在函数中通过return关键字可以返回结果。注意,return表示返回,使用return返回后,return下方的属于这个函数的代码就不会执行了。
**模块:**模块是Python程序架构的一个核心概念:
(1)模块就好比是工具包,要想使用这个工具包中的工具,就需要导入这个模块
(2)每一个以扩展名py结尾的Python源代码文件都是一个模块
(3)在模块定义的全局变量,函数都是模块能够提供给外界直接使用的工具
面试题:
设置Python模块的搜索路径有几种方式:
(1)设置PYTHONPATH环境变量
(2)添加.pth文件
(3)通过sys.path设置路径
(4)如果使用Pycharm,可以直接设置搜索路径
永久设置Python模块搜索路径有几种方式,如何让使用他们:
(1)设置PYTHONPATH环境变量
(2)添加.pth文件
(3)如果使用Pycharm,可以直接设置搜索路径
临时设置Python模块搜索路径有几种方式,如何让使用他们:
(1)通过sys.path设置路径
(2)临时设置PYTHONPATH
模块名也是一个标识符:
(1)标识符可以由字母、下划线和数字组成
(2)不能以数字开头
(3)不能与关键字重名
注意:如果在给Python文件起名时,以数字开头是无法在Pycharm中通过import导入这个模块的
.pyc文件:
(1)浏览程序目录会发现一个__pycache__的目录
(2)目录下会有一个helloworld.cpython-37.pyc文件,cpython-37表示python解释器的版本
(3)这个pyc文件是由Python解释器将模块的源码转换为字节码,Python这样保存字节码是作为一种启动速度的优化
字节码:
(1)Python在解释源程序时是分成两个步骤的:首先处理源代码,编译生成一个二进制字节码;再对二进制字节码进行处理,才会生成CPU能够识别的机器码
(2)有了模块的字节码文件之后,下一次运行程序时,如果上次保存字节码之后没有修改过源代码,Python将会加载.pyc文件并跳过编译这个步骤
(3)当Python重编译时,他会自动检查源文件和字节码文件的时间戳
(4)如果你修改了源代码,下次程序运行时,字节码将自动重新创建
高级变量类型
字符串、列表、元组、字典(非数字型)
在Python中,所有的非数字类型变量都支持以下特点:
(1)都是一个序列sequence,也可以理解为容器
(2)取值[]
(3)遍历for in
(4)计算长度、最大最小值、比较、删除
(5)连接+和重复*
(6)切片
列表:
(1)list列表是Python中使用最频繁的数据类型,在其他语言中通常叫做数组
(2)专门用来存储一串信息
(3)列表用[]定义,数据之间使用, 分隔
(4)列表的索引从0开始,索引就是数据在列表中的位置编号,索引又可以被称为下标
(5)从列表中取值时,如果超出索引范围,程序会报错
列表的增加:
list.insert(索引,数据) # 在指定位置插入数据,若数据是一个列表,则把列表当作整体插入到索引位置处
list.append(数据) # 在末尾追加数据,若数据是一个列表,则把列表当作整体插入到索引位置处
list.extend(列表2) #将列表2的数据追加到list,注意是将列表中的数据追加到list中
列表的修改:
list[0]=数据 # 修改指定索引的数据
列表的删除:
del list[索引] # 删除指定索引的数据
list.remove[数据] # 删除第一个出现的指定数据
list.pop # 删除末尾数据
list.pop[索引] # 删除指定索引的数据
list.clear # 清空列表
列表的统计:
len(list) # 列表长度
list.count(数据) # 数据在列表中出现的次数
列表的排序:
list.sort() # 默认升序排序
list.sort(reverse=True) # 降序排序
list.reverse() # 将列表的元素逆序排列
del关键字:
使用del关键字同样可以删除列表中的元素,del关键字本质上使用来将一个变量从内存中删除的,如果使用del关键字将变量从内存中删除,后续的代码就不能再使用这个变量了。在日常开发中,要从列表中删除数据,建议使用列表本身提供的方法
循环遍历:
遍历就是从头到尾依次从列表中获取数据,在循环体内部针对每一个元素执行相同的操作,在Python中为了提高列表的遍历效率,专门提供的迭代遍历,使用for实现迭代遍历。
循环遍历应用场景:
尽管Python的列表中可以存储不同类型的数据,但是在开发中,更多的应用场景是:
(1)列表存储相同类型的数据
(2)通过迭代遍历,在循环体内部,针对列表中的每一项元素,执行相同的操作
元组:
(1)元组与列表类似;不同之处在于元组的元素不能修改
(2)元组表示多个元素组成的序列
(3)元组在Python开发中,有特定的应用场景
(4)用于存储一串信息,数据之间使用,分隔
(5)元组用()定义
(6)元组的索引从0开始
(7)元组中只包含一个元素时,需要在元素后面添加逗号,tuple = (50, )
元组的常用操作:
tuple.count(数据) # 数据在元组中出现的次数
tuple.index(数据) # 获得数据第一次出现的索引
元组的循环遍历:
(1)取值就是从元组中获取存储在指定位置的数据
(2)遍历就是从头到尾依次从元组中获取数据
(3)在实际开发中,除非能够确认元组中的数据类型,否则针对元组的循环遍历需求并不是很多。
元组的应用场景:
尽管可以使用for in 遍历元组,但是在开发中,更多的应用场景是:
(1)函数的参数和返回值:return a, b这里实际上返回的是元组(a,b)只是可以省略括号,换句话说就是,一个函数可以接收任意多个参数,或者一次返回多个数据。
(2)格式化字符串:格式化字符串后面的()本质上就是一个元组
(3)把列表转化为元组,使列表不可以被修改,保护数据安全
列表与元组之间的转换:
(1)使用list函数可以把元组转换成列表list(元组)
(2)使用tuple函数可以把列表转换成元组tuple(列表)
字典(可修改):
(1)dictionary(字典)是除列表以外Python之中最灵活的数据类型
(2)字典同样可以用来存储多个数据,通常用于存储描述一个物体的相关信息
字典和列表的区别:
(1)列表是有序的对象集合
(2)字典是无序的对象集合
(3)字典用{}定义,列表用[]定义
(4)字典使用键值对存储数据,键值对之间使用,分隔,键key是索引,值value是数据,键和值之间使用 : 分隔,键必须是唯一的,值可以取任何数据类型
(5)len(字典) # 获取字典的键值对数量
(6)dict.keys() # 返回所有key列表
dict.values() # 所有value列表
dict.items() # 所有(key, value)元组列表
dict[key] # 可以从字典中取值,key不存在会报错
dict.get(key) # 可以从字典中取值,key不存在不会报错
del dict[key] # 删除指定的键值对,key不存在会报错
dict.pop(key) # 删除指定的键值对,key不存在会报错
dict.popitem[] # 随机删除一个键值对
dict.clear() # 清空字典
dict[key] = value # key存在,修改数据,key不存在,新建键值对
dict.setdefault(key, value) # key存在,不会修改数据,key不存在,新建键值对
dict.update(字典2) # 将字典2的数据合并到字典1
dict.clear .items .setdefault .copy .keys .update .fromkeys .pop .values .get .popitem
字典应用场景:
(1)尽管可以使用for in 遍历字典,但是在开发中,更多的应用场景是:
(2)使用多个键值对,存储一个物体的相关信息 – 描述更复杂的数据信息
(3)将多个字典放在一个列表中,再进行遍历,在循环体内部针对每一个字典进行相同的处理
card_list = [
{"name":"张三"
"qq":"12345"
"age":18}
{"name":"李四"
"qq":"54321"
"age":19}
]
字符串
(1)字符串就是一串字符,是编程语言中表示文本的数据类型
(2)在Python中可以使用一对双引号""或者一对单引号’'定义一个字符串。若字符串内有字符串,则外层单引号内层双引号或者外层双引号内层单引号
(3)可以使用索引获取一个字符串中指定位置的字符,索引计数从0开始
(4)也可以使用for循环遍历字符串中的每一个字符
(5)len(str)获取字符串的长度,str.count(str1)返回str1在str中出现的次数,str[索引]返回索引位置的单个字符,str.index(str1)返回str1第一次出现的索引
判断类型:
方法 | 说明 |
---|---|
string.isspace() | 如果 string 中只包含空格,则返回 True |
string.isalnum() | 如果 string 至少有一个字符并且所有字符都是字母或数字则返回 True |
string.isalpha() | 如果 string 至少有一个字符并且所有字符都是字母则返回 True |
string.isdecimal() | 如果 string 只包含数字则返回 True全角数字 |
string.isdigit() | 如果 string 只包含数字则返回 True全角数字 、⑴ 、\u00b2 |
string.isnumeric() | 如果 string 只包含数字则返回 True,全角数字 ,汉字数字 |
string.istitle() | 如果 string 是标题化的(每个单词的首字母大写)则返回 True |
string.islower() | 如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True |
string.isupper() | 如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True |
查找和替换:
方法 | 说明 |
---|---|
string.startswith(str) | 检查字符串是否是以 str 开头,是则返回 True |
string.endswith(str) | 检查字符串是否是以 str 结束,是则返回 True |
string.find(str, start=0, end=len(string)) | 检测 str 是否包含在 string 中,如果 start 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回 -1 |
string.rfind(str, start=0, end=len(string)) | 类似于 find(),不过是从右边开始查找 |
string.index(str, start=0, end=len(string)) | 跟 find() 方法类似,不过如果 str 不在 string 会报错 |
string.rindex(str, start=0, end=len(string)) | 类似于 index(),不过是从右边开始 |
string.replace(old_str, new_str, num=string.count(old)) | 把 string 中的 old_str 替换成 new_str,如果 num 指定,则替换不超过 num 次 |
大小写转换:
方法 | 说明 |
---|---|
string.capitalize() | 把字符串的第一个字符大写 |
string.title() | 把字符串的每个单词首字母大写 |
string.lower() | 转换 string 中所有大写字符为小写 |
string.upper() | 转换 string 中的小写字母为大写 |
string.swapcase() | 翻转 string 中的大小写 |
文本对齐:
方法 | 说明 |
---|---|
string.ljust(width) | 返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串 |
string.rjust(width) | 返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串 |
string.center(width) | 返回一个原字符串居中,并使用空格填充至长度 width 的新字符串 |
去除空白字符:
方法 | 说明 |
---|---|
string.lstrip() | 截掉 string 左边(开始)的空白字符 |
string.rstrip() | 截掉 string 右边(末尾)的空白字符 |
string.strip() | 截掉 string 左右两边的空白字符 |
拆分和连接:
方法 | 说明 |
---|---|
string.partition(str) | 把字符串 string 分成一个 3 元素的元组 (str前面, str, str后面) |
string.rpartition(str) | 类似于 partition() 方法,不过是从右边开始查找 |
string.split(str="", num) | 以 str 为分隔符拆分 string,如果 num 有指定值,则仅分隔 num + 1 个子字符串,str 默认包含 ‘\r’, ‘\t’, ‘\n’ 和空格 |
string.splitlines() | 按照行(’\r’, ‘\n’, ‘\r\n’)分隔,返回一个包含各行作为元素的列表 |
string.join(seq) | 以 string 作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串 |
字符串的切片
切片 方法适用于 字符串、列表、元组
- 切片 使用 索引值 来限定范围,从一个大的 字符串 中 切出 小的 字符串
- 列表 和 元组 都是 有序 的集合,都能够 通过索引值 获取到对应的数据
- 字典 是一个 无序 的集合,是使用 键值对 保存数据
- 字符串[开始索引:结束索引:步长]
不包括结束位本身,左闭右开型。 - 从头开始,开始索引数字可以省略,冒号不能省略
- 到末尾结束,结束索引数字可以省略,冒号不能省略
- 步长默认为1,如果连续切片,数字和冒号都可省略
索引的顺序和倒序: - 在Python中不仅支持顺序索引,同时还支持倒序索引,
- 所谓倒序索引就是从右向左计算索引,最右边索引值-1,依次递减,
- 字符串的逆序str[::-1]
- 字符串比较符合以下规则:“0”<“A”<“B”<“a”<“b”
- str[::-2]从右到左,步长为2
运算符
- [1, 2]+[3, 4] = [1, 2, 3, 4] 适用于字符串、列表、元组
- [“hi”]*4=[“hi”,“hi”,“hi”,“hi”] 适用于字符串、列表、元组
- < <= > >= == (1,2,3)<(2,2,3)返回True 适用于字符串、列表、元组
- in 3 in (1,2,3) 返回True,适用于字符串、列表、元组、字典
- not in 4 not in (1,2,3) 返回True
- 注意,in在对字典操作时,判断的是字典的键
- in not in被称作成员运算符
变量进阶
- 引用:变量中记录数据的地址,就叫做引用
- 在Python中,函数的实参和返回值都是靠引用来传递的
可变类型和不可变类型: - 可变类型:内存中的数据可以被修改,如列表、字典
- 不可变类型:内存中的数据不允许被修改,如数字类型、字符串、元组
- 注意:可变类型的数据变化,是通过方法来实现的,如append(),即是通过方法修改变量内容,变量的引用不会改变
- 如果给一个可变类型的变量,赋值了一个新的数据,引用会修改。
- 在Python中,设置字典的键值对时,会首先对key进行hash以决定如何在内存中保存字典的数据,以方便后续对字典的增删改查
- 在函数内部如果需要修改全局变量,需要使用global进行声明
- 在Python中,可以将一个元组使用赋值语句同时赋给多个变量,如 a,b=b,a,其实(b,a)是一个元组
面试题:交换两个数字 - c=b,b=a, a=c
- a=a+b,b=a-b,a=a-b
- Python专用,利用元组:a,b=b,a
面试题:"+=" - 在Python中,列表变量调用"+="本质上是在执行列表变量的extend方法,不会修改变量的引用
- 缺省参数,需要使用最常见的值作为默认值
- 必须保证带有默认值的缺省参数在参数列表末尾,故这样定义是错误的def print_info(name,gender=True,age):
- 调用带有多个缺省参数的函数,需要指定参数名,如def print_info(name,title="",gender=True)
- 在调用时,print_info(“李四”, title=“班长”)
- print_info(“张三”, gender=False)
多值参数:
*args–存放元组参数
**kwargs–存放字典参数
例如:
def demo(num, *args, **kwargs):
pass
demo(1,2,3,4,5,name="李四",age=18,gender=True)
# 其中1是num,2,3,4,5是*args,其余为**kwargs
元组和字典的拆包:
def demo(*args, **kwargs):
gl_nums = (1, 2, 3)
gl_list = {"name":"李四", "age":18}
# 若用demo(gl_nums,gl_list),会把gl_nums和gl_list作为一个元组传递给*args.
# 应该写成这样的格式:demo(*gl_num, **gl_kwargs),这就叫拆包
函数的递归:
在处理不确定的循环条件时,如遍历整个文件目录的结构,格外有用
类
- 类名要求大驼峰命名法
- 类名的确定:名词提炼法分析整个业务流程,出现的名词,通常就是找到的类
- 使用内置函数dir传入标识符/数据,可以查看对象内的所有属性和方法
__方法名__
格式的方法是Python
提供的 内置方法 / 属性
方法名 | 作用 |
---|---|
__new__ | 创建对象时,会被 自动 调用 |
__init__ | 对象被初始化时,会被 自动 调用 |
__del__ | 对象被从内存中销毁前,会被 自动 调用 |
__str__ | 返回对象的描述信息,print 函数输出使用 |
Python定义一个类:
class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self, 参数列表):
pass
- 方法的定义格式和之前学习过的函数几乎一样
- 区别在于方法的第一个参数必须是self,
- 类名的命名规则要符合大驼峰命名法
- 创建对象:对象变量=类名()
- %d可以以十进制输出数字
- %x可以以十六进制输出数字
- 使用self,由哪一个对象调用的方法,方法内的self就是哪一个对象的引用,如tom.eat(),eat方法中的self就是对象tom
- 在封装类的方法内部,self就表示当前调用方法的对象自己
- 调用方法时,程序员不需要传递self参数,即tom.eat()中不用写与形参self对应的实参
- 在方法内部,可以通过self.访问对象的属性,也可以通过self.调用其他的数以同一类的方法
- 在类的外部,通过对象名.访问对象的属性和方法
- 在类封装的方法中,通过self.访问对象的属性和方法
初始化方法
- 当使用类名()创建对象时,会自动执行以下操作:(即自动调用初始化方法)
- 1:为对象在内存中分配空间–创建对象
- 2:为对象的属性设置初始值–调用初始化方法
__init()__
__init()__
方法是专门用来定义一个类具有哪些属性的方法- 在
__init()__
方法内部使用self.属性名=属性的初始值,就可以给定义属性 - 定义属性之后,再使用该类创建的对象都会拥有该属性
class Cat():
def __init__(self, name):
self.name = name
# 注意,右边的name是方法中的形参name,左边的name是真正的属性
__del__
方法:一个对象的__del__
方法一旦被调用,执行完__del__
方法体内的所有语句后描绘将对象从内存删除,生命周期结束__str__
方法:在Python中,使用print输出对象变量,默认情况下,会输出这个变量引用的对象是由哪一个类创建的对象,以及这个对象在内存中的地址(十六进制的地址)- 如果在开发中,希望使用print输出对象变量时,能够打印自定义的内容,就可以利用
__str__
这个内置方法了 - 注意,
__str__
方法必须返回一个字符串,例如:
class Dog():
def __str__(self):
return "必须返回一个字符串"
# 当创建对象tom = Dog(),print(tom)是会调用__str__方法,执行__str__方法中的语句,输出"必须返回一个字符串"
- 在对象方法内部,是可以直接访问对象属性的,属性一般都定义在
__init()__
方法中 - 同一个类创建的多个对象之间,属性互不干扰
- 身份运算符is is not
- 身份运算符用于比较两个对象的内存地址是否一致–是否是对同一个对象的引用
- 在Python中针对None比较时,建议使用is判断
- x is y类似于id(x)==id(y)
- is和==的区别:
- is用于判断两个变量引用对象是否为同一个;
- ==用于判断引用变量的值是否相等
私有属性和私有方法
- 在实际开发中,对象的某些属性或者方法可能只希望在对象的内部被使用,而不希望在外部被访问到
- 在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性和方法,如__age(),__secret(self):
- 单例设计模式:目的是让类创建的对象,在系统中只有唯一的一个对象或者实例
- 每一次执行类名()返回的对象,都是同一个对象,内存地址都是相同的
- 单例设计模式应用场景:音乐播放对象,回收站对象,打印机对象
__new__
方法:使用类名()创建对象时,Python的解释器首先会调用__new__
方法为对象分配空间__new__
方法是一个由object基类提供的内置的静态方法,主要作用有两个:- (1)在内存中为对象分配空间
- (2)返回对象的引用
- Python解释器获得对象的引用后,将引用作为第一个参数,传递给
__init__
方法 - 重写
__new__
方法的代码非常固定,一定要 return super().__new__(cls)
- 否则Python的解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
- 注意:
__new__
方法是一个静态方法,在调用时需要主动传递cls参数,其他方法是self参数,如__init__(self)
Python中的单例
- 单例:让类创建的对象,在系统中只有唯一的一个实例
- (1)定义一个类属性,初始值是None,用于记录单例对象的引用
- (2)重写
__new__
方法 - (3)如果类属性is None,调用父类方法分配空间,并在类属性中记录结果
- (4)返回类属性中记录的对象引用,例如
class MusicPlayer(object):
# 所有的类,如果没有继承父类,都要写上最顶层的父类,基类object
instance = None
# 定义类属性记录单例对象引用
def __new__(cls, *args, **kwargs):
# 判断类属性是否已经被赋值
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
单例模式下实现只执行一次初始化工作:
- 在每次使用类名()创建对象时,Python的解释器都会自动调用两个方法:
__new__
、__init__
- 在上边对
__new__
方法改造之后,每次都会得到第一次被创建对象的引用,但是,初始化方法还会被再次调用 - 需求:让初始化动作只被执行一次
- 解决方法:
- (1)定义一个类属性init_flag标记是否执行过初始化动作,初始值为False
- (2)在
__init__
方法中,判断init_flag,如果为False就执行初始化动作 - (3)然后将init_flag设置为True
- (4)这样,创建新对象调用
__init__
方法时,初始化动作就不会被再次执行了,例如
class MusicPlayer(object):
# 记录第一个被创建对象的引用
instance = None
init_flag = False
def __new__(cls, *args, **kwargs):
# 判断类属性是否为空对象
if cls.instance is None:
# 调用父类的方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self):
if not MusicPlayer.init_flag:
print("初始化音乐播放器")
MusicPlayer.init_flag = True
# 创建多个对象
player1 = MusicPlayer()
player2 = MusicPlayer()
# 只会输出一遍"初始化音乐播放器"
多态
未完待续…