文章目录
Python属于解释性语言
Python解释器将编写的代码编译成二进制文件提供给计算机执行
输出函数print()
-
print()函数可以将内容输出的目的地
-
控制台(显示器)
-
文件
fp=open('D:/text.txt','a+') #a+如果文件不存在就创建,存在就在文件内容的后面继续追加 print('hello world',file=fp) fp.close()
- 所指定的盘符存在
- 使用file=fp
-
-
print()函数的输出形式
保留字
import keyword
print(keyword.kwlist)
变量的定义和使用
变量由三部分组成
- 标识:表示对象所存储的内存地址,使用内置函数
id(obj)
来获取 - 类型:表示对象的数据类型,使用内置函数
type(obj)
来获取 - 值:表示对象所存储的具体数据,使用
print(obj)
可以将值进行打印输出
当多次赋值之后变量名会指向新的空间。(之前的对象若没有任何变量指向它,那么它将会被python垃圾回收机制回收)
数据类型
-
整数类型(
int
)- 十进制(默认)
- 二进制 -> 以
0b
开头 - 八进制 -> 以
0o
开头 - 十六进制 -> 以
0x
开头
-
浮点类型(
float
)-
浮点数存储不精确性
-
使用浮点数进行计算时,可能会出现小数位不确定的情况
print(1.1+2.2) #3.3000000000000003 print(1.1+2.1) #3.2
解决方案:导入模块decimal
from decimal import Decimal print(Decimal('1.1')+Decimal('2.2')) #3.3
-
-
-
布尔类型(
bool
)- True -> 1
- False -> 0
-
字符串类型(
str
)- 字符串又被称为不可变字符序列
- 可以使用单引号
''
双引号""
或三引号'''
"""
来定义 - 单引号和双引号定义的字符串必须在一行
- 三引号定义的字符串可以分布在连续的多行
数据类型的转换
print('我叫' + name + '今年' + age + '岁') #会导致 TypeError: can only concatenate str (not "int") to str 错误
Python不能像 Java 一样直接用连字符
+
将字符串和其他数据类型进行连接,进而将其他数据类型转换为 字符串类型。数据类型转换函数
-
str()
将其他数据类型转成字符串也可以使用引号转换
-
int()
将其他数据类型转换成整数文字类和小数类字符串,无法转换成整数
浮点数转化成整数会直接截取整数位
-
float
将其他数据类型转换成浮点数文字类无法转成整数
整数转成浮点数,末尾为.0
注释
- 单行注释 -> 以
#
开头,直到换行结束 - 多行注释 -> 并没有单独的多行注释标记,将一对三引号
'''
"""
之间的代码称为多行注释 - 中文编码声明注释 -> 在文件的开头加上中文声明注释,用以指定源码文件的编码格式
#coding:gbk/utf-8
input函数
- 作用:接收来自用户的输入
- 返回值类型:输入值的类型为
str
- 值的存储:使用
=
对输入的值进行存储
isOk = input('Are yu ok?')
运算符
算术运算符
- 标准运算符
+ - * /
//(整除)
- 取余运算符
%
- 幂运算符
**
print(9//-4) #-3
print(-9//4) #-3
整除 (一正一负向下取整)
print(9%-4) #-3
print(-9%4) #3
取余 (一正一负要公式) 余数=被除数-除数*商
赋值运算符
-
执行顺序: 右 -> 左
-
支持链式赋值:
a=b=c=20
这种赋值实际上是在内存中创建了一个对象
id:*** type:int value:20
然后将这三个变量都指向这个对象。 -
支持参数赋值:
+= -= *= /= //= %=
-
支持系列解包赋值:
a,b,c = 20,30,40
若变量数与值的个数不匹配 抛出 ValueError: too many values to unpack (expected *) 异常
解包赋值用于变量间的数据交换
a,b,c = 1,2,3 print('交换之前:',a,b,c) a,b,c = b,c,a print('交换之后:',a,b,c) ''' 输出结果: 交换之前: 1 2 3 交换之后: 2 3 1 '''
比较运算符
> < >= <= !=
==
对象value
的比较is is not
对象id
的比较
a = 10 #在内存中创建了一个int类型值为10的对象的地址(引用)赋值给a
b = 10 '''先在内存中找是否存在int类型值为10的对象,若存在则直接将该对象的地址(引用)赋值给变量b,若不存在则创建对象将新创建的对象的地址(引用)复制给变量'''
print(a==b) #True 说明a和b的value相等
print(a is b) #True 说明a和b的id标识相等
print(a is not b)
list1 = [1,2,3,4]#在内存中创建了两个含有相同元素的数组对象
list2 = [1,2,3,4]
print(id(list1),id(list2))#1962441820608 1962441633856
print(list1==list2) #True 说明list1和list2的value相等
print(list1 is list2) #False 说明list1和list2的id标识不相等
print(list1 is not list2)
布尔运算符
-
and or not
类比 Java 的且&&(&) 或||(|) 非!
运算符 -
in not in
print(prev in next) #如果prev是next的子集 返回True 反之返回False
位运算符
- 位与
&
:对应的数位都是1,结果数位才是1,否则为0 - 位或
|
:对应的数位都是0,结果数位才是0,否则为1 - 左移运算符
<<
:高位溢出舍弃,低位补0 - 右移运算符
>>
:低位溢出舍弃,高位补0
print(4<<1) # 每向左移动一位相当于乘以一个2
print(4<<2) #16 向左移动两位,相当于乘2的2次幂
print(4>>1) # 每向右移动一位相当于除以一个2
print(4>>2) #1 向左移动两位,相当于除以2的2次幂
运算符的优先级
程序的组织结构
1996年,计算机科学家证明了这样的事实:任何简单或复杂的算法都可以由顺序结构、选择结构和循环结构这三种基本结构组合而成。
顺序结构
程序从上到下顺序地执行代码,中间没有任何的判断和跳转,知道程序结束。
对象的布尔值
-
Python一切皆对象,所有对象都有一个布尔值
通过内置函数
bool()
获取对象的布尔值 -
以下对象的布尔值为Flase
- False
- 数值()
- None
- 空字符串
- 空列表
- 空元组
- 空字典
- 空集合
print(bool(False)) print(bool(0)) print(bool(0.0)) print(bool(None)) print(bool('')) print(bool("")) print(bool([])) #空列表 print(bool(list())) #空列表 print(bool(())) #空元组 print(bool(tuple())) #空元组 print(bool({})) #空字典 print(bool(dict())) #空字典 print(bool(set())) #空集合
选择结构
程序根据判断条件的布尔值选择性地执行部分代码(明确的让计算机知道在神门掉件下,该去做什么)
单分支结构
语法结构:
if 条件表达式:
条件执行体
'''银行账户取款'''
money = 1000 #余额
withdrawal = int(input('请输入取款金额:')) #取款金额
#判断余额是否充足
if money>=withdrawal:
money -=withdrawal
print('取款成功,余额为: ',money)
双分支结构
语法结构:
if 条件表达式:
条件执行体1
else:
条件执行体2
'''从键盘录入一个整数,编写程序判断录入的数是奇数还是偶数'''
num = int(input('请输入一个整数: '))
#条件判断
if num%2==0:
print(num,'是偶数')
else:
print(num,'是奇数')
多分支结构
语法结构:
if 条件表达式1:
条件执行体1
elif 条件表达式2:
条件执行体2
elif 条件表达式N:
条件执行体N
else:#可选
条件执行体N+1
'''键盘录入一个成绩(整数) 输出相对应的等级 A B C D E'''
score = int(input('请输入一个成绩: '))
#判断
if 90<=score<=100: #score>=90 and score<=100
print('A级')
elif 80<=score<90: #score>=80 and score<90
print('B级')
elif 70<=score<80: #score>=70 and score<80
print('C级')
elif 60<=score<70: #score>=60 and score<70
print('D级')
elif 0<=score<60: #score>=0 and score<60
print('E级')
else:
print('输入的成绩不在有效范围内!')
嵌套if
语法结构:
if 条件表达式:
if 内层条件表达式:
内层条件执行体1
else:
内层条件执行体2
else:
条件执行体
money = float(input('请输入购物金额: '))
answer = input('您是会员吗?y/n')
#外层判断是否为会员
if answer=='y':#会员
if money>=200:
print('付款金额为',money*0.8)
elif money>=100:
print('付款金额为',money*0.9)
else:
print('付款金额为',money)
else:#非会员
if money>=200:
print('付款金额为',money*0.95)
else:
print('付款金额为',money)
条件表达式
语法结构:
x if 判断条件 else y
运算规则:
如果判断条件的布尔值为True,条件表达式的返回值为 x,否则条件表达式的返回值为 y
num = int(input('请输入一个整数: '))
print( str(num)+(' 是偶数' if num%2==0 else ' 是奇数'))
pass语句
语句什么都不做,只是一个占位符,用在语法上需要语句的地方
-
什么时候使用:
先搭建语法结构,还没想好代码怎么写的时候
-
和哪些语句一起使用:
- if 语句的条件执行体
- for-in 语句的循环体
- 定义函数时的函数体
内置函数range()
range()函数
- 用于生成一个整数序列
- 创建range对象的三种方式(默认步长为1)
- range(stop) 创建一个[0,stop)之间的整数序列,步长为 1
- range(start,stop) 创建一个[start,stop)之间的整数序列,步长为 1
- range(start,stop,step) 创建一个[start,stop)之间的整数序列,步长为 step
- 返回值是一个迭代器对象
- range类型的优点:不管range对象表示的整数序列有多长,所有range对象占用的内存空间都是相同的,因为仅仅需要存储start,stop和step,只有当用到range对象时,才会去计算序列中的相关元素
- in 与 not in 判断整数序列中是否存在(不存在)指定的整数
r = range(10)
print(r) #range(0, 10)
print(list(r)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
r = range(1,10)
print(list(r)) #[1, 2, 3, 4, 5, 6, 7, 8, 9]
r = range(1,10,2)
print(list(r)) #[1, 3, 5, 7, 9]
print(9 in r) #True
print(9 not in r) #False
循环结构
反复做同一件事情的情况,称为循环
- 循环的分类
- while
- for -in
while循环
用于次数不固定的循环
语法结构:
while 条件表达式:
条件执行体(循环体)
- while新欢的执行流程
- 初始化变量
- 条件判断
- 条件执行体(循环体)
- 改变变量
'''计算1-100的偶数和'''
sum = 0
i = 1
while i<=100:
if not bool(i%2): #i%2==0
sum += i
i+=1
print('1-100之间的偶数和为',sum)
for-in循环
用于次数固定的循环
- in 表示从(字符串、序列等)中依次取值,又称为遍历
- for-in 遍历的对象必须是可迭代对象
语法结构:
for 自定义变量 in 可迭代对象:
循环体
- 循环体内不需要访问自定义变量时,可以将自定义变量替代为下划线
for item in 'Python': #逐个逐行输出字符串中的字符
print(item)
for i in range(10):
print(i)
for _ in range(5): #打印输出5次字符串
print('anonymous')
sum = 0
for i in range(1,101): #计算1-100的偶数和
if i%2==0:
sum+=i
print('1-100之间的偶数和为',sum)
'''100-999之间的水仙花数'''
for i in range(100,1000):
a = i//100
b = i%100//10
c = i%10
if(a**3+b**3+c**3==i):
print(i,'')
流程控制语句break
用于结束循环结构,通常与分支结构if一起使用
'''银行输入密码(限制最多3次输入)'''
for _ in range(3):#for-in循环实现
password = input('请输入密码: ')
if password=='8888':
print('密码输入正确')
break
else:
print('密码输入不正确!')
a = 0
while a<3:#while循环实现
password = input('请输入密码: ')
if password == '8888':
print('密码输入正确')
break
else:
print('密码输入不正确!')
a+=1
流程控制语句continue
用于结束当前循环,进入下一次循环,通常与分支结构中的if一起使用
与 Java 中 continue用法一致
else语句
与else语句搭配的三种情况:
- if…else… if 条件表达式不成立时执行 else
- while…else…
- for…else… 没有碰到 break 时执行 else
for _ in range(3):
password = input('请输入密码: ')
if password=='8888':
print('密码输入正确')
break
else:
print('密码输入不正确!')
else:
print('对不起,三次输入密码均错误!')
嵌套循环
循环结构中又嵌套了另外网站的循环结构,其中内层循环作为外层的循环体执行
'''打印输出3行4列的矩形'''
for _ in range(3):
for _ in range(4):
print('*',end='\t')
print()
'''打印输出9*9乘法表'''
for i in range(1,10):
for j in range(1,i+1):
print(i,'*',j,'=',i*j,end='\t')
print()
二重循环中的break与continue
二重循环中的break和continue用于控制本层循环
列表
为什么需要列表?
- 变量可以存储一个元素,而列表是一个“大容器”可以存储N多个元素,程序可以方便地对这些数据进行整体操作
- 列表相当于其他语言中的数组
列表的特点
- 列表元素按顺序有序排序
- 索引映射唯一数据
- 列表可以存储重复数据
- 任意数据类型混存
- 根据需要动态分配和回收内存
列表的创建
-
列表需要使用中括号[],元素之间使用英文的逗号进行分隔
-
列表的创建方式
- 使用中括号
lst = ['anonymous','雷军','丁磊','张一鸣']
- 调用内置函数list()
lst = list(['anonymous','雷军','丁磊','张一鸣'])
列表内的每个元素都是一个对象的索引。因为任何类型对象的索引在内存中占用的空间都是一样的,因此列表可以方便的存储任何类型的数据对象并对它们进行相应操作。
- 使用中括号
列表元素的查询操作
-
获取列表中指定元素的索引
index()
- 如果列表中存在N个相同的元素,只返回相同元素中的第一个元素的索引
- 如果查询的元素在列表中不存在,这会抛出
ValueError
- 还可以在指定的start和stop之间进行查找操作
-
获取列表中的单个元素
- 正向索引从 0 到 N-1
- 逆向索引从 -N 到 -1
- 指定索引不存在,抛出
IndexError
-
获取列表中的多个元素
语法格式:
列表名[start:stop:step]
切片操作
- 切片的结果 -> 原始片段的拷贝
- 切片的范围 -> [start,stop)
- step默认为1 -> 简写为
[start:stop]
- step为正数(从start开始往后计算切片)
[:stop:step]
-> 切片的第一个元素默认是列表的第一个元素[start::step]
-> 切片的最后一个元素默认是列表的最后一个元素
- step为负数(从start开始往前计算切片)
[:stop:step]
-> 切片的第一个元素默认是列表的最后一个元素[start::step]
-> 切片的最后一个元素默认是列表的第一个元素
列表元素的增加操作
append()
在列表的末尾添加一个元素extend()
在列表的末尾至少添加一个元素insert()
在列表的任意位置添加一个元素- 切片 在列表的任意位置添加至少一个元素
列表元素的删除操作
remove()
- 一次删除一个元素
- 重复元素只删除第一个
- 元素不存在 抛出
ValueError
异常
pop()
- 删除一个指定索引位置上的元素
- 指定索版不存在 抛出
IndexError
异常 - 不指定索引,删除列表中最后一个元素
- 切片 一次至少删除一个元素
clear()
请空列表del
删除列表
列表元素的修改操作
- 为指定索引的元素赋予一个新值
- 为指定的切片赋予一个新值
列表的排序操作
- 常见的两种排序方式
- 调用
sort()
方法,列表中的所有元素默认按照从小到大的顺序排序,可以指定 reverse = True,进行降序排序 - 调用内置函数
sorted()
,可以指定 reverse = True,进行降序排序,原列表不发生改变
- 调用
列表生成式
列表生成式简称“列表生成公式”
语法格式:
[表示列表元素的表达式 for 自定义变量 in 可迭代对象];
# [i*i for i range(1,10)]
注意事项:”表示列表元素的表达式“中通常包含自定义变量
字典
-
Python内置的数据结构之一,与列表一样是个可变序列
-
以键值对的方式存储数据,字典是一个无序的序列
-
字典是实现原理
-
字典是实现原理与查字典类似,查字典是先根据部首或拼音查找相应的页码,Python的字典是根据 key 查找 value 所在的位置
通过
hash
函数来根据 key 获取 value 所在的位置
-
字典的创建
- 使用花括号(最常用的常见方式)
scores = {'anongymous':100,'雷军':100,'张一鸣':99}
- 使用内置函数
dict()
dict(name='anonymous',age=20)
字典的常用操作
-
字典元素的获取
-
[]
scores['雷军']
-
get()方法
scores.get(雷军)
[]
取值与使用get()
取值的区别[]
如果字典中不存在指定的key,抛出KeyError
异常- get() 方法取值,如果字典中不存在指定的 key,并不会抛出
KeyError
而是返回None
,可以通过参数设置默认的 value,以便指定的 key 不存在时返回scores.get('丁磊',99)
-
-
key 的判断
in
指定的key
在字典中存在 返回True
反之 返回False
not in
指定的key
在字典中不存在 返回True
反之 返回False
-
字典元素的删除
del scores['anonynmous']
-
字典元素的新增
scores['Jack']=90
-
获取字典视图
keys()
获取字典中所有 keyvalues()
获取字典中所有 valueitems
获取字典中所有 key,value 对
scores = {'anonymous':100,'雷军':100,'张一鸣':99} keys = scores.keys() print(type(keys)) # <class 'dict_keys'> print(keys) # dict_keys(['anonymous', '雷军', '张一鸣']) print(list(keys)) # ['anonymous', '雷军', '张一鸣'] values = scores.values() # <class 'dict_values'> print(type(values)) # dict_values([100, 100, 99]) print(values) # dict_values([100, 100, 99]) print(list(values)) # [100, 100, 99] items = scores.items() print(type(items)) # <class 'dict_items'> print(items) # dict_items([('anonymous', 100), ('雷军', 100), ('张一鸣', 99)]) print(list(items)) # 转换之后的列表元素是由 元组 组成[('anonymous', 100), ('雷军', 100), ('张一鸣', 99)]
-
字典元素的遍历
语法格式:
for item in 字典类型变量: 执行语句...
字典遍历是对字典中各个键的遍历
for item in scores: # 是对字典中键的遍历 print(item,end='\t') # anonymous 雷军 张一鸣
字典的特点
- 字典中所有的元素都是一个 key-value 对,key不允许重复(若重复会存在“覆盖”情况),value可以重复
- 字典中的元素是无序的
- 字典中的key必须是不可变对象
- 字典也可以根据需要动态地伸缩
- 字典会浪费较大的内存,是一种使用空间换时间的数据结构
字典生成式
- 内置函数
zip()
用于将可迭代的对象作为参数,将对象中对应的元素打包成一个元组,然后返回由这些元组组成的列表
{表示字典key的表达式:表示字典value的表达式 for 自定义表示key的变量,自定义表示value的变量 in 可迭代对象}
items = ['anonymous','雷军','张一鸣']
scores = [100,99,98]
dictionary = zip(items,scores)
print(list(dictionary)) # [('anonymous', 100), ('雷军', 99), ('张一鸣', 98)]
diction = {item:price for item,price in zip(items,scores)}
print(diction,type(diction)) # {'anonymous': 100, '雷军': 99, '张一鸣': 98} <class 'dict'>
元组
Python内置的数据结构之一,是一个不可变序列
- 不可变序列与可变序列
- 不可变序列:没有增、删、改的操作(字符串、元组)
- 可变序列:可以对序列执行增、删、改操作,对象地址不发生更改(列表、字典)
为什么要将元组设计成不可变序列
-
在多任务环境下,同时操作对象使不需要加锁
-
在程序中尽量使用不可变序列
注意事项:元组中存储的是对象的引用
a) 如果元组中对象本身是不可变对象,则不能再引用其它对象
b) 如果元组中对象是可变对象,则可变对象的引用不允许改变,但数据可以改变
元组的创建
- 直接小括号
t = ('python','hello','world')
- 使用内置函数
tuple
t=tuple('python',hello',90)
- 只包含一个圆柱的元素需要使用逗号和小括号
t = ('python',)
元组的遍历
元组是可迭代对象,所以可以使用for...in
进行遍历
集合
-
Python语言提供的内置数据结构
-
与列表、字典一样都属于可变类型的序列
-
集合是没有 value 的字典
集合的创建
- 直接使用
{}
- 使用内婚制函数
set()
s = {'python','hello',90} # {90, 'python', 'hello'}
print(s)
print(set(range(6))) # {0, 1, 2, 3, 4, 5}
print(set([1,2,3,4,4,65])) # {65, 1, 2, 3, 4}
print(set((1,2,3,3,4))) # {1, 2, 3, 4}
print(set('python')) # {'y', 'n', 'h', 'p', 't', 'o'}
print(set({1,2,2,3,4})) # {1, 2, 3, 4}
print(set()) # set()
集合的相关操作
集合元素的判断操作
in
或not in
集合元素的新增
- 调用
add()
方法,一次添加一个元素 - 调用
update()
方法 ,至少添加一个元素
language = {'Java','Python','Go','JavaScript'}
language.add('PHP')
print(language) # {'Go', 'Python', 'Java', 'JavaScript', 'PHP'}
language.update(['Swift','R','Ruby'])
print(language) # {'Go', 'Swift', 'R', 'Python', 'Ruby', 'Java', 'JavaScript', 'PHP'}
集合元素的删除操作
- 调用
remove()
方法,一次删除一个指定元素,如果指定元素不存在 抛出KeyError
异常 - 调用
discard()
方法,一次删除一个指定元素,如果指定元素不存在 不抛出异常 - 调用
pop()
方法,一次只删除一个任意元素 - 调用
clear()
方法,清空集合
language.remove('c#') # KeyError: 'c#'
language.discard('PHP')
print(language) # {'JavaScript', 'Python', 'Ruby', 'Go', 'R', 'Java', 'Swift'}
language.pop()
print(language) # {'Go', 'Swift', 'Java', 'JavaScript', 'Python', 'Ruby'}
language.clear()
print(language) # set()
集合间的关系
-
两个集合是否相等
可以使用运算符
==
或!=
进行判断 -
一个集合是否是另一个集合的子集
可以调用方法
issubset
进行判断 -
一个集合是否是另一个集合的超集
可以调用方法
issuperset
进行判断 -
两个结合是否没有交集
可以调用方法
isdisjoint
进行判断
集合间的关系
- 两个集合是否相等:使用运算符 == 或 != 进行判断
- 一个集合是否是另一个集合的子集:调用 方法
s1.issubset(s2)
进行判断 - 一个集合是否是另一个集合的超集:调用方法
s1.issupperset(s2)
进行判断 - 两个集合是否没有交集:调用方法
s1.isdisjoint(s2)
进行判断
s1 = {10,20,30,40}
s2 = {20,30,40,50,60}
print(s1 == s2) # False
print(s1 != s2) # True
print(s1.issubset(s2)) # False
print(s2.issuperset(s1)) # False
print(s1.isdisjoint(s2)) # False
集合的数学操作
- 交集
s1.intersection(s2)
&
- 并集
s1.union(s2)
|
- 差集
s1.difference(s2)
-
- 对称差集
s1.symmetric_difference(s2)
^
# 交集
print(s1.intersection(s2))
print(s1 & s2) # {40, 20, 30}
# 并集
print(s1.union(s2))
print(s1 | s2) # {40, 10, 50, 20, 60, 30}
# 差集
print(s1.difference(s2))
print(s1 - s2) # {10}
# 对称差集
print(s1.symmetric_difference(s2))
print(s1 ^ s2) # {50, 10, 60}
集合生成式
语法格式:
{表示集合元素的表达式 for 自定义变量 in 可迭代对象}
# {i*i for i in range(1,10)}
- 将
{}
修改为[]
就是列表生成式 - 没有元组生成式
列表、字典、元组、集合总结
字符串
在Python中字符串是基本数据类型,是一个不可变的字符序列
字符串的驻留机制
-
什么叫字符串驻留机制呢?
仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串的驻留池中,Python的驻留机制对相同字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量。
a = 'python' b = "python" c = '''python''' print(id(a)) # 1722934638960 print(id(b)) # 1722934638960 print(id(c)) # 1722934638960
-
驻留机制的几种情况(交互模式)
-
字符串的长度为0或1时
-
符合标识符的字符串
-
字符串只在编译时进行驻留,而非运行时
>>> str = 'anonymous' >>> print(str) anonymous >>> str1 = 'anony'+'mous' >>> print(id(str)) 1419843712688 >>> print(id(str1)) 1419843712688 #与str地址相同 >>> str2 = ''.join(['anony','mous']) >>> print(id(str2)) 1419843713264 #与str地址不相同
-
[-5,256]
之间的整数数字>>> a = -5 >>> b = -5 >>> print(id(a)) 1419841661040 >>> print(id(b)) 1419841661040 #与 a 地址相同 >>> a = -6 >>> b = -6 >>> print(id(a)) 1419841903184 >>> print(id(-6)) 1419843513008 #与 a 地址不相同
-
-
sys
中的intern
方法强制 2个字符指向同一个对象>>> import sys >>> s1 = 'Python%' >>> s2 = 'Python%' >>> print(id(s1),id(s2)) 1419843713328 1419843713456 # 地址不同 >>> s1 = sys.intern(s2) >>> print(id(s1),id(s2)) 1419843713456 1419843713456 # 转换后,地址相同
-
PyCharm 对字符串进行了优化处理
-
字符串驻留机制的优缺点
- 当需要值相同的字符串时,可以直接从字符串池里拿来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串是会比较影响性能的。
- 在需要进行字符串拼接是建议使用
str
类型的的join
方法,而非+
,因为join()
方法是先计算出所有字符中的长度,然后再拷贝,只是new
一次对象,效率要比+
效率高。
字符串常用操作
字符串的查询操作的方法
index()
:查找子串substr
第一次出现的位置,如果查找的子串不存在时,则抛出ValueError
异常rindex()
:查找子串substr
最后一次出现的位置,如果查找的子串不存在时,则抛出ValueError
异常find()
:查找子串substr
第一次出现的位置,如果查找的子串不存在时,则返回-1
find()
:查找子串substr
最后一次出现的位置,如果查找的子串不存在时,则返回-1
字符串的大小写转换操作的方法
upper()
:把字符串中所有字符都转成大写字母lower()
:把字符串中所有字符都转成小写字母swapcase()
:把字符串中所有大写字母转成小写字母,所有的小写字母转成大写字母capitalize()
:把第一个字符转换为大写,把其余字符转换为小写title()
:把每个单词的第一个字符转换为大写,把每个单词的剩余字符转换为小写
以上所有方法均返回一个新的字符串,因为字符串是不可变序列。
字符串内容对齐操作的方法
center()
:居中对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则返回原字符串ljust()
:左对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则返回原字符串rjust()
:右对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则返回原字符串zfill()
:右对齐,左边用0填充,该方法只接受一个参数,用于指定字符串的宽度,如果指定的宽度小于等于字符串的长度,返回字符串本身
字符串劈分操作的方法
split()
:- 从字符串的左边开始劈分,默认的劈分字符串是空格字符串,返回的值是一个列表
- 以通过参数
sep
指定劈分字符串的劈分符 - 通过参数
maxsplit
指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独作为一部分
rsplit()
:- 从字符串的右边开始劈分,默认的劈分字符串是空格字符串,返回的值是一个列表
- 以通过参数
sep
指定劈分字符串的劈分符 - 通过参数
maxsplit
指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独作为一部分
判断字符串操作的方法
isidentifier()
:判断指定字符串是不是合法的标识符isspace()
:判断指定字符串是否是全部有空白字符组成(回车、换行、水平制表符)isalpha()
:判断指定字符串是否全部由字母组成isdecimal()
:判断指定字符串是否全部由十进制的数字组成isnumeric()
:判断指定字符串是否全部由数字组成isalnum()
:判断指定字符串是否全部由字母和数字组成
字符串替换与合并操作的方法
replace()
:第1个参数指定被替换的子串,第2个参数指定替换子串的字符串,该方法返回替换后得到的字符串,替换前端字符串不发生变化,调用该方法可以通过第3个参数指定最大替换次数join()
:将列表或元组中的字符串合并成一个字符串
字符串的比较操作
- 运算符:
> >= < <= == !=
- 比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下一个字符吗,依次比较下去,知道两个字符串中的字符不相等时,其比较结果就是两个字符串的比较结果,两个字符串中的所有后续字符将不再被比较
- 比较原理:两个字符进行比较时,比较的是其
ordinal value
(原始值),调用内置函数ord()
可以得到指定字符的ordinal value
。与内置函数ord(0)
对应的是内置函数chr()
,调用内置函数chr()
时指定ordinal value
可以得到其对应的字符
字符串的切片操作
字符串是不可变类型,不具备增、删、改等操作,切片操作将产生新的对象
s = '马克扎克伯格'
s1 = s[:2]
s2 = s[2:]
s3 = s1 + '.' +s2
print(s1) # 马克
print(s2) # 扎克伯格
print(s3) # 马克.扎克伯格
格式化字符串
%
作占位符{}
作占位符f-string
name = 'anonymous'
age = 18
#(1) %占位符
print('my name is %s, %d years old.' % (name,age))
#(2) {}占位符
print('my name is {0}, {1} years old.'.format (name,age))
#(3) f-string
print(f'my name is {name}, {age} years old.')
print('{0:.3}'.format(3.1415926)) # 0表示顺序(第一个数) .3表示一共是3位数
print('{:.3f}'.format(3.1415926)) # .3f表示一共是3位小数
print('{:10.3f}'.format(3.1415926)) # 同时设置宽度和精度.一共10位,3位是小数
字符串的编码
-
为什么需要字符串的编码转换
-
编码与解码的方式
- 编码:将字符串转换为二进制数据(bytes)
- 解码:将bytes类型的数据转换成字符串类型
s = '马克扎克伯格' #编码 print(s.encode(encoding='GBK')) # 在GBK这种编码格式中 一个中文占两个字节 print(s.encode(encoding='UTF-8')) # 在UTF-8这种编码格式中 一个中文占三个字节 #解码 byte = s.encode(encoding='GBK') # 编码 byte代表一个二进制数据(字节类型数据) print(byte.decode(encoding='GBK')) # 解码 byte = s.encode(encoding='UTF-8') print(byte.decode(encoding='UTF-8'))
函数
什么是函数?
函数就是执行特定任务和完成特定功能的一段代码
为什么需要函数?
- 复用代码
- 隐藏实现细节
- 提高可维护性
- 提高可读性便于调试
函数的创建
def 函数名称(参数列表):
函数语句...
return 函数返回值
函数调用的参数传递
- 位置实参:根据形参对应的位置进行实参传递
- 关键字实参:根据形参名称进行实参传递
def calc(a,b): #a,b称为形式参数,简称:形参; 形参的位置是在函数的定义处
c = a+b
return c
result = calc(10,20) #10,20称为实际参数的值,简称:实参; 实参的位置是在函数的调用处
print(result)
res = calc(b=10,a=20) # 等号左侧的变量名称称为 关键字参数
print(res)
def fun(arg1,arg2):
print('arg1=',arg1)
print('arg2=',arg2)
arg1=100 # arg1的修改不会影响n1的值
arg2.append(10) # arg2的修改,append(10),会影响到n2的值
print('arg1=',arg1)
print('arg2=',arg2)
n1 = 11
n2 = [22,33,44]
print(n1)
print(n2)
print('---------')
fun(n1,n2)
print(n1)
print(n2)
'''
输出:
11
[22, 33, 44]
---------
arg1= 11
arg2= [22, 33, 44]
arg1= 100
arg2= [22, 33, 44, 10]
11
[22, 33, 44, 10]
'''
在函数调用过程中,进行参数的传递
- 如果是不可变对象,在函数体的修改不会影响实参的值 。
- 如果是可变对象,在函数体的修改会影响到实参的值。
函数的返回值
- 如果函数没有返回值,函数执行完毕后,不需要给调用处提供数据,return 可以省略不写。
- 函数的返回值是一个,直接返回相应类型。
- 函数的返回值是多个,返回的结果为元组。
'''将列表中的奇数和偶数分别存放'''
def fun(num):
odd=[] # 存奇数
even=[] # 存偶数
for i in num:
if i%2:
odd.append(i)
else:
even.append(i)
return odd,even
print(fun([10,29,34,23,44,53,55]))
函数参数的定义
- 函数定义默认值参数
函数定义是,给形参设置默认值,只有与默认值不符的时候才需要传递实参。
def fun(a,b=10):
print(a,b)
fun(100)
fun(20,30)
-
个数可变的位置参数
- 定义函数时,可能无法实现确定传递的位置实参的个数时,使用可变的位置参数
- 使用
*
定义个数可变的位置形参 - 结果为一个元组
def fun(*args): print(args) fun('anonymous') # ('anonymous',) fun('anonymous','雷军','丁磊') # ('anonymous', '雷军', '丁磊')
-
个数可变的关键字形参
- 定义函数时,无法实现确定关键字实参的个数时,使用可变的关键字形参
- 使用
**
定义个数可变的关键字形参 - 结果为一个字典
def fun1(**args): print(args) fun1(a='python') # {'a': 'python'} fun1(a='anonymous',b='雷军',c='张一鸣') # {'a': 'anonymous', 'b': '雷军', 'c': '张一鸣'}
函数的参数总结
def fun(a,b,c): # a,b,c在函数的定义处,所以是形式参数
print('a=',a)
print('b=',b)
print('c=',c)
# 函数的调用
fun(10,20,30) # 位置传参
lst = [10,20,30]
fun(*lst) # 在函数调用时,将列表中的每个元素都转换为位置实参传入
fun(a=100,b=200,c=300) # 关键字传参
dic = {'a':111,'b':222,'c':333}
fun(**dic) # 在函数的调用时,将字典中的键值对都转换为关键字实参传入
''' fun(lst) fun(dic)
TypeError: fun() missing 2 required positional arguments: 'b' and 'c' '''
def fun(*args,*args1):
pass
# 以上代码,程序会报错,个数可变的位置参数,只能是1个
def fun1(**args,**args1):
pass
# 以上代码,程序会报错,个数可变的关键字参数,只能是1个
def fun2(**args,*args1):
pass
# 以上代码,程序会报错
def fun3(*args,**args2):
pass
''' 在一个函数定义过程中,既有个数可变的关键字形参,也有个数可变的位置形参
要求,个数可变的位置形参,放在个数可变的关键字形参之前'''
def fun4(a,b,*,c,d):
print('a=',a)
print('b=',b)
print('c=',c)
print('d=',d)
#调用fun4函数
fun4(10,20,30,40) #TypeError: fun4() takes 2 positional arguments but 4 were given
fun4(a=10,b=20,c=30,d=40) # 关键字实参传递
fun4(10,20,c=30,d=40) # 前两个参数,采用的是位置实参传递,而c,d采用的是关键字实参传递
'''需求 c,d只能采用关键字实参传递'''
'''函数定义时的形参的顺序问题'''
def fun5(a,b,*,c,d,**args):
pass
def fun6(*args,**args1):
pass
def fun7(a,b=10,*args,**args1):
pass
变量的作用域
程序代码能访问该变量的区域
-
根据变量的有效范围可分为
-
局部变量
在函数内定义并使用的变量,只在函数内部有效,局部变量使用
global
声明,这个变量就会变成全局变量 -
全局变量
函数体外定义的变量,可以用于函数内外
-
递归函数
-
什么是递归函数?
如果在一个函数的函数体内调用了该函数本身,这个函数就称为递归函数
-
递归函数的组成部分
递归调用与递归终止条件
-
递归的调用过程
每递归调用一次函数,都会在栈内存分配一个栈帧;每次执行完一次函数,都会释放相应的空间
-
递归的优缺点
- 缺点:占用的内存多,效率低下
- 优点:思路和代码简单
# 计算阶乘的递归算法
def fac(n):
if n==1:
return 1
else: return n*fac(n-1)
print(fac(6))
# 斐波那契数列的递归算法
def fib(n):
if n==1: return 1
if n==2: return 1
else: return fib(n-1)+fib(n-2)
print(fib(6))
# 输出斐波那契数列的前n个值
def fibn(n):
for i in range(1,n+1):
print(fib(i))
print(fibn(8))
Bug
常见的异常类型
- 漏了末尾的冒号,如
if
语句,循环语句else
子句等 - 代码缩进错误
- 把英文符号写成中文符号,如 引号,冒号,括号
- 字符串的拼接,把字符串和数字拼在一起
- 没有定义变量直接使用标识符
=
赋值运算符误用为==
比较运算符- 程序代码逻辑没有错误,只是因为用户错误操作或者一些“例外情况”而导致的程序崩溃
异常处理机制
被动掉坑问题的解决方案
Python提供了异常处理截止,可以在异常出现时及时补货,然后内部“消化”,让程序继续运行
语法结构:
try:
可能会出现异常的代码...
except 异常类型名称:
异常处理代码(报错后执行的代码)...
异常处理结构
-
多个
except
结构捕获异常的顺序按照先子类后父类的循序,为了避免遗漏可能出现的异常,可以在最后增加
BaseExcepetion
语法结构:
try: 可能会出现异常的代码... except 异常类型名称: 异常处理代码... except 异常类型名称: 异常处理代码... except Base Exception: 异常处理代码...
try: a = int(input('请输入第一个整数:')) b = int(input('请输入第二个整数:')) result = a/b print('结果为:',result) except ZeroDivisionError: print('对不起,除数不允许为0') except ValueError: print('只能输入数字串') print('程序结束')
-
try..except...else
结构如果
try
块中没有抛出异常,则执行else
块,如果try
中抛出异常,则执行except
块 -
try..except...else...finally
结构finally
块无论是否发生异常都会被执行,常用于释放try
块中申请的资源try: a = int(input('请输入第一个整数:')) b = int(input('请输入第二个整数:')) result = a / b except BaseException as e: print('出错了!',e) else: print('计算结果为:',result) finally: print('无论是否产生异常,总会被执行的代码') print('程序结束')
traceback模块
使用traceback模块打印异常信息
import traceback
try:
print('1.-------------')
print(1/0)
except:
traceback.print_exc()
异常信息有可能被存入文件当中,放入日志文件。
编程思想
类与对象
类是多个类似事务组成的群体的统称。能够帮助我们快速理解和判断事务的性质。
-
数据类型
- 不同的数据类型属于不同的类
- 可以使用内置函数查看数据类型
type(data)
-
对象
类的实例
类型:
- 类对象
- 实例对象
类的创建
-
创建类的语法
class 类名: pass
类的名称 (类名) 由一个或多个单词组成,每个单词的首字母大写,其余小写
class Student:# 类对象 pass # Python中一切皆对象Student是对象吗?内存有开辟空间吗? print(id(Student)) # 1986696427792 print(type(Student)) # <class 'type'> print(Student) # <class '__main__.Student'>
-
类的组成
- 类属性
- 实例方法
- 类方法
- 静态方法
在类之外定义的称为函数,在类之内定义的称为方法
class Student: native_place = '河南' # 直接写在类里面的变量,称为类属性 def __init__(self,name,age): # 类似于Java里面的构造函数 self.name = name # self.name 称为实体属性,进行了一个赋值的操作,将局部变量的name赋值给实体属性 self.age = age # 实例方法 def eat(self): print('学生在吃饭...') # 类方法 @classmethod def cm(cls): print('类方法,使用了classmethod进行修饰') # 静态方法 @staticmethod def sm(): print('静态方法,使用了staticmethod进行修饰')
Python中的类属性类似于Java中的类变量
def __int__(self,args...):
方法类似于Java中类的构造函数,self.变量名
用于初始化所创建实例对象的实体属性。实体属性类似于Java中的成员变量,但又有所不同,Python中使用相同类创建的实例对象可以拥有不同的实体属性,而Java中使用相同类创建的对象的成员变量均一致(只是成员变量的值不一样)。
实例方法和静态方法的用法均与Java中的实例方法、静态方法一致
实例方法、类方法与静态方法的区别
实例方法在定义的时候,需要有表示类实例的参数(通常以self表示,例如
def eat(self,arg1,arg2……): 方法语句...
),实例方法不能通过类名.方法名()
来调用,必须先创建类的实例,然后通过实例.方法名()
来调用。类中的静态方法用
@staticmethod
来修饰,静态方法在定义的时候,不需要表示类的实例,可想类外的方法定义一样。静态方法可以通过类名.方法名()
和实例.方法名()
调用。类方法用
@classmethod
来修饰,类方法在定义的时候,需要有表示类对象的参数。类方法也可以通过类名.方法名()
和实例.方法名()
调用。(注意:python中,类也是一个对象,这里所说的类对象是指类本身,而非类实例化得对象)
对象的创建
对象的创建又称为类的实例化
语法结构:
实例名=类名()
意义:有了实例,就可以调用类中的内容
class Student:
native_place = '河南' # 直接写在类里面的变量,称为类属性
def __init__(self,name,age):
self.name = name # self.name 称为实体属性,进行了一个赋值的操作,将局部变量的name赋值给实体属性
self.age = age
# 实例方法
def eat(self):
print('学生在吃饭...')
# 类方法
@classmethod
def cm(cls):
print('类方法,使用了classmethod进行修饰')
# 静态方法
@staticmethod
def sm():
print('静态方法,使用了staticmethod进行修饰')
stu = Student('anonymous',18)
print(id(stu)) # 2750062780272
print(type(stu)) # <class '__main__.Student'>
print(stu) # <__main__.Student object at 0x000002804C83DF70>
print('------------------------------------------------------')
print(id(Student)) # 2750054448912
print(type(Student)) # <class 'type'>
print(Student) # <class '__main__.Student'>
print(stu.name)
print(stu.age)
stu.eat()
Student.eat(stu)
类属性、类方法、静态方法
- 类属性:类中方法外的变量称为类属性,被该类的所有对象所共享
- 类方法:使用
@classmethod
修饰的方法,使用类名直接访问的方法 - 静态方法:使用
@staticmethod
修饰的方法,使用类名直接访问的方法
print(Student.native_place) # 河南
Student.sm() # 静态方法,使用了staticmethod进行修饰
Student.cm() # 类方法,使用了classmethod进行修饰
print(stu.native_place) # 河南
Student.native_place = '重庆'
print(stu.native_place) # 重庆
实例对象通过
类指针
来访问类属性(每个实例对象都有一个类指针指向它所对应的类)
动态绑定
Python 是动态语言,在创建对象之后,可以动态地绑定属性和方法。
stu.gender = '男' # 动态绑定属性
print(stu.gender)
def show():
print('类外部定义的函数,用于实例对象的动态绑定')
stu.show = show
stu.show()
stu1 = Student('joker',17)
print(stu1.gender) # AttributeError: 'Student' object has no attribute 'gender'
stu1.show() # AttributeError: 'Student' object has no attribute 'show'
面向对象
面向对象三大特征
- 封装:提高程序的安全性
- 继承:提高代码的复用性
- 多态:提高程序的可扩展性和可维护性
封装
- 将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样无序关心方法内部的具体实现细节,从而隔离了复杂度。
- 在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前面使用两个
-
class Student:
def __init__(self,name,age):
self.name = name
self.__age = age # 年龄不希望在类的外部被使用,所以加两个_
def show(self):
print(self.name,self.__age)
stu = Student('anonymous',18)
stu.show()
#在类的外部使用name与age
print(stu.name)
# print(stu.__age) # AttributeError: 'Student' object has no attribute '__age'
print(dir(stu))
'''['_Student__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__',
'__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__','__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__', 'name', 'show']'''
print(stu._Student__age) # 在类的外部可以通过 _Student__age 进行访问
继承
- 语法格式:
class 子类类名(父类1,父类2...): pass
- 如果一个类没有继承任何类,则默认继承
object
- Python 支持多继承
- 定义子类时,必须在其够着函数中调用父类的构造函数
class Person(object): # Person继承object类
def __init__(self,name,age):
self.name = name
self.age = age
def info(self):
print(self.name,self.age)
class Student(Person):
def __init__(self,name,age,stu_no):
super().__init__(name,age)
self.stu_no = stu_no
class Teacher(Person):
def __init__(self,name,age,teachOfYear):
super().__init__(name,age)
self.teachOfYear = teachOfYear
stu = Student('anonymous',18,'1001')
teacher = Teacher('雷军',30,10)
stu.info()
teacher.info()
# 多继承
class A(object):
pass
class B(object):
pass
class C(A,B):
pass
方法重写
- 如果子类对继承自父类的某个属性或方法不满意,可以在子类中对其(方法体)进行重新编写
- 子类重写后的方法中可以通过
super().方法名()
调用父类中被重写的方法
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def info(self):
print('姓名:{0},年龄:{1}'.format(self.name,self.age))
class Student(Person):
def __init__(self,name,age,stu_no):
super().__init__(name,age)
self.stu_no = stu_no
def info(self):
super().info()
print('学号:{0}'.format(self.stu_no))
stu = Student('Jocker',18,'1001')
stu.info()
object类
object
类是所有类的父类,因此所有类都有object
类的属性和方法。- 内置函数
dir()
可以查看指定对象所有属性 object
有一个__str__()
方法,用于返回一个对于 “对象的描述”,对应于内置函数__str__()
经常用于print()
方法,帮我们查看对象的信息,所以我们经常会对__str__()
进行重写
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return '我的名字是{0},今年{1}岁'.format(self.name,self.age)
stu = Student('anonymous',18)
print(dir(stu))
'''['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__','__getattribute__',
'__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__','__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']'''
print(stu) # 未重写 __str__()方法之前 <__main__.Student object at 0x000001F725D2CFD0>
# 我的名字是anonymous,今年18岁
print(type(stu)) # <class '__main__.Student'>
多态
简单地说,多态就是“具有多种形态”,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法。
class Animal(object):
def eat(self):
print('动物要吃东西')
class Dog(Animal):
def eat(self):
print('狗吃骨头')
class Cat(Animal):
def eat(self):
print('猫吃鱼')
class Person(object):
def eat(self):
print('人吃五谷杂粮')
# 定义一个函数
def fun(obj):
obj.eat()
# 调用函数
fun(Cat())
fun(Dog())
fun(Animal())
fun(Person())
静态语言与动态语言
静态语言和动态语言关于多态的区别
- 静态语言实现多态的三个必要条件
- 继承
- 方法重写
- 父类引用指向子类对象
- 动态语言的多态崇尚“鸭子类型”,当看到一只鸟走起来像鸭子、游泳起来像鸭子,纳闷这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为。
特殊方法和特殊属性
class A(object):
pass
class B(object):
pass
class C(A,B):
def __init__(self,name,age):
self.name = name
self.age = age
# 创建C类的对象
x = C('Joker',18) # x是C类型的一个实例对象
print(x.__dict__) # {'name': 'Joker', 'age': 18}
print(C.__dict__) # {'__module__': '__main__', '__init__': <function C.__init__ at 0x000002A456890430>, '__doc__': None}
print(x.__class__) # <class '__main__.C'> 输出对象所属的类
print(C.__base__) # 类的基类
print(C.__bases__) # C类的父类类型的元素
print(C.__mro__) # 类的层次结构
print(A.__subclasses__()) # 子类的列表
a = 20
b = 80
c = a+b # 两个整数对象的相加操作
d = a.__add__(b)
print(c) # 100
print(d) # 100
class Student:
def __init__(self,name):
self.name = name
def __add__(self, other):
return self.name+other.name
stu = Student('anonymous')
stu1 = Student('Joker')
s = stu+stu1 # 实现了两个对象的加法运算(因为在Student类中 编写__add__()特殊的方法)
print(s) # anonymousJoker
s = stu.__add__(stu1)
print(s) # anonymousJoker
class Person(object):
def __new__(cls, *args, **kwargs):
print('___new__ 被调用执行了,cls的id值为:{0}'.format(id(cls))) # 2177786755568
obj = super().__new__(cls)
print('创建的对象的id为:{0}'.format(id(obj))) # 2177793992640
return obj
def __init__(self,name,age):
print('__int__被调用了,self的id值为:{0}'.format(id(self))) # 2177793992640
self.name = name
self.age = age
print('object这个类对象的id为:{0}'.format((id(object)))) # 140726781099520
print('Person这个类对象的id为:{0}'.format((id(Person)))) # 2177786755568
#创建Person类的实例对象
person = Person('anonymous',18)
print('person这个类对象的id为:{0}'.format((id(person)))) # 2177793992640
类的浅拷贝与深拷贝
-
变量的赋值操作
只是形成两个变量,实际上还是指向同一个对象
-
浅拷贝
Python拷贝一般都是钱拷贝,拷贝时,对象包含的子对象内容不拷贝。因此,源对象与拷贝对象会引用同一个子对象
-
深拷贝
使用
copy
模块的deepcopy
函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同
class CPU:
pass
class Disk:
pass
class Computer:
def __init__(self,cpu,disk):
self.cpu = cpu
self.disk = disk
# 变量的赋值
cpu = CPU()
cpu1 = cpu
print(cpu,id(cpu)) # <__main__.CPU object at 0x000002D562B1CFD0> 3115507109840
print(cpu1,id(cpu1)) # <__main__.CPU object at 0x000002D562B1CFD0> 3115507109840
disk = Disk()
print(disk) # <__main__.Disk object at 0x000001E192E8DF70>
computer = Computer(cpu,disk)
# 浅拷贝
import copy
computer1 = copy.copy(computer)
print(computer,computer.cpu,computer.disk) # <__main__.Computer object at 0x000001E192E8DE50> <__main__.CPU object at 0x000001E192E8DFD0> <__main__.Disk object at 0x000001E192E8DF70>
print(computer1,computer1.cpu,computer1.disk) # <__main__.Computer object at 0x000001E192E8DD60> <__main__.CPU object at 0x000001E192E8DFD0> <__main__.Disk object at 0x000001E192E8DF70>
# 深拷贝
computer1 = copy.deepcopy(computer)
print(computer,computer.cpu,computer.disk) # <__main__.Computer object at 0x000002302CF9DE50> <__main__.CPU object at 0x000002302CF9DFD0> <__main__.Disk object at 0x000002302CF9DF70>
print(computer1,computer1.cpu,computer1.disk) # <__main__.Computer object at 0x000002302CF9DC70> <__main__.CPU object at 0x000002302CF9D460> <__main__.Disk object at 0x000002302CF9D490>
模块
什么叫模块?
-
英文:
Modules
-
函数与模块的关系
一个模块中可以包含N多个函数
-
在Python中一个扩展名为
.py
的文件就是一个模块
使用模块的好处
- 方便其他程序和脚本的导入并使用
- 避免函数名和变量名的冲突
- 提高代码的可维护性
- 提高代码的可重用性
自定义模块
-
创建模块
新建一个
.py
文件,名称尽量不要与 Python 自带的标准模块名称相同 -
导入模块
import 模块名称 [as 别名] from 模块名称 import 函数/变量/类
import math # 关于数学运算 print(id(math)) print(type(math)) # <class 'module'> print(math) # <module 'math' (built-in)> print(math.pi) # 3.141592653589793 print(dir(math)) ''' ['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'nextafter', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp'] ''' print(math.pow(2,3),type(math.pow(2,3))) print(math.ceil(9.0001)) print(math.floor(9.9999))
from math import pi print(pi) # 3.141592653589793 print(pow(2,3)) # 8 from math import pow print(pow(2,3)) # 8.0
calc.py :
def add(x,y): return x+y def div(x,y): try: z = x/y except BaseException: print('The denominator can\'t be zero') else: return z print(add(100,200))
demo.py :
import calc print(calc.add(10,20)) print(calc.div(10,4)) ''' 输出结果: 300 30 2.5 '''
若导入自定义模块后,出现编译器报错情况。
解决办法:
右键单击导入自定义模块的所在报错模块的目录文件 -> Mark Directory as -> Source Root
以主程序形式运行
在每个模块的定义中都包括一个记录模块名称的变量
__name__
,程序可以检查该变量,以确定他们在哪个模块中执行。如果一个模块不是被导入到其他程序中执行,那么它可能在解释器的顶级模块中的执行。顶级模块的__name__
变量的值为__main__
calc.py :
def add(x,y): return x+y def div(x,y): try: z = x/y except BaseException: print('The denominator can\'t be zero') else: return z if __name__ == '__main__': print(add(100,200))
demo.py :
import calc print(calc.add(10,20)) print(calc.div(10,4)) ''' 输出结果: 300 30 2.5 '''
Python中的包
-
包是一个分层次的目录结构,它将一组功能相近的模块组织在一个目录下
-
作用:
- 代码规范
- 避免模块名称冲突
-
包与目录的区别
包含
__init__.py
文件的目录称为包,目录里的通常不包含__init__.py
文件 -
包的导入
import 包名.模块名
使用
import
方式进行导入时,只能跟包名或模块名from ... import
可以导入包、模块、函数、变量
Python中常用的内置模块
import sys
import time
import urllib.request
print(sys.getsizeof(10)) # 28
print(sys.getsizeof(True)) # 28
print(sys.getsizeof(False)) # 24
print(time.time()) # 1611479973.6438103
print(time.localtime()) # time.struct_time(tm_year=2021, tm_mon=1, tm_mday=24, tm_hour=17, tm_min=19, tm_sec=33, tm_wday=6, tm_yday=24, tm_isdst=0)
print(urllib.request.urlopen('http://www.baidu.com').read())
'''
b'<!DOCTYPE html><!--STATUS OK-->\n\n\n <html><head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta content="always" name="referrer"><meta name="theme-color" content="#2932e1">
<meta name="description" content="\xe5\x85...
'''
第三方模块的安装和使用
安装
打开命令行程序 输入 pip install 模块名
使用
import 模块名
import schedule
import time
def printString():
print('anonymous')
schedule.every(3).seconds.do(printString)
while True:
schedule.run_pending()
time.sleep(1)
文件的读写
编码格式
- 常见的字符串编码格式
- Python的解释器使用的是 Unicode(内存)
- .py 文件在磁盘上使用 UTF-8 存储(外存)
在程序中写入#encoding = 编码格式
可以改变程序编码格式
文件的读写原理
- 文件的读写俗称
IO
操作 - 文件的读写流程
- 操作原理
文件的读写操作
-
内置函数
open()
创建文件对象
-
语法规则
file = open(filename [,mode,encoding])
file = open('text.txt','w')
print(file.write('Anonymous Joker'))
file.close()
常用的文件打开模式
文件的类型
-
按文件中数据的组织形式,文件分为以下两大类
- 文本文件:存储的是普通“字符”文本,默认为unicode字符集,可以使用记事本程序打开
- 二进制文件:把数据内容用“字节”进行存储,无法用记事本打开,必须使用专用的软件打开,举例:mp3音频文件、jpg图片、doc文档等
src_file = open('picture.png','rb')
target_file = open('copyPicture','wb')
target_file.write(src_file.read())
target_file.close()
src_file.close()
文件对象的常用方法
with语句(上下文管理器)
with 语句可以自动管理上下文资源,不论什么原因跳出 with 块,都能确保文件正确的关闭,以此来达到释放资源的目的
with open('text.txt','r') as file:
print(file.readline())
with open('picture.png','rb') as src_file:
with open('copyPicture','wb') as target_file:
target_file.write(src_file.read())
目录操作
os
模块是Python内置的与操作系统功能和文件系统相关的模块,该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样os
模块与os.path
模块用于目录或文件进行操作
#os模块与操作系统相关的一个模块
import os
os.system('notepad.exe') # 打开记事本
os.system('calc.exe') # 打开计算器
#直接调用可执行文件
os.startfile('D:\\WeChat\\WeChat.exe') # 打开微信
os模块操作目录的相关函数
import os
print(os.getcwd()) # E:\PyCharm workspace\venv
lst = os.listdir('../venv')
print(lst) # ['calc.py', 'demo.py', 'Include', 'Lib', 'pyvenv.cfg', 'Scripts', 'text.txt', '__pycache__']
os.mkdir('pythondir') # 创建目录 pythondir
os.makedirs('A/B/C') # 创建多级目录 A/B/C
os.rmdir('pythondir') # 删除目录 pythondir
os.removedirs('A/B/C') # 删除多级目录 A/B/C
os.chdir('E:\\PyCharm workspace\\venv') # 将 E:\\PyCharm workspace\\venv 设置为当前工作目录
print(os.getcwd())
os.path模块操作目录的相关函数
import os.path
print(os.path.abspath('demo.py')) # E:\PyCharm workspace\venv\demo.py
print(os.path.exists('demo.py'),os.path.exists('notExists.py')) # True False
print(os.path.join('E:\\PyCharm workspace','demo.py')) # E:\PyCharm workspace\demo.py
print(os.path.split('E:\\PyCharm workspace\\venv\\demo.py')) # ('E:\\PyCharm workspace\\venv', 'demo.py')
print(os.path.splitext('demo.py')) # ('demo', '.py')
print(os.path.basename('E:\\PyCharm workspace\\venv\\demo.py')) # demo.py
print(os.path.dirname('E:\\PyCharm workspace\\venv\\demo.py')) # E:\PyCharm workspace\venv
print(os.path.isdir('E:\\PyCharm workspace\\venv\\demo.py')) # False
# 列出指定目录下的所有py文件
import os
path = os.getcwd()
lst = os.listdir(path)
for filename in lst:
if filename.endswith('.py'):
print(filename)
'''
calc.py
demo.py
'''
import os
path = os.getcwd()
lst_files = os.walk(path)
for dirpath,dirname,filename in lst_files:
print(dirpath)
print(dirname)
print(filename)
print('-----------------------------------')
for dir in dirname:
print(os.path.join(dirpath,dir))
for file in filename:
print(os.path.join(dirpath,file))
print('---------------------------------')
'''
E:\PyCharm workspace\venv
['Include', 'Lib', 'Scripts', '__pycache__']
['calc.py', 'demo.py', 'pyvenv.cfg', 'text.txt']
-----------------------------------
E:\PyCharm workspace\venv\Include
E:\PyCharm workspace\venv\Lib
E:\PyCharm workspace\venv\Scripts
E:\PyCharm workspace\venv\__pycache__
E:\PyCharm workspace\venv\calc.py
...
'''