记录生活中的点点滴滴

0%

Python学习笔记

下学期有Python的课,所以这两天没事就学习了一下 Python,因为有 JavaScript 和 Java 的基础,基础部分一切都很顺利,下面是自己针对自己的情况,总结的Python学习笔记。

Python基本语法

注释

Python中单行注释以 # 开头,多行注释可以用 ‘’’“””

1
2
3
4
5
6
7
8
9
10
11
# 单行注释
"""
多行注释
多行注释
"""
print("hello world!")
print("hello world!")
print("hello world!")
'''
多行注释
'''

行与缩进

python最具特色的就是使用缩进来表示代码块,不需要使用大括号 {} 。

1
2
3
4
5
if 1:
print("111")
print("111")
else:
print('222')

print输出

print 默认输出是换行的,如果要实现不换行需要在变量末尾加上 end=””

1
2
3
4
5
print("不换行",end="")
print("不换行")

# 输出结果:
# 不换行不换行

基本数据类型

变量不需要声明

Python 中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。

在 Python 中,变量就是变量,它没有类型,我们所说的”类型”是变量所指的内存中对象的类型。

1
2
name = 'gsgs' #不需要声明
print(name)

标准数据类型

Python3 中有六个标准的数据类型:

  • Number(数字)
  • String(字符串)
  • List(列表)
  • Tuple(元祖)
  • Set(集合)
  • Dictionary(字典)

不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);

可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。

Number(数字)

Python3 支持 int、float、bool、complex(复数)

内置的 type() 函数可以用来查询变量所指的对象类型。

1
2
3
4
bb = True
cc = 11.2
print(type(bb)) #<class 'bool'>
print(type(cc)) #<class 'float'>

此外还可以用 isinstance 来判断。

1
print(isinstance(bb, int)) #True

isinstance 和 type 的区别在于:

  • type()不会认为子类是一种父类类型。
  • isinstance()会认为子类是一种父类类型。

注意:在 Python2 中是没有布尔型的,它用数字 0 表示 False,用 1 表示 True。到 Python3 中,把 True 和 False 定义成关键字了,但它们的值还是 1 和 0,它们可以和数字相加。

数值运算

数值的除法包含两个运算符:/ 返回一个浮点数,// 返回一个整数。

** 来进行乘方操作

1
2
3
4
5
6
7
8
>>> 2 / 4  # 除法,得到一个浮点数
0.5
>>> 2 // 4 # 除法,得到一个整数
0
>>> 17 % 3 # 取余
2
>>> 2 ** 5 # 乘方
32

String(字符串)

Python中的字符串用单引号 '' 或双引号 "" 括起来,同时使用反斜杠 \ 转义特殊字符。

1
2
3
4
5
6
7
8
9
str = 'Runoob'

print (str) # 输出字符串
print (str[0:-1]) # 输出第一个到倒数第二个的所有字符
print (str[0]) # 输出字符串第一个字符
print (str[2:5]) # 输出从第三个开始到第五个的字符
print (str[2:]) # 输出从第三个开始的后的所有字符
print (str * 2) # 输出字符串两次,也可以写成 print (2 * str)
print (str + "TEST") # 连接字符串

输出结果:

1
2
3
4
5
6
7
Runoob
Runoo
R
noo
noob
RunoobRunoob
RunoobTEST

Python 使用反斜杠 \ 转义特殊字符,如果你不想让反斜杠发生转义,可以在字符串前面添加一个 r,表示原始字符串:

1
2
print('gs\ngs')
print(r'gs\ngs')

输出结果:

1
2
3
gs
gs
gs\ngs

与 C 字符串不同的是,Python 字符串不能被改变。向一个索引位置赋值,比如word[0] = ‘m’会导致错误。

List(列表)

List(列表) 是 Python 中使用最频繁的数据类型。

列表可以完成大多数集合类的数据结构实现。列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套)。

列表是写在方括号 [] 之间、用逗号分隔开的元素列表。

和字符串一样,列表同样可以被索引和截取,列表被截取后返回一个包含所需元素的新列表。

1
2
3
list = ['abcd', 786, 2.23, 'runoob', 70.2]
print(list) #['abcd', 786, 2.23, 'runoob', 70.2]
print(list[1]) #786

与Python字符串不一样的是,列表中的元素是可以改变的:

1
2
list[1] = 111
print(list) #['abcd', 111, 2.23, 'runoob', 70.2]

Python 列表截取可以接收第三个参数,参数作用是截取的步长,以下实例在索引 1 到索引 4 的位置并设置为步长为 2(间隔一个位置)来截取字符串:

1
2
3
4
dd = "h e l l o"
ee = dd.split(" ")
print(ee) #['h', 'e', 'l', 'l', 'o']
print(ee[0:5:2]) #['h', 'l', 'o']

List 内置了有很多方法,例如 append()、pop() 等等,后面再说。

Tuple(元祖)

元组(tuple)与列表类似,不同之处在于元组的元素不能修改。元组写在小括号 () 里,元素之间用逗号隔开。

1
2
3
4
myTuple = ('abcd', 786, 2.23, 'runoob', 70.2)
print(myTuple) #('abcd', 786, 2.23, 'runoob', 70.2)
print(myTuple[1]) #786
myTuple[1] = 111 #会报错:TypeError: 'tuple' object does not support item assignment

元组与字符串类似,可以被索引且下标索引从0开始,-1 为从末尾开始的位置。

其实,可以把字符串看作一种特殊的元组。

虽然tuple的元素不可改变,但它可以包含可变的对象,比如list列表。

Set(集合)

集合(set)是由一个或数个形态各异的大小整体组成的,构成集合的事物或对象称作元素或是成员。

基本功能是进行成员关系测试和删除重复元素。

可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。

创建格式:

1
2
3
parame = {value01,value02,...}
或者
set(value)
1
2
3
sites = {'Google', 'Taobao', 'Runoob', 'Facebook', 'Zhihu', 'Zhihu', 'Baidu'}
print(sites) # 输出集合,重复的元素被自动去掉
# {'Facebook', 'Baidu', 'Zhihu', 'Google', 'Runoob', 'Taobao'}

列表和元祖内的元素可重复 ,但是集合内的元素重复的话会自动删除重复的元素,并且每次输出集合的元素,顺序不一样

成员测试
1
2
3
4
if 'Taobao' in sites:
print('Taobao在集合sites里面')
else:
print('Taobao不在集合sites里面')
集合运算
1
2
3
4
5
6
7
a = set('abracadabra')
b = set('alacazam')

print(a - b) # a 和 b 的差集
print(a | b) # a 和 b 的并集
print(a & b) # a 和 b 的交集
print(a ^ b) # a 和 b 中不同时存在的元素

输出结果:

1
2
3
4
{'d', 'b', 'r'}
{'d', 'm', 'a', 'l', 'z', 'r', 'c', 'b'}
{'c', 'a'}
{'m', 'd', 'l', 'b', 'r', 'z'}

Dictionary(字典)

字典(dictionary)是Python中另一个非常有用的内置数据类型。

列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。

字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合。

键(key)必须使用不可变类型。

在同一个字典中,键(key)必须是唯一的。

1
2
3
4
5
person = {'name': 'zhangsan', 'age': 20, 'email': '123@qq.com'}
print(person)
print(person.keys())
print(person.values())
print(person.get('name'))

输出结果:

1
2
3
4
{'name': 'zhangsan', 'age': 20, 'email': '123@qq.com'}
dict_keys(['name', 'age', 'email'])
dict_values(['zhangsan', 20, '123@qq.com'])
zhangsan

Python数据类型转换

函数 描述
int(x [,base]) 将x转换为一个整数,base为进制数,默认为2
float(x) 将x转换到一个浮点数
complex(real[,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
list(s) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个 (key, value)元组序列。
frozenset(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> float(1)
1.0
>>> int(1.02)
1
>>> eval('1+2')
3
>>> chr(110)
'n'
>>> ord('n')
110
>>> hex(100)
'0x64'
>>> oct(100)
'0o144'

输入和输出

输出

格式符号 转换
%s 字符串
%d 有符号的十进制数
%f 浮点数
%c 字符
%u 无符号的十进制数
%o 八进制整数
%x 十六进制整数(小写ox)
%X 十六进制整数(大写OX)
%e 科学计数法(小写e)
%E 科学计数法(大写E)
%g %f和%e的简写
%G %f和%E的简写

技巧

  • %04d,表示输出的整数为4位,前面不足的用0补全;超出4位,则原样输出
  • %.2f,表示小数点后显示的小数位数
  • 格式化字符串除了%s,还可用 f'{表达式}'
1
2
3
4
5
6
7
8
9
10
name = 'Tom'
age = 10
money = 10.2
id = 1

print("我的名字是:%s" % name)
print("我有 %.2f 元" % money)
print("我的学号是:%04d" % id)

print(f'我的名字是{name},今年{age}岁!')

输出结果:

1
2
3
4
我的名字是:Tom
我有 10.20
我的学号是:0001
我的名字是Tom,今年10岁!

输入

1
2
3
password = input('请输入您的密码:')

print(f'您的密码是:{password}')

  • 一般将input接收的数据存储到变量中
  • input接收的任何数据类型默认都是字符串数据类型

运算符

Python语言支持以下类型的运算符:

  • 算术运算符
  • 比较(关系)运算符
  • 赋值运算符
  • 逻辑运算符
  • 位运算符
  • 成员运算符
  • 身份运算符

算术运算符

运算符 描述 实例
+
-
*
/
% 取余
** 乘方 2 ** 3 = 8
// 取整除,向下接近商的整数 5 // 2 = 2

比较运算符

==!=><>=<=

赋值运算符

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

:= :海象运算符,可在表达式内部为变量赋值。Python3.8 版本新增运算符

位运算符

按位运算符是把数字看作二进制来进行计算的。

先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a = 60  # 60 = 0011 1100
b = 13 # 13 = 0000 1101
c = 0

# 12 = 0000 1100
print("a & b 的值为:", a & b)

# 61 = 0011 1101
print("a | b 的值为:", a | b)

# 49 = 0011 0001
print("a ^ b 的值为:", a ^ b)

# -61 = 1100 0011
print("~a 的值为:", ~a)

# 240 = 1111 0000
print("a << 2 的值为:", a << 2)

# 15 = 0000 1111
print("a >> 2 的值为:", a >> 2)

Python中的按位运算法则如下:

运算符 描述 实例
& 按位与运算符 (a & b) 输出结果 12 ,二进制解释: 0000 1100
| 按位或运算符 (a | b)输出结果 61 ,二进制解释:0011 1101
^ 按位异或运算符 (a ^ b) 输出结果 49 ,二进制解释: 0011 0001
~ 按位取反运算符 (~a ) 输出结果 -61 ,二进制解释: 1100 0011
<< 左移动运算符 a << 2 输出结果 240 ,二进制解释: 1111 0000
>> 右移动运算符 a >> 2 输出结果 15 ,二进制解释: 0000 1111

在python中对一个数进行取反运算,得到的值(1100 0011)是我们要求的数的补码,现在问题变成了 一个数x的补码等于1100 0011 我们要求这个x,x的符号由左边第一位确定,如果为1则为负数,为0则为正数

求一个数的补码,是对这个数取反,再加一,得到原码,1100 0011的补码 0011 1100再加一,得到 0011 1101也就是61,加上负号就是-64

逻辑运算符

Python语言支持逻辑运算符,以下假设变量 a 为 10, b为 20:

运算符 逻辑表达式 描述 实例
and x and y 布尔”与” - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 (a and b) 返回 20
or x or y 布尔”或” - 如果 x 是 True,它返回 x 的值,否则它返回 y 的计算值。 (a or b) 返回 10
not not x 布尔”非” - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 not(a and b)返回False

成员运算符

除了以上的一些运算符之外,Python还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。

运算符 描述 实例
in 如果在指定的序列中找到值返回 True,否则返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。
not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。
1
2
3
myList = [1, 2, 3, 4, 5]
print(1 in myList) #True
print(1 not in myList) #False

身份运算符

身份运算符用于比较两个对象的存储单元

运算符 描述 实例
is is 是判断两个标识符是不是引用自一个对象 x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False
is not is not 是判断两个标识符是不是引用自一个对象 x is not y ,类似 id(a) != id(b)。如果引用的不是同一个对象则返回结果 True,否则返回 False。

注: id() 函数用于获取对象内存地址。

is 与 == 区别:

is 用于判断两个变量引用对象是否为同一个, == 用于判断引用变量的值是否相等。

1
2
3
4
myList1 = [1, 2, 3, 4, 5]
myList2 = [1, 2, 3, 4, 5]
print(myList1 is myList2) #False
print(myList1 == myList2) #True

条件语句

if语句

1
2
3
4
5
6
7
i = 1
if i == 1:
print('hello')
elif i == 2:
print('world')
else:
print('!!')

Python 中用 elif 代替了 else if,所以if语句的关键字为:if – elif – else

注意:

  • 1、每个条件后面要使用冒号 :,表示接下来是满足条件后要执行的语句块。
  • 2、使用缩进来划分语句块,相同缩进数的语句在一起组成一个语句块。
  • 3、在Python中没有switch – case语句。

while语句

求1到100的和

1
2
3
4
5
6
i = 1
sum = 0
while i <= 100:
sum += i
i += 1 #不能使用i++或++i
print(sum)

在 Python 中没有 do..while 循环。

为什么python为什么不能使用 i++ ?

Python 中的可迭代对象/迭代器/生成器提供了非常良好的迭代/遍历用法,能够做到对 i++ 的完全替代。

for语句和range()函数

如果你需要遍历数字序列,可以使用内置range()函数。它会生成数列,例如:

1
2
3
4
5
6
7
8
9
for x in range(6):
print(x, end=" ") #0 1 2 3 4 5
print()
for x in range(1, 6):
print(x, end=" ") #1 2 3 4 5
print()
for x in range(1, 6, 2):
print(x, end=" ") #1 3 5
print()

可以使用range指定区间的值,并指定不同的增量(甚至可以是负数,有时这也叫做’步长’)

字符串

1
2
3
4
5
6
7
8
9
name = 'zhangsan'
words1 = '''I am Tom.
I am 20 years old.'''

words2 = 'I am Tom.\nI am 20 years old.'

print(name)
print(words1)
print(words2)

输出结果:

1
2
3
4
5
zhangsan
I am Tom.
I am 20 years old.
I am Tom.
I am 20 years old.

三引号的字符串支持换行

查找

  • find() : 检测某个子串是否包含在这个字符串中,如果在则返回子串开始的位置下标,否则返回-1

    语法:字符串序列.find(子串 [, 开始位置下标, 结束位置下标])

  • index() : 检测某个子串是否包含在这个字符串中,如果在则返回子串开始的位置下标,否则报异常

    语法和 find() 相同

1
2
3
4
5
6
7
words = 'str : hello world and hello world'
print(words.find('hello')) # 6
print(words.find('hello', 10, 40)) # 22
print(words.find('hello', 10)) # 22
print(words.index('hello')) # 6
print(words.find('ands')) # -1
print(words.index('ands')) # 会报错:ValueError: substring not found
  • rfind() : 和 find() 功能相同,但查找方向从右侧开始

  • rindex() : 和 index() 功能相同,但查找方向从右侧开始

  • count() : 返回某个子串在字符串中出现的次数

    语法:字符串序列.count(子串 [, 开始位置下标, 结束位置下标])

1
2
print(words.count('hello'))  # 2
print(words.rfind('hello')) # 22

修改

  • replace() : 替换

    语法:字符串序列.replace( 旧子串 , 新子串 , [, 替换次数])

    1
    2
    print(words.replace('and', 'ands'))  # str : hello world ands hello world
    print(words) # str : hello world and hello world

    如果替换次数超出,则替换次数为最大可替换次数

    字符串为不可变类型,因此不会修改原字符串

  • split() : 按照指定字符分割字符串

    语法:字符串序列.split( 分割字符 [, num])

    1
    2
    myList = words.split(' ')
    print(myList) # ['str', ':', 'hello', 'world', 'and', 'hello', 'world']
  • join() : 用一个字符或子串合并字符串,即是将多个字符串合并为一个新的字符串

    语法:字符或子串.join(多字符串组成的序列)

    1
    print('-'.join(myList))  # str-:-hello-world-and-hello-world
  • capitalize() : 将字符串第一个字母转换成大写,其他的字符全部小写

  • title() : 将字符串每个单词的首字母转换成大写

  • lower() : 将字符串中的大写转换成小写

  • upper() : 将字符串中的小写转换成大写

  • strip() : 删除字符串两侧空白字符

  • lstrip() : 删除字符串左侧空白字符

  • rstrip() : 删除字符串右侧空白字符

  • center() : 填充字符使原字符居中,默认填充为空格

    语法:字符串序列.cneter( 长度 [, 填充字符])

    1
    2
    str = 'hello'
    print(str.center(10, '.')) # ..hello...
  • ljust() : 填充字符使原字符左对齐,默认填充为空格,语法和 center() 一样

  • rjust() : 填充字符使原字符右对齐,默认填充为空格,语法和 center() 一样

判断

  • startswith() : 检查字符串是否以指定字符串开头
  • endswith() : 检查字符串是否以指定字符串结尾
  • isalpha() : 如果字符串至少有一个字符且所有字符全都是字母返回True,否则False
  • isdigit() : 如果字符串至少有一个字符且所有字符全都是数字返回True,否则False
  • isalnum() : 如果字符串至少有一个字符且所有字符全都是字母或者数字返回True,否则False
  • isspace() : 如果字符串中至包含空白,则返回True,否则返回False

列表

列表的格式:

1
[数据1, 数据2, 数据3, 数据4, ...]

列表可以一次性存储多个数据,且可以为不同的数据类型

查找

下标对应值

1
2
myList = ['Tom', 'Lily', 'Rose', 'Lily']
print(myList[0]) # Tom

函数:

  • index() : 返回指定数据所在位置的下标

    1
    print(myList.index('Lily'))  # 1
  • count() : 统计指定数据在当前列表出现的次数

    1
    print(myList.count('Lily'))  # 2
  • len() : 列表长度

    1
    print(len(myList))   # 4

判断是否存在

  • in : 判断指定数据是否在某个列表序列,若在返回True,否则返回False

  • not in : 判断指定数据是否不在某个列表序列,若不在返回True,否则返回False

    1
    2
    print('Tom' in myList)  # True
    print('Tom' not in myList) # False

增加

作用:增加指定数据到列表中

  • append() : 列表结尾增加数据

    1
    2
    myList.append('xiaoming')
    print(myList) # ['Tom', 'Lily', 'Rose', 'Lily', 'xiaoming']

    注意点:

    如果append增加的是一个序列,则会追加整个序列到列表

    1
    2
    3
    4
    name_list = ['Tom', 'Lily', 'Rose']
    other_list = ['zhangsan', 'lisi']
    name_list.append(other_list)
    print(name_list) # ['Tom', 'Lily', 'Rose', ['zhangsan', 'lisi']]
  • extend() : 列表结尾增加数据,如果末尾增加的是一个序列,则会追加这个序列的数据逐一添加到列表

    1
    2
    3
    4
    name_list = ['Tom', 'Lily', 'Rose']
    other_list = ['zhangsan', 'lisi']
    name_list.extend(other_list)
    print(name_list) # ['Tom', 'Lily', 'Rose', 'zhangsan', 'lisi']
  • insert() : 指定位置新增数据

    1
    2
    3
    name_list = ['Tom', 'Lily', 'Rose']
    name_list.insert(1, 'xiaoming')
    print(name_list) # ['Tom', 'xiaoming', 'Lily', 'Rose']

删除

  • del

    • 删除整个列表

      1
      2
      3
      name_list = ['Tom', 'Lily', 'Rose']
      del name_list
      print(name_list) # 会报错:NameError: name 'name_list' is not defined
    • 删除指定数据

      1
      2
      3
      name_list = ['Tom', 'Lily', 'Rose']
      del name_list[1]
      print(name_list) # ['Tom', 'Rose']
  • pop() : 删除指定下标的数据(默认为最后一个),并返回该数据

    1
    2
    3
    4
    5
    name_list = ['Tom', 'Lily', 'Rose', 'xiaoming']
    name_list.pop()
    print(name_list) # ['Tom', 'Lily', 'Rose']
    name_list.pop(0)
    print(name_list) # ['Lily', 'Rose']
  • remove() : 移除列表中某个数据的第一个配置项

    1
    2
    3
    name_list = ['Tom', 'Lily', 'Rose', 'xiaoming', 'Lily']
    name_list.remove('Lily')
    print(name_list) # ['Tom', 'Rose', 'xiaoming', 'Lily']
  • clear() : 清空列表

    1
    2
    3
    name_list = ['Tom', 'Lily', 'Rose', 'xiaoming', 'Lily']
    name_list.clear()
    print(name_list) # []

修改

  • 修改指定下标元素

    1
    2
    3
    name_list = ['Tom', 'Lily', 'Rose']
    name_list[0] = 'David'
    print(name_list) # ['David', 'Lily', 'Rose']
  • 逆置:reverse()

    1
    2
    3
    name_list = ['Tom', 'Lily', 'Rose']
    name_list.reverse()
    print(name_list) # ['Rose', 'Lily', 'Tom']
  • 排序:sort()

    1
    2
    3
    num_list = [2, 8, 4, 6]
    num_list.sort()
    print(num_list) # [2, 4, 6, 8]

复制

函数:copy()

1
2
3
4
5
6
7
8
9
name_list = ['Tom', 'Lily', 'Rose']
other_list = name_list.copy()
print(name_list == other_list) # True 表示两个变量值相等
print(name_list is other_list) # False 表示两个变量的引用对象不是同一个

name_list = ['Tom', 'Lily', 'Rose']
other_list = name_list
print(name_list == other_list) # True 表示两个变量值相等
print(name_list is other_list) # True 表示两个变量的引用对象是同一个

元祖

一个元祖可以存储多个元素,元祖内的数据是不能修改的

定义元祖

1
2
3
t1 = (10, 20, 30)
print(t1) # (10, 20, 30)
print(t1[2]) # 30

如果定义单个元祖,最好在这个数据后面添加一个 逗号 , ,否则数据类型为唯一的这个数据类型

1
2
3
4
t2 = ('hello')
t3 = ('hello',)
print(type(t2)) # <class 'str'>
print(type(t3)) # <class 'tuple'>

常见操作

  • 按下标查找数据
  • index() : 查找某个数据,返回对应下标,否则报错
  • count() : 统计某个数据在元祖中出现的次数
  • len() : 统计元祖中数据的个数

注意:元祖内数据直接修改会立即报错,如果元祖里有列表,修改列表中的数据则是支持的

1
2
3
4
t5 = ('aa', 'bb', ['cc', 'dd', 'ee'], 'ff')
t5[1] = 'bbbb' # 报错:TypeError: 'tuple' object does not support item assignment
t5[2][1] = 'dddd'
print(t5) # ('aa', 'bb', ['cc', 'dddd', 'ee'], 'ff')

集合

创建集合

创建集合使用 {}set() ,但如果要创建空集合只能使用 set() ,因为 {} 用来创建空字典

1
2
3
4
5
6
7
8
9
10
s1 = {10, 20, 30, 10}
print(s1) # {10, 20, 30}

s2 = set('abcd')
print(s2) # {'a', 'c', 'b', 'd'}

s3 = set()
s4 = {}
print(type(s3)) # <class 'set'>
print(type(s4)) # <class 'dict'>

特点:

  1. 集合可以去掉重复元素
  2. 集合是无序的,所以不支持下标

增加数据

  • add() : 追加数据

    1
    2
    3
    4
    s5 = {10, 20, 30}
    s5.add(40)
    s5.add(10)
    print(s5) # {40, 10, 20, 30}
  • update() : 追加数据,追加的数据必须是序列

    1
    2
    3
    s6 = {10, 20, 30}
    s6.update(['a', 'b', 'c'])
    print(s6) # {10, 'b', 20, 'c', 'a', 30}

删除数据

  • remove() : 删除集合中的指定数据,如果数据不存在则报错

  • discard() : 删除集合中的指定数据,如果数据不存在也不报错

  • pop() : 随机删除集合中的某个数据,并返回这个数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    s7 = {10, 20, 30, 40, 50, 60}
    s7.remove(60)
    print(s7) # {40, 10, 50, 20, 30}
    # s7.remove(70) # 报错:KeyError: 50

    s7.discard(50)
    s7.discard(70) # 不会报错
    print(s7) # {40, 10, 20, 30}

    s7.pop()
    print(s7) # {10, 20, 30}

查找元素

  • in : 判断数据在集合序列
  • not in : 判断数据不在集合序列

字典

字典里面的数据是以键值对形式出现,字典数据和数据顺序没有关系,即字典不支持下标,后期无论数据这怎样变化,只需要按照对应的键的名字查找数据即可

创建字典

1
2
3
4
5
d1 = {'name': 'Tom', 'age': 20, 'gender': '男'}
print(d1) # {'name': 'Tom', 'age': 20, 'gender': '男'}

d2 = {}
d3 = dict()

写法:字典序列[key] = 值

注意:如果key值存在则修改这个key对应的值;如果key值不存在则新增这个键值对

1
2
3
4
d2 = {'name': 'Tom', 'age': 20, 'gender': '男'}
d2['name'] = 'Lily'
d2['id'] = 1
print(d2) # {'name': 'Lily', 'age': 20, 'gender': '男', 'id': 1}

  • del() / del : 删除字典或字典中指定键值对

  • clear() : 清空字典

    1
    2
    3
    4
    5
    d3 = {'name': 'Tom', 'age': 20, 'gender': '男'}
    del d3['age']
    print(d3) # {'name': 'Tom', 'gender': '男'}
    d3.clear()
    print(d3) # {}

增的那一节:字典序列[key] = 值,key值存在则更新,不存在则添加

key值查找

如果当前查找的key值存在,则返回对应的值;否则则报错

1
2
3
d4 = {'name': 'Tom', 'age': 20, 'gender': '男'}
print(d4['name']) # Tom
print(d4['id']) # 报错:KeyError: 'id'
get()

语法:字典序列.get(key [, 默认值])

如果查找的key值不存在,则返回第二个参数默认值,如果没有第二个参数,则返回 None

1
2
3
4
d5 = {'name': 'Tom', 'age': 20, 'gender': '男'}
print(d5.get('gender')) # 男
print(d5.get('id')) # None
print(d5.get('id', 10)) # 10
keys()

以列表返回一个字典所有的键。

1
2
3
d6 = {'name': 'Tom', 'age': 20, 'gender': '男'}
print(d6.keys()) # dict_keys(['name', 'age', 'gender'])
print(type(d6.keys())) # <class 'dict_keys'>
values()

以列表返回一个字典所有的值。

1
2
3
d7 = {'name': 'Tom', 'age': 20, 'gender': '男'}
print(d7.values()) # dict_values(['Tom', 20, '男'])
print(type(d7.values())) # <class 'dict_values'>
items()

以列表返回可遍历的(键, 值) 元组数组。

1
2
3
d8 = {'name': 'Tom', 'age': 20, 'gender': '男'}
print(d8.items()) # dict_items([('name', 'Tom'), ('age', 20), ('gender', '男')])
print(type(d8.items())) # <class 'dict_items'>

遍历

  • 遍历key:dict.keys()

  • 遍历value:dict.values()

  • 遍历元素:dict.items()

  • 遍历键值对:for key, value in dict.items():

    1
    2
    3
    d9 = {'name': 'Tom', 'age': 20, 'gender': '男'}
    for key, value in d9.items():
    print(f'{key} = {value}')

    输出结果:

    1
    2
    3
    name = Tom
    age = 20
    gender =

公共操作

运算符

运算符 描述 支持的容器类型
+ 合并 字符串、列表、元祖
* 复制 字符串、列表、元祖
in 元素是否存在 字符串、列表、元祖、字典
not in 元素是否不存在 字符串、列表、元祖、字典
1
2
3
4
5
6
7
8
9
10
11
str1 = 'Hello'
str2 = 'World'
print(str1 + str2) # HelloWorld

list1 = ['a', 'b', 'c']
list2 = ['d', 'e', 'f']
print(list1 + list2) # ['a', 'b', 'c', 'd', 'e', 'f']

tuple1 = ('a', 'b', 'c')
tuple2 = ('d', 'e', 'f')
print(tuple1 + tuple2) # ('a', 'b', 'c', 'd', 'e', 'f')

公共方法

函数 描述
len() 计算容器中元素个数
del 或 del() 删除
max() 返回容器中元素最大值
min() 返回容器中元素最小值
range(start, end, step) 生成从start到end的数字,步长为step,供for循环使用
enumerate() 函数用于将一个可遍历的数据对象(如列表、元祖或字符串)组成一个索引序列,同时列出数据和数据下标,一般用在for循环中

前面几个都很容易理解,这里重点介绍一下最后一个方法:

1
2
3
4
5
6
7
8
list3 = ['Tom', 'Lily', 'June']
# 普通的for循环
for i in range(len(list3)):
print(str(i) + '->' + list3[i])

# for 循环使用 enumerate
for i, element in enumerate(list3):
print(str(i) + '->' + element)

输出结果都为:

1
2
3
0->Tom
1->Lily
2->June

​ 还可以为enumerate()方法设置start属性:

1
2
3
# enumerate,设置start属性
for i, element in enumerate(list3,start=1):
print(str(i) + '->' + element)

输出结果:

1
2
3
1->Tom
2->Lily
3->June

容器类型转换

  • tuple() : 将某个序列转换成元祖
  • list() : 将某个序列转换成列表
  • set() : 将某个序列转换成集合

注意:

  1. 集合可以快速完成列表去重
  2. 集合不支持下标

推导式

推导式的作用:简化代码

列表推导式

作用:用一个表达式创建一个有规律的列表或控制一个有规律列表

列表推导式又叫列表生成式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 构建一个 0-9 的列表
list1 = [i for i in range(10)]
print(list1) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 构建一个 0-9 的偶数列表
list2 = [i for i in range(0, 10, 2)]
print(list2) # [0, 2, 4, 6, 8]

list3 = [i for i in range(10) if i % 2 == 0]
print(list3) # [0, 2, 4, 6, 8]

# 多个for循环实现列表推导式
list4 = [(i, j) for i in range(1, 4) for j in range(1, 4)]
print(list4) # [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]

字典推导式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建一个字典,key是1-4数字,value是key的平方
dict1 = {i: i*i for i in range(1, 5)}
print(dict1) # {1: 1, 2: 4, 3: 9, 4: 16}

# 将两个列表合并成一个字典
myList1 = ['name', 'age', 'gender']
myList2 = ['Tom', 20, '男']
dict2 = {myList1[i]: myList2[i] for i in range(len(myList1))}
print(dict2) # {'name': 'Tom', 'age': 20, 'gender': '男'}

# 提取字典中的数据
dict3 = {'Mac': 268, 'HP': 120, 'Dell': 160, 'Lenovo': 452}
# 过滤出数量大于200的键值对,并构成一个新字典
dict4 = {key: value for key, value in dict3.items() if value > 200}
print(dict4) # {'Mac': 268, 'Lenovo': 452}

集合推导式

1
2
tuple1 = {i**2 for i in range(1, 5)}
print(tuple1) # {16, 1, 4, 9}

和列表推导式差不多,集合推导式具有去重功能

函数

在Python中,函数必须先定义再使用

1
2
3
4
5
def sum(a, b):
"""求和函数"""
return a + b

print(sum(2, 3)) # 5

参数传递

在Python中,类型属于对象,变量是没有类型的

1
2
a = [1, 2, 3]
a = 'hello'

以上代码中,[1,2,3] 是 List 类型,“hello” 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是 List 类型对象,也可以指向 String 类型对象。

在 Python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

1
2
3
4
5
6
def changeInt(a):
a = 100
return
a = 10
changeInt(a)
print(a) # 10
1
2
3
4
5
6
def changeList(myList):
myList[0] = 'hello'
return
myList = [1, 2, 3]
changeList(myList)
print(myList) # ['hello', 2, 3]

参数

  • 必备参数

    必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。

    调用printStr()函数,你必须传入一个参数,不然会出现语法错误:

    1
    2
    3
    4
    def printStr(str):
    print(str)
    return
    printStr() # 会报错:TypeError: printStr() missing 1 required positional argument: 'str'
  • 关键字参数

    关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。

    使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

    1
    2
    3
    4
    def printInfo(name, age):
    print(f'姓名:{name},年龄:{age}')
    return
    printInfo(age=20, name='Tom') # 姓名:Tom,年龄:20
  • 默认参数

    1
    2
    3
    4
    5
    def printInfo2(name, age = 30):
    print(f'姓名:{name},年龄:{age}')
    return
    printInfo2(name='Tom') # 姓名:Tom,年龄:30
    printInfo2('July', 20) # 姓名:July,年龄:20
  • 不定长参数

    1
    2
    3
    4
    def info(*args):
    print(args)
    return
    info('Tom', 'Lily', 'June') # ('Tom', 'Lily', 'June')

    传递进来的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元祖(tuple)

    1
    2
    3
    4
    def info2(**args):
    print(args)
    return
    info2(name='Tom', age=20) # {'name': 'Tom', 'age': 20}

匿名函数

Python 使用 lambda 来创建匿名函数。

  • lambda只是一个表达式,函数体比def简单很多。
  • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  • lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
  • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
1
2
3
4
5
6
7
8
9
10
11
sum = lambda arg1, arg2: arg1 + arg2
print(sum(10, 20)) # 30

# 更简单的lambda
print((lambda arg1, arg2: arg1 + arg2)(10, 20)) # 30

printPerson = lambda name, age: f'姓名:{name},年龄:{age}'
print(printPerson('Tom', 20)) # 姓名:Tom,年龄:20

# 更简单的lambda
print((lambda name, age: f'姓名:{name},年龄:{age}')('Tom', 20))

体验高阶函数

把函数作为参数传入,这样的函数被称为高阶函数,高阶函数是函数式编程的体现。

需求:一个函数完成任意两个数字的绝对值之和

  • 方法一

    1
    2
    3
    def add_nums1(a, b):
    return abs(a) + abs(b)
    print(add_nums1(10, -10)) # 20
  • 方法二

    1
    2
    3
    def add_nums2(a, b, f):
    return f(a) + f(b)
    print(add_nums2(10, -10, abs)) # 20

明显第二种方法的代码会更加简洁

函数式编程大量使用函数,减少了代码的重复

内置高阶函数

  • map()

    map(func, lst),将传入的函数变量func作用到lst变量的每个元素中,并将结果组成新的列表(Python2)/迭代器(Python3)返回

    需求:计算list1序列中每个数字的平方

    1
    2
    3
    4
    5
    6
    7
    8
    9
    list1 = [1, 2, 3, 4]

    def func(x):
    return x ** 2

    result = map(func, list1)

    print(result) # <map object at 0x000001DEA2123F98>
    print(list(result)) # [1, 4, 9, 16]
  • reduce()

    reduce(func(x, y), lst),其中func必须有两个参数。每次func计算的结果继续和序列的下一个元素做累积运算

    需求:计算list1序列中各个数字的累加和

    1
    2
    3
    4
    5
    6
    7
    8
    import functools

    list2 = [1, 2, 3, 4]
    def func(a, b):
    return a + b

    result = functools.reduce(func,list2)
    print(result) # 10
  • filter()

    filter(func, lst)函数用于过滤序列,过滤掉不符合条件的元素,返回一个filter对象。如果要转换成列表,可以用list() 来转换

    1
    2
    3
    4
    5
    6
    7
    8
    list3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    def func(x):
    return x % 2 ==0

    result = filter(func, list3)

    print(result) # <filter object at 0x000001FC68C7B9B0>
    print(list(result)) # [2, 4, 6, 8, 10]

文件操作

打开文件

open 函数:你必须先用Python内置的open()函数打开一个文件,创建一个file对象,相关的方法才可以调用它进行读写。语法:

1
file object = open(file_name [, access_mode][, buffering])

各个参数的细节如下:

  • file_name:file_name变量是一个包含了你要访问的文件名称的字符串值
  • access_mode:access_mode决定了打开文件的模式:只读,写入,追加等。所有可取值见如下的完全列表。这个参数是非强制的,默认文件访问模式为只读(r)
  • buffering:如果buffering的值被设为0,就不会有寄存。如果buffering的值取1,访问文件时会寄存行。如果将buffering的值设为大于1的整数,表明了这就是的寄存区的缓冲大小。如果取负值,寄存区的缓冲大小则为系统默认

不同模式打开文件的完全列表:

模式 描述
t 文本模式 (默认)。
x 写模式,新建一个文件,如果该文件已存在则会报错。
b 二进制模式。
+ 打开一个文件进行更新(可读可写)。
U 通用换行模式(不推荐)。
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

模式 r r+ w w+ a a+
+ + +
+ + + + +
创建 + + + +
覆盖 + +
指针在开始 + + + +
指针在结尾 + +

File对象的操作

  • close() 方法

    File 对象的 close()方法刷新缓冲区里任何还没写入的信息,并关闭该文件,这之后便不能再进行写入

  • read() 方法

    read()方法从一个打开的文件中读取一个字符串。需要重点注意的是,Python字符串可以是二进制数据,而不是仅仅是文字。

    语法:

    1
    fileObject.read([count])

    在这里,被传递的参数是要从已打开文件中读取的字节计数。该方法从文件的开头开始读入,如果没有传入count,它会尝试尽可能多地读取更多的内容,很可能是直到文件的末尾

  • write() 方法

    write()方法可将任何字符串写入一个打开的文件。需要重点注意的是,Python字符串可以是二进制数据,而不是仅仅是文字

文件定位

  • tell() 方法

    告诉你文件内的当前位置, 换句话说,下一次的读写会发生在文件开头这么多字节之后。

    比如我的 test.txt 文件中就 hello 这五个字节构成的字符串,那么如果以 a 的模式打开这个文件,调用它的 tell() 方法,返回值为:5

    1
    2
    3
    f = open('test.txt', 'a')
    print(f.tell()) # 5
    f.close()
  • seek(offset [,from]) 方法

    改变当前文件的位置。Offset变量表示要移动的字节数。From变量指定开始移动字节的参考位置

    如果from被设为0,这意味着将文件的开头作为移动字节的参考位置。如果设为1,则使用当前的位置作为参考位置。如果它被设为2,那么该文件的末尾将作为参考位置

例:现在我的 test.txt 文件中就 hello world! 这12个字节构成的字符串,以 a+ 的模式打开这个文件

1
2
3
4
5
6
f = open('test.txt', 'a+')
print(f.tell()) # 12
f.seek(2, 0) # 把指针从第12个字节后改变成第2个字节后
print(f.tell()) # 2
print(f.read()) # llo world!
f.close()

重命名和删除文件

Python的os模块提供了帮你执行文件处理操作的方法,比如重命名和删除文件。

rename() 方法需要两个参数,当前的文件名和新文件名。

1
os.rename(current_file_name, new_file_name)

你可以用 remove() 方法删除文件,需要提供要删除的文件名作为参数。

1
os.remove(file_name)

例:把 test1.txt 重命名为 test2.txt ,在将其删除

1
2
3
import os
# os.rename('test1.txt', 'test2.txt')
# os.remove('test2.txt')

目录相关

os模块有许多方法能帮你创建,删除和更改目录。

  • mkdir() 方法

    在当前目录下创建新的目录

  • chdir() 方法

    改变当前的目录

  • getcwd() 方法

    显示当前的工作目录

  • rmdir() 方法

    删除目录

  • listdir() 方法

    列出所有文件,包括文件夹

例:在项目根目录下创建一个 test 的文件夹,并改变当前目录到 test 文件夹下面,输出当前目录,再改变到项目根目录回来,删除这个 test 文件夹

1
2
3
4
5
6
import os
os.mkdir('test') # 创建 test 文件夹
os.chdir('test') # 改变当前目录到 test 文件夹下
print(os.getcwd()) # C:\Users\Lenovo\PycharmProjects\hellopy\test
os.chdir('../') # 改变回来
os.rmdir('test') # 删除 test 文件夹

面向对象——基础

面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟”是一个(is-a)”关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

类的创建

直接先上代码,创建一个 Person 类,有两个属性:nameage

1
2
3
4
5
6
7
8
9
10
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_info(self):
print(f'name: {self.name},age: {self.age}')

p1 = Person('zhangsan', 20)
print(p1)
p1.print_info()

输出结果:

1
2
<__main__.Person object at 0x0000024B6DCDBA20>
name: zhangsan,age: 20

在类的内部,使用 def 关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self ,且为第一个参数

先解释 self 这个词:是指调用该函数的对象,感觉和 Javathis 差不多

__init__ 方法,在创建一个对象时默认调用,不需要手动调用,感觉和 Java 的构造方法差不多

我们还在类中定义了一个 print_info 方法,执行此方法会打印这个对象的相关信息

对象的创建直接用类名创建即可,不用 new 关键字等:p1 = Person('zhangsan', 20) ,创建时这个对象的 name 属性会被赋值为 zhangsanage 属性会被赋值为 20

除了 __init__() 方法,还有 __str__() 方法 和 __del__() 方法

  • __str__() 方法:当使用print输出对象时,默认打印对象的内存地址。如果类定义了 __str__ 方法,那么就会打印从这个方法里 return 的数据

  • __del__() 方法:当删除对象时,python解释器会调用 __del__ 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Person:
    def __init__(self, name, age):
    self.name = name
    self.age = age
    def __str__(self):
    return f'这是一个Person对象,属性name为: {self.name},属性age为: {self.age}.'
    def __del__(self):
    print(f'名字为{self.name}的对象已被删除')

    p1 = Person('zhangsan', 20)
    print(p1)
    del p1

输出结果:

1
2
这是一个Person对象,属性name为: zhangsan,属性age为: 20.
名字为zhangsan的对象已被删除

访问属性

可以使用点号 . 来访问对象的属性。

也可以使用以下函数的方式来访问属性:

  • getattr(obj, name[, default]) : 访问对象的属性。
  • hasattr(obj,name) : 检查是否存在一个属性。
  • setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
  • delattr(obj, name) : 删除属性。

内置类属性

  • __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
  • __doc__ :类的文档字符串
  • __name__: 类名
  • __module__: 类定义所在的模块(类的全名是’main.className’,如果类位于一个导入模块mymod中,那么className.module 等于 mymod)
  • __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
1
2
3
4
5
print(Person.__dict__)
print(Person.__doc__)
print(Person.__name__)
print(Person.__module__)
print(Person.__bases__)

输出结果:

1
2
3
4
5
{'__module__': '__main__', '__doc__': 'Person类', '__init__': <function Person.__init__ at 0x000001798C0689D8>, '__str__': <function Person.__str__ at 0x000001798C068AE8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>}
Person类
Person
__main__
(<class 'object'>,)

面向对象——继承

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。

通过继承创建的新类称为子类派生类,被继承的类称为基类父类超类

1
2
3
4
5
6
7
8
9
10
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

class Student(Person):
pass

c1 = Student('Tom', 20)
print(c1.name) # Tom

还可以继承多个类:

1
2
3
4
5
6
7
8
class A:        # 定义类 A
.....

class B: # 定义类 B
.....

class C(A, B): # 继承类 A 和 B
.....

我们还可以使用issubclass()或者isinstance()方法来检测。

  • issubclass(sub,sup) :布尔函数判断一个类是另一个类的子类或者子孙类
  • isinstance(obj, Class) :布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。
1
2
3
print(issubclass(Student, Person))  # True
print(isinstance(c1, Student)) # True
print(isinstance(c1, Person)) # True

方法重写

如果你的父类方法的功能不能满足你的需求,我们可以在子类重写你父类的方法

类的私有属性和私有方法

类的私有属性

__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs

类的私有方法

__private_method:两个下划线开头,声明该方法为私有方法,不能在类的外部调用。在类的内部调用 self.__private_methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class People:
publicCount = 0
__privateCount = 0
def __init__(self):
self.publicCount += 1
self.__privateCount +=1
def publicMethod(self):
print('publicMethod执行了...')
def __privateMethod(self):
print('__privateMethod执行了...')

p = People()
print(p.publicCount) # 1
# print(p.__privateCount) # 报错:AttributeError: 'People' object has no attribute '__privateCount'

p.publicMethod()
p.__privateMethod() # AttributeError: 'People' object has no attribute '__privateMethod'

单下划线、双下划线、头尾双下划线说明:

  • foo: 定义的是特殊方法,一般是系统定义名字 ,类似 init() 之类的。
  • _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
  • __foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。

类属性和对象属性

类属性就是 类对象 所拥有的属性,它被 该类所有实例对象共有

类属性可以通过 类对象实例对象 访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A:
a = 10
def __init__(self):
self.b = 10
def count(self):
A.a += 1
self.b += 1

a1 = A()
a2 = A()

a1.count()
a2.count()

print(A.a) # 12
print(a1.a) # 12
print(a1.b) # 11
print(a2.a) # 12
print(a2.b) # 11

类方法和静态方法

类方法特点:

  • 第一个形参是类对象的方法
  • 需要使用装饰器 @classmethod 来标识其方法,对于类方法,第一个参数必须是类对象,一般以 cls 作为第一个参数

使用场景:

  • 当方法中 需要使用类对象(如访问私有属性等)时,定义类方法
  • 类方法一般和类属性配合使用
1
2
3
4
5
6
7
8
9
class Dog:
__tooth = 10
@classmethod
def get_tooth(cls):
return cls.__tooth

dog = Dog()
result = dog.get_tooth()
print(result) # 10

静态方法特点:

  • 需要通过装饰器 @staticmethod 来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参也没有self/cls)
  • 静态方法也可以通过 实例对象类对象 去访问

使用场景:

  • 当方法中 既不需要使用实例对象(如实例对象、实例属性),也不需要使用类对象(如类属性、类方法、创建实例等),定义静态方法
  • 取消不需要的参数传递,有利于减少不必要的内存占用和性能消耗
1
2
3
4
5
6
7
8
class Dog:
@staticmethod
def info_print():
print('这是一个狗类')

dog = Dog()
dog.info_print() # 这是一个狗类
Dog.info_print() # 这是一个狗类

异常

异常语法

1
2
3
4
5
6
7
8
try:
可能发生异常的代码
except:
如果出现异常执行的代码
else:
没有异常执行的代码
finally:
无论是否有异常都要执行的代码

实例:

1
2
3
4
5
6
7
8
try:
2/0
except:
print('出现了异常')
else:
print('没有出现异常')
finally:
print('finally代码块执行')

输出结果:

1
2
出现了异常
finally代码块执行

捕获异常

1
2
3
4
5
except 异常类型:
代码

except 异常类型 as xxx:
代码

实例:

1
2
3
4
5
try:
2/0
except Exception as e:
print(e)
print('出现了异常')

输出结果:

1
2
division by zero
出现了异常

自定义异常

在Python中,抛出自定义异常的语法为 raise 异常类对象

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 自定义异常
class 异常类类名(Exception):
代码

# 设置抛出异常的描述信息
def __str__(self):
return ...

# 2. 抛出异常
raise 异常类名()

# 捕获异常
except Exception ...

需求:密码长度不足,则报异常(用户提示输入密码,若不足三位,则报错,即抛出自定义异常,并捕获该异常)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 自定义异常类
class ShortInputError(Exception):
def __init__(self, length, min_len):
self.lenth = length
self.min_len = min_len
# 设置抛出异常的描述信息
def __str__(self):
return f'你输入的长度是{self.lenth},不能少于{self.min_len}个字符'

try:
password = input('请输入密码:')
if (len(password) < 3):
raise ShortInputError(len(password), 3)
except Exception as e:
print(e)
else:
print('密码已经输入完成')

输出结果:

1
2
请输入密码:1
你输入的长度是1,不能少于3个字符
1
2
请输入密码:123
密码已经输入完成

模块和包

Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义 和 Python语句

模块能定义函数,类和变量,模块里也能包含可执行的代码

导入模块

方式:

  • import 模块名
  • from 模块名 import 功能名
  • from 模块名 import *
  • import 模块名 as 别名
  • from 模块名 import 功能名 as 别名
1
2
3
# import 模块名
import math
print(math.sqrt(9)) # 3.0
1
2
3
# from 模块名 import 功能名
from math import sqrt
print(sqrt(9)) # 3.0
1
2
3
# from 模块名 import *
from math import *
print(sqrt(9)) # 3.0
1
2
3
# import 模块名 as 别名
import math as MATH
print(MATH.sqrt(9)) # 3.0
1
2
3
# from 模块名 import 功能名 as 别名
from math import sqrt as SQRT
print(SQRT(9)) # 3.0

制作模块

新建一个 my_module1.py 的文件:

1
2
3
4
5
6
def test1(a, b):
print(a + b)

# 只有在当前文件中才调用该函数,其它导入的文件内不符合条件,则不会执行
if __name__ == '__main__':
test1(10, 20)

另外主函数里面进行调用:

1
2
import my_module1 as m1
m1.test1(1, 3) # 4

__all__

如果一个模块文件中有 __all__ 变量,当使用 from xxx import * 导入时,只能导入这个列表中的元素

my_module1.py 的文件:

1
2
3
4
__all__ = 'test'

def test1(a, b):
print(a + b)

主函数里面代码:

1
2
from my_module1 import *
test1(10, 20)

会报错:

1
2
3
4
Traceback (most recent call last):
File "C:/Users/Lenovo/PycharmProjects/hellopy/模块和包.py", line 20, in <module>
from my_module1 import *
AttributeError: module 'my_module1' has no attribute 't'

导入包

在Python项目根目录中新建 Python Package ,新建包,包内部会自动创建 __init__.py 文件,这个文件控制着包的导入行为

我们新建一个名字为 my_package 的包,里面创建两个模块,模块内代码如下:

1
2
3
# my_module1.py
def test1(a, b):
print(a + b)
1
2
3
# my_module2.py
def test1(a, b):
print(a * b)

导入包的两种方式:

  • import 包名.模块名

    1
    2
    import my_package.my_module1 as m
    m.test1(10, 20) # 30
  • from 包名 import *

    先要在包内的 __init__.py 里面声明:__all__ = ['my_module1'] ,意思是只能导入 my_module1 这个模块包

    1
    2
    3
    from my_package import *
    my_module1.test1(10, 20) # 30
    # my_module2.test2(10, 20) # 编译不能通过