有了java基础,迅速学完Python并做了一份笔记-全套Python,建议收藏

面向过程

Python简介

Python和Java的解释方式对比

Java:源代码 -> 编译成class -> Jvm解释运行

Python:源代码 -> Python解释器解释运行

我经常和身边的Java开发者开玩笑说:“Java真变态,别的语言都是要么直接编译要么直接解释,Java太另类了又编译又解释的......”

直接解释和编译后解释其实最大的区别就是源代码的安全性。

如果是直接解释源代码,那么源代码没有安全性可言,也就是任何一个人都可以打开源代码一看究竟,任何人都可以随意修改源代码。

事实上,Python和Java的解释方式是相同的,只是我们表面上看Python是直接解释源代码,而实际上python解释器只会加载字节码。细心的小伙伴肯定发现了这一点,当我们import某个模块时,总是会在模块所在的目录创建一个pycache目录,里面存放着被加载模块的字节码文件。

编译源代码有以下作用:

源代码保护(算法保护)/ 防止用户篡改源代码解释器加载代码速度加快


安装好py之后会有几个文件,如下:

  • IDLE:是py自带的一种简单的开发环境

  • Python+版本号:这个是python的交互式命令行程序

  • Python+版本号+ Manuals是官方技术文档(API)

  • Python+版本号+Module Docs是已安装模块的文档

Python输出

open('可以指定文件,将数据输出到对应文件中',a+"),a是以读写的方式创建,如果文件不存在的话就创建,存在的话就在文件后面追加

fp=open('D:/text.txt','a+')

print('helloworld',file=fp)

fp.close

转移字符

什么是转义字符?

  • 就是反斜杠+想要实现转移功能的首字母

  • 当字符串中包含反斜杠、单引号和双引号等有特殊用途的字符时,必须使用反斜杠对这些字符进行转移

  • 反斜杠:\ \ 这里都用空格隔开了,不然中间会转移

  • 单引号:\ ' (可以适用于单引号里面加单引号)

  • 双引号: \ "

  • 换行:\n

  • 回车:\r

  • 退一个格:\b 'hello\bworld' 输出hellworld

  • 水平制表符:\t,一个制表符占位置4个字符,hello\t这样占3个,因为hell算1个制表符,0算一个,剩下3个字符算一个制表符

  • 退格:\b

  • 原字符:不希望字符串中的转义字符起作用,就用元字符,就是在字符串前面加上r或R,如:print(r'hello\nworld') 中间不能有空格,否则报错

  • 注意:最后一个字符不能写一个反斜线 \ ,能写两个

print(r'helloWorld\' ) 错误,这里为了demo,写了两个\才显示一个\

Python基本类型

关键字

importkeyword

pring(keyword.kwlist)

变量的定义

name='哈哈哈哈哈'

print('标识',id(name))

print('类型',type(name))

print('值',name)

输出:

标识 2717730201040 内存地址,可以用id()输出内存地址,也就是标识

类型 <class 'str'>

值 哈哈哈哈哈

十进制-->默认的进制

八进制-->以0b开头

二进制-->以0o开头、

十六进制-->0x开头

浮点数

进行浮点数计算的时候会因为二进制的底层问题导致不精确,我们要小心,不用深究

解决方案:导入模块decimal

#3.4000000000000004

print(1.2+2.2)

#导入Decimal之后 输出3.4

fromdecimalimportDecimal

print(1.2+2.2)

#3.4

布尔型

true表示1

false表示0

字符串

单引号'',双引号" ",三引号''''' ''''',''' '''-无论单双都是String类型

#单双引号换行自动会加 \ 否则报错,三引号不用加,这是唯一区别

str1='哈哈' \

'哈哈哈'

str2="哈哈" \

"哈哈"

str3="""

哈哈哈哈哈 """

数据类型转换

str():将其它数据类型转换为字符串

int():将其它数据类型转换为整数

  • 文字类和小数类字符串-小数串是无法转换为字符串,无法转换为整数

  • 浮点数转换为整数:抹零取整

float():将其他数据类型转换为浮点数

  • 文字类无法转换为整数

  • 整数类转成浮点数,末尾为.0

Python中的注释和输入

注释

在代码中代码的功能进行说明,提升代码的可读性

注释分为三种类型的注释

  • 单行注释:以#开头,直到换行结束

  • 多行注释:并没有单独的多行注释标准,将一到三引号之间的代码称为多行注释

'afd'''

'''afd'''

"""agd"""

"agd"""

  • 中文编码声明注释,在文件的开头加上中文声明注释,用来指定文件的编码格式

如 #coding:gbk

  • java中单行注释 为: //

  • 多行注释为 /** **/

input

它的类型是一个String类型

可以将输出的内容直接转换

a=int(input(' 请输入一个加数'))

present=input('随便输入')

print(present,type(present))

输出

随便输入a

a <class 'str'>

运算符

  • //表示整除运算(11%2=5)

整除注意:一正一负向下取整(9//-4=-3)

  • 2**2表示2的2次方

  • %:取模

一正一负的余数=被除数-除数*商

9%-4=9-(-4)*(-3)=-3

赋值运算符

从右到左执行

a,b,c=20,30,40分别给abc赋值

a=b=c=20表示

ab进行交换:

a,b=b,a

比较运算符

一个=是赋值,==称为比较运算符,

比较对象用的是 is / is not说明它们的标识id是否相同

布尔运算符

and:两个都为true的时候,才为true

or:只有只有一个为true即为true

not:运算数为true,结果为false;运算为false,结果为true

in 和 not in

str='helloworld'

print('w' in str) #true

print('w' not in str) #false

print('z' in str) #false

print('z' not in str) #true

位运算符

位与& : 对应数位都是1,结果才是1,否则为0(底层转换为二进制,每右边开始每一位进行比较)

4: 0 0 0 0 0 1 0 0

8: 0 0 0 0 1 0 0 0

结:0 0 0 0 0 0 0 0

位或|:对应数位都是0,结果数位才是0,否则为1

左移运算符 << :高位溢出舍弃,低位补0,向左移动一位,相当于乘以2

左移一位:

0 0 0 0 0 1 0 0

0 0 0 0 1 0 0 0 0 低位补0

右移运算符 >>:低位溢出舍弃,高位补0,相当于除以2

右移一位:

0 0 0 0 0 1 0 0

0 0 0 0 0 0 1 0 -->0 低位截断

对象的布尔值

print(bool(0.0))#false

print(bool(None))#false

print(bool(''))#false

print(bool(""))#false

print(bool([])) #空列表

print(bool(list())) #空列表

print(bool(()))#空元组

print(bool(tuple()))#空元组

print(bool({})) #空字典

print(bool(dict())#空字典

print(bool(set()))#空集合

print('以上布尔值全为false,其它对象的布尔值都为true')

分支结构

单分支结构

money=1000

minus=int(input("请输入金额"))

if money>=minus:

money-=minus

print(money)

双分支结构

if 条件表达式:

条件执行体1

else:

条件执行体2

多分支结构

if 条件表达式1:

条件执行体1

elif 条件表达式2:

条件执行体2

elif 条件表达式N:

[else:] #这个[]中的内容是可写可不写的,多分支else是可以省略的

条件执行体N+1

嵌套分支

if 条件表达式:

if 条件表达式:

elif 条件表达式

else:

else:

if 条件表达式:

else:

条件表达式

num_a=int(input("请输入第一个整数:"))

num_b=int(input("请输入第二个整数:"))

print(str(num_a),'大于等于',str(num_b)

if (num_a>=num_b) else str(num_a)+"小于"+str(num_b))

#这里注意,整数和字符串想加是出错的,

#这里注意,整数和字符串想加是出错的,需要转换才能进行--java这里可以自动识别相加,python不行

输出

请输入第一个整数:3

请输入第二个整数:1

3 大于等于 1

pass语句

pass语句什么都不做,只是一个占位符,用在语法上需要占位的地方

什么时候用?

  • 先搭建语法结构,没想好代码怎么写的时候,写pass语法不报错

哪些语句一起使用

  • if语句的条件执行体

  • for-in语句的循环体

  • 定义函数时的函数体

if answer='y':

pass

else:

pass

内置函数range()

range()函数

  • 用于生成一个整数序列

  • 创建range对象的三种方式

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) #[0,1,2,3,4,5,6,7,8,9],默认从0开始,默认相差1为步长

print(r)#range(0,10)

print(list(r))#用于查看range对象中的整数序列 -->list是列表的意思

#第二种创建方式

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

r=range(1,10)

print(list(r))

#第三种创建方式

#[1, 3, 5, 7, 9]

r=range(1,10,2)

print(list(r))

print(10 in r) # false

print(10 not in r)# true

循环结构

  • 循环的分类

  • while

  • for -in

语法结构

  • while 条件表达式

条件执行体(循环体)

  • if是判断一次,条件为True执行一次

  • while是判断N+1次,条件为True执行N次

for-in循环

  • in表达从(字符串、序列等)中依次取出,又称遍历

  • for-in遍历的对象必须是可迭代对象

for-in的语法结构

  • for 自定义的变量 in 可迭代对象

循环体

循环体内不需要访问自定义变量,可以将自定义变量替代为下划线

for item in 'Python':

print(item) # 分别打印Python的各个字母

for i in range(10):

print(i) # 打印1-9的数字

#如果在循环体中不需要使用自定义变量,可以将其设置为_,以下打印5次

for _ in range(5):

print('人生苦短,我用python')

sum = 0 #用于存储偶数和

for item in range(1,100):

if item%2 == 0:

sum += item

print('1-100之间的偶数和为:',sum)

水仙花数

for item in range(100,1000):

single = item % 10

ten = item // 10 % 10

hundred = item // 100

if(hundred**3+ten**3+single**3==item):

print(item)

java的这样输入

//如153-java有明确的类型标注,不用和py一样//取整

int x = a/100;//结果取整 分解出百位数 1

int y = a/10%10;//分解出十位数 5

int z = a%10;//个位数 3

输出

153

370

371

407

流程控制语句

break

经常和if一起用

for item in range(3):

pwd = input('请输入密码:')

if pwd == '888':

print("success")

break #执行成功跳出for循环

else:

print('fail')

continue

  • 用于结束当前循环,进入下一次循环,通常和if一起使用

else语句

  • 与else语句配合使用的三种情况

  • if...else: if条件不成立时执行else

  • while...else: 没有碰到break时执行else

  • for...else: 没有碰到break时执行else

while...else

a = 0

while a < 3:

pwd=input('please input your password:')

if pwd == '123':

print('密码正确')

break

else:

print('密码错误')

else:

print('sorry,三次均输入错误')

打印矩形

for i in range(1,4):

for j in range(1,5):

print("*",end = '\t') #不换行输出

print()

* * * *

* * * *

* * * *

九九乘法表

for i in range(1,10): # 9行,不包括10

for j in range (1,10):

if(j<=i):

print(str(j)+' * '+str(i)+' = '+str(j*i),end='\t')

print()

输出

1 * 1 = 1    
1 * 2 = 2    2 * 2 = 4    
1 * 3 = 3    2 * 3 = 6    3 * 3 = 9    
1 * 4 = 4    2 * 4 = 8    3 * 4 = 12    4 * 4 = 16    
1 * 5 = 5    2 * 5 = 10    3 * 5 = 15    4 * 5 = 20    5 * 5 = 25    
1 * 6 = 6    2 * 6 = 12    3 * 6 = 18    4 * 6 = 24    5 * 6 = 30    6 * 6 = 36    
1 * 7 = 7    2 * 7 = 14    3 * 7 = 21    4 * 7 = 28    5 * 7 = 35    6 * 7 = 42    7 * 7 = 49    
1 * 8 = 8    2 * 8 = 16    3 * 8 = 24    4 * 8 = 32    5 * 8 = 40    6 * 8 = 48    7 * 8 = 56    8 * 8 = 64    
1 * 9 = 9    2 * 9 = 18    3 * 9 = 27    4 * 9 = 36    5 * 9 = 45    6 * 9 = 54    7 * 9 = 63    8 * 9 = 72    9 * 9 = 81    

拓展:

python里的end是print函数中的参数,为末尾end传递一个字符串,这样print函数不会在字符串末尾添加一个换行符,而是添加一个字符串,其实这也是一个语法要求,表示这个语句没结束。

二重循环中的break和continue

  • 二重循环中的break和continue用于控制本层循环

continue:
跳过本次循环体中剩下尚未执行的语句,立即进行下一次的本循环条件判定,可以理解为只是中止(跳过)本次循环,接着开始下一次本循环的条件语句
break:
如果有两层for循环,第二层循环中有if...break,跳出的是第二层for循环,继续执行第一层的下一个条件语句

列表

为什么需要列表

  • 变量可以存储一个元素,而列表是一个大容器,可以存储N多个元素,程序可以方便地对这些数据进行整体操作

  • 列表相当于其它语言中的数组

  • 变量存储的是一个对象的引用,而列表存储的是多个对象的引用

  • 列表的创建用 [] 或者内置函数list()创建

元素之间用,分割

  • 列表元素按顺序有序培训

  • 索引映射唯一一个数据

  • 列表可以存储重复元素

  • 任意类型混存

  • 根据需要动态分配和回收内存

  • 和java不同的是:从后往前采用的是负数索引比如第一个0的索引,它同时也是负数最后一个索引,java索引从0开始,无负数

  • 如果列表中有多个元素,只返回列表中相同元素第一个元素的索引

在指定索引进行查找

lst=['hello','world','99','hello']

print(lst.index('hello',1,3)) #1-3不包括3,这里会报错找不到索引

获取列表中的多个元素

  • 语法格式

列表名[start : stop : step]

  • 切片的结果:原列表片段的拷贝

  • 切片的范围,[start,stop)

  • step默认为1,简写为[stop,step]

lst=[10,20,30,40,50,60,70,80]

print('原列表',id(lst))# 原列表 3184358125248

lst2=lst[1:6:1]

print('切的片段:',id(lst2))# 切的片段: 3184361791744

print(lst[1:6]) # 默认步长为1 [20, 30, 40, 50, 60]

print(lst[1:6:])# [20, 30, 40, 50, 60]

print(lst[1:6:2]) # [20, 40, 60]

print(lst[:6:2]) # [10, 30, 50]

print(lst[1::2]) # [20, 40, 60, 80]

print('----------step步长为负数的情况-----------------')

print(lst[::-1]) # [80, 70, 60, 50, 40, 30, 20, 10] 相当于start=7最后一个元素

print(lst[6:0:-2])# [70, 50, 30]

列表元素的判断及遍历

for 迭代变量 in 列表名:

操作

print(10 in lst) #True

print(10 not in lst) #False

遍历

for item in lst:

print(item)

列表元素的增删改操作

增加

  • append():在列表的末尾添加一个元素

  • extend():在列表的末尾至少添加一个元素

  • insert():在列表的任意位置添加一个元素

  • 切片:在列表的任意位置添加至少一个元素

id没变说明,append是在同一个列表中添加元素,每一个元素的id不同,但这个列表的id不变

lst=[10,20,30]

print('添加元素之前',lst,id(lst)) #添加元素之前 [10, 20, 30] 1732983054336

lst.append(40)

print('添加元素之后',lst,id(lst)) #添加元素之后 [10, 20, 30, 40] 1732983054336

添加列表

  • 将lst2作为一个元素添加到lst1的末尾

lst2=['hello','world']

lst.append(lst2)

print(lst) #[10, 20, 30, 40, ['hello', 'world']]

用extend()添加列表

lst2=['hello','world']

lst.extend(lst2)

print(lst) # [10, 20, 30, 40, 'hello', 'world']

在任意位置上添加一个元素

lst = [10,20,30]

lst.insert(1,90)

print(lst) #[10, 90, 20, 30, 40]

切片

lst.insert(1,90)

print(lst) # [10, 20, 30, 40]

lst3=[True,False,'hello'] # [10, 90, 20, 30, 40]

lst[1:]=lst3

print(lst) # [10, True, False, 'hello']

列表元素的删除操作

  • remove():一次删除一个元素

重复元素只删除第一个

元素不存在抛出ValueError

  • pop() :删除一个指定索引位置上的元素

指定索引不存在抛出IndexError

不指定索引,删除列表中最后一个元素

  • 切片:一次至少删除一个元素

  • clear():清空列表

  • del:删除列表

lst=[10,40,50,60]

new_list=lst[1:3]

print('原列表:',lst) # 原列表: [10, 40, 50, 60]

print('切片后的列表:',new_list) # 切片后的列表: [40, 50]

#不产生原列表中的对象,而是删除原列表中的内容

lst[1:3]=[]

print(lst) # [10, 60]

del lst

print(lst) # name 'lst' is not defined 既然删除了,那么就没有定义

列表元素的排序操作

常见的两种方式:

  • 调用sort()方法,列表中所有元素默认按照从大到小顺序进行排序,指定reverse=True,进行降序排序,默认是False

  • 调用内置函数sorted(),可以指定reverse=True,进行降序排序,原列表不发生改变,id不会变

  • sort()是对原列表进行排序,sorted()是对新列表进行排序

列表生成式

  • 列表生成式简称 生成列表的公式

  • 语法格式:[ i * i for i in range(1,10) ]

i * i 表示列表元素的表达式,自定义, for后面的 i 表示自定义变量,range(1,10)表示可迭代对象

lst=[i for i in range(1,10)] #会产生一个1-9的整数序列,所以用[]括起来,这个列表中存的是产生的整数序列,产生的整数序列是i,所以在for之前加上i

print(lst) #[1, 2, 3, 4, 5, 6, 7, 8, 9]

字典

  • 字典是Python内置的数据结构之一<class 'dict'>,与列表一样是一个可变的序列(进行增删改)

  • 键值对的方式存储数据,字典是一个无序的序列

第一个放进去不一定在第一个位置(它底层会用hash计算键进行放入)

  • 字典会浪费较大的内存,是一种空间换时间的数据结构

  • 无序不可重复

  • 字典中的可以是不可变对象

scores={'张三': 100, '李四' : '98'}

  • 根据key找value

类似于java中的Map,也都是无序不可重复 ,重复即覆盖

字典的创建

  • 最常用的方式:使用花括号

scores={' 张三' : 100, '李四' : 98}

  • 使用内置函数dict()

dict(name = 'jack' , age= 20)

取值与使用get()取值的区别

  • []如果字典中不存在指定的key,抛出keyError异常

  • get()方法取值,如果字典中不存在指定的key,并不会抛出KeyError,而是返回None,可以通过参数设置默认的value,以便指定的key不存在时返回

scores={'张三': 100, '李四' : '98'}

scores.get('哈哈',99) #99是在查找哈哈不存在时候返回99

key的判断

  • in :指定的key在字典中存在返回True

  • not in:指定的key在字典中不存在时返回True

  • 字典的删除:del scores['张三']

  • 字典的新增:scores['jack']=90 没有则新增,有则value覆盖

  • 字典的清空:clear

获取字典视图的三个方法

获取字典视图

  • keys():获取字典中所有key,类型<class 'dict_keys'>

也可以将其转换为列表,list(keys)

  • values():获取字典中所有value,类型<class 'dict_values'>

  • items():获取字典中所有的key,value对

scores={'张三':100,'李四':98,'王五':45}

# 获取所有的key

keys = scores.keys()

print(keys) # dict_keys(['张三', '李四', '王五'])

print(type(keys)) # <class 'dict_keys'>

print(list(keys)) # ['张三', '李四', '王五']

# 获取所有value

values=scores.values()

print(values) # dict_values([100, 98, 45])

print(type(values)) # <class 'dict_values'>

print(list(values)) # [100, 98, 45]

# 获取所有的key-value对

items=scores.items()

print(items) # dict_items([('张三', 100), ('李四', 98), ('王五', 45)])

print(list(items)) # 这个小括号称为元祖[('张三', 100), ('李四', 98), ('王五', 45)]

字典元素的遍历

scores={'张三':100,'李四':98,'王五':45}

for item in scores:

print(item,scores[item],scores.get(item)) # scpres.get()和scores[]都是根据key获取value

输出

张三 100 100

李四 98 98

王五 45 45

字典生成式

  • 内置函数zip()

  • 用于将可迭代的对象作为参数,将对象中对应的元素打包成一个元祖,然后返回由这些元组组成的列表

items=['Fruits','Books','Others']

prices=[96,78,85]

d = {item : price for item,price in zip(items , prices)}

print(d) # {'Fruits': 96, 'Books': 78, 'Others': 85}

# d = {item.upper() : price for item,price in zip(items , prices)} item.upper()会全部变成大写

元组

  • python内置数据结构之一,是一个不可变序列

不可变序列与可变序列

不可变序列

  • 字符串、元组

  • 没有增删改操作

  • 字符串、元组

  • 增删改内存地址发生改变

java中的String同样也是不可变序列
private final char value[]; // 不可变指的是内存地址不能修改

可变序列

  • 列表、字典

  • 可以增删改,对象地址不发生改变

  • <class 'tuple'>

创建方式

  • 直接小括号t = ('Python' , 'hello')

  • 也可以省略小括号:t = ‘Python’ , 'hello'

  • 使用内置函数tuple()

t = tuple( ('Python' , 'hello') )

注意:只包含一个元组的元素需要使用逗号
t = (10 , )
否则会被当成字符串!
空列表创建:
lst = []
lst1 = list ()
空字典:
d = {}
d2 = dict ()
空元组:
t4 = ()
t5 = tuple()

lst = []

lst2 = list()

d = {}

d2 = dict()

t = ()

t2 = tuple()

print('空列表', lst ,lst2)

print('空字典', d,d2)

print('空元组' , t, t2)

输出

空列表 [] []

空字典 {} {}

空元组 () ()

注意:

  • 元组中存储的是对象的引用

  • 如果元组中对象本身是不可变对象,则不能再引用其它对象

  • 如果元组中的对象是可变对象,则可变对象的引用不允许改变,但数据可以改变

t = (10 ,[20,30],9)

print(t)

print(type(t)) # [20, 30]

print(t[1]) # 元组是不能再修改新的地址

t[1].append(100) #列表是可变序列,是可以添加元素的,但是id是不变的

元组的遍历

  • 元组是可迭代对象,所以可以用for in 遍历

t = (10 ,[20,30],9)

for item in t:

print(item)

集合

  • Python提供的内置数据结构

  • 与列表、字典一样都属于可变类型的序列

  • 集合{key}是没有value的字典-{key : value}

  • 不能重复,重复即覆盖

  • 通过hash(dataA)哈希进行计算,第一个放未必在第一个位置

创建方式

  • 直接{} ,和字典区别就是没有value

  • 使用内置函数set()

集合的相关操作

  • in 或者 not in

  • 调用add()方法,一次添加一个元素

  • 调用update()方法至少添加一个元素 ,里面可以添加集合,可以添加列表,元组等

集合元素的删除操作

  • 调用remove()方法,一次删除一个指定元素,如果指定元素不存在,抛出,KeyError

  • 调用discard()方法,一次删除一个指定元素,如果指定元素不存在不抛异常

  • 调用pop()方法,一次只删除一个任意元素,它是随机删除的

  • 调用clear()方法,清空集合

集合之间的关系

两个集合是否相等

  • 可以使用运算符==或!=进行判断

  • 一个集合是否是另一个集合的子集

  • 可以调用方法issubset进行判断

  • B是A的子集

一个集合是否是另一个集合的超集

  • 可以调用方法issuperset进行判断

  • A是B的子集

两个集合是否没有子集

  • 可以调用方法isdisjoint进行判断 (disjoin-adj不相交的,v拆散)

s = {10,20}

s2 = {20,10}

s3 = {10}

print(s==s2) #True

print(s.issubset(s2)) # True

print(s2.issubset(s)) # True

print(s.issubset(s3)) # False

print(s.issuperset(s3)) # True

print(s3.isdisjoint(s)) # Falsexxxxxxxxxx s = {10,20}s2 = {20,10}s3 = {10}print(s==s2) #Trueprint(s.issubset(s2)) # Trueprint(s2.issubset(s)) # Trueprint(s.issubset(s3)) # Falseprint(s.issuperset(s3)) # Trueprint(s3.isdisjoint(s)) # Falses = {10,20}s2 = {20,10}print(s==s2) #True

集合的数学操作

交集:A和B共有的

并集:A和B所有元素加一起的

差集:s1.difference(s2):是求集合s1和s2的差集,即求在s1中同时不在s2中的元素集合,该方法的返回值是二者差集。

对称差集:s1.symmetric_difference(s2):是求集合s1和s2的对称差集,即s1和s2的并集减去二者的交集,该方法的返回值是二者的对称差集。

集合生成式

  • 也就是用于生成集合的公式

{i * i for i in range(1,10)}

  • 将{}改为[] 就是列表生成式

  • 没有元组生成式-不可变序列

列表、字典、元组、集合总结

字符串的创建和驻留机制

  • 在Python中字符串是基本数据类型 ,java中String是引用数据类型

什么是字符串驻留机制

  • 仅保存一份相同且不可变字符串的方法,不同的值,被存放在字符串的驻留池中,Python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量(不会创建新的空间,而是指向已经创建的空间)

a = 'Python'

b = "Python"

c = '''Python'''

print(a,id(a)) # Python 1365644283120

print(b,id(b)) # Python 1365644283120

print(c,id(c)) # Python 1365644283120

Java和Python中等于的区别

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

  • Java只有值传递,所以对于==来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址。

  • java中的equals()方法:用来比较两个对象的内容是否相等

public boolean equals(Object obj) {

return (this == obj);

字符串的驻留机制

驻留机制的几种情况(交互模式-命令窗口)

  • 字符串的长度为0或1时,无论是标识符与否都驻留

  • 符合标识符的字符串

  • 字符串只在编译时驻留,而非运行时

  • [-5,256]之间的整数数字

s = ''

s1 = ''

print(s is s1) # True

s2 = '%'

s3 = '%'

print(s2 is s3) # True

print(a==b) # True a='Python'

print(a is b) # True b="Python"

d = 'abc%' # 非标识符 标识符字母数字下划线

e = 'abc%'

print(d==e) # True

print(d is e) # False 在PyCharm中运行时True,要在交互模式

a = 'abc'

b = 'ab' + 'c' # b的值是在运行之前就已经连接完毕了

c = ''.join(['ab','c']) # c是在程序运行的时候通过join方法连接的,会开辟新的空间,没有驻留

print(type(a)) # <class 'str'>

print(type(b)) # <class 'str'>

print(type(c)) # <class 'str'>

print(a is b) # True

print(a is c) # False

# [-5 - 256]之间的数字也是驻留的

a = -5

b = -5

print(a is b) # True

a = -6

b = -6

print(a is b) # False

# 感觉两个内存地址,这样太浪费空间了,所以我们可以让它存储一个空间

a = 'abc%'

b = 'abc%'

print(a is b) # False

import sys

sys.intern(a)

print(a is b) # True

PyCharm对字符串进行了优化,原本不驻留的,PyCharm进行了驻留

驻留机制的优缺点

  • 当需要值相同的字符串时,可以直接从字符串池中来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串是会比较影响性能的

  • 在需要进行字符串拼接时建议使用str类型的join方法,而非+,因为join()方式是先计算出所有字符串的长度,然后再拷贝,只new一次,效率比+效率高

由于字符串是不可变对象,当使用“+”连接字符串的时候,每执行一次“+”操作都会申请一块新的内存,然后复制上一个“+”操作的结果和本次操作的有操作符到这块内存空间中,所以用“+”连接字符串的时候会涉及内存申请和复制;join在连接字符串的时候,首先计算需要多大的内存存放结果,然后一次性申请所需内存并将字符串复制过去。在用"+"连接字符串时,结果会生成新的对象,而用join时只是将原列表中的元素拼接起来,因此在连接字符串数组的时候会考虑优先使用join。

字符串的常用操作

字符串的查询操作的方法

  • index():查找子串substr第一次出现的位置,如果查找的字符串不存在,抛出ValueError

  • rindex():查找子串substr最后一次出现的位置,如果查找的子串不存在,抛出ValueError

  • find():查找子串substr第一次出现的位置,不存在返回-1

  • rfind():查找子串substr最后一次出现的位置,如果查找的子串不存在,返回-1

  • r:reserve v.n.adj都表示相反的、逆转、背面的意思,

  • 建议用find方法,不跑异常

字符串的大小写转换操作的方法

  • upper(): 把字符串所有字符都转成大写字母

  • lower():把字符串中所有字符都转成小写字母

  • swapcase():大小写转换,大写变小写,小写变大写

  • capitalize():把第一个字符转换为大写,其余转小写

  • title,第一个转大写,每个单词首字母大写,其余小写

字符串内容对齐操作的方法

  • center():居中对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数是可选的,默认是空格,如果设置的宽度小于实际宽度则返回源字符串

  • ljust():左对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数是可选的,默认是空格,如果设置的宽度小于实际宽度则返回源字符串

  • rjust():右对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数是可选的,默认是空格,如果设置的宽度小于实际宽度则返回源字符串

  • zfill():右对齐,左边用0填充,该方法只接受一个参数,用于指定字符串的宽度,如果指定的宽度小于等于字符串的长度,返回字符串本身

s = 'hello,Python'

print(s.center(20,'*')) # ****hello,Python****

# 共指定20个字符,减去原有12个居中对齐,左右补充 *

print(s.ljust(20,'*')) # hello,Python********

print(s.rjust(20,'*')) # ********hello,Python

print(s.zfill(20)) # 00000000hello,Python

print('-666888'.zfill(8)) # -0666888

字符串的劈分

  • split():从字符串左边开始劈分,默认的劈分字符是空格字符串,返回值的值是一个列表

以通过参数sep指定劈分字符串是的劈分符

通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独作为一部分、

  • rsplit():从字符串的右边开始劈分,默认的劈分字符是空格字符串,返回的值是一个列表

  • 以通过参数sep指定劈分字符串是的劈分符

  • 通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大劈分之后,剩余的子串会单独作为一部分

s = 'hello world Python'

print(s.split()) # ['hello', 'world', 'Python']

s1 = 'hello|world|Python'

print(s1.split(sep='|')) # ['hello', 'world', 'Python'] 这是已经分割的

print(s1.split(sep='|',maxsplit=1)) # ['hello', 'world|Python']

# rsplit同理

判断字符串操作的方法

  • isidentifier():判断指定的字符串是不是合法的标识符

  • isspace():判断指定的字符串是否全部由空白字符组成(回车、换行、水平制表符)

  • isalpha():判断指定字符是否全部由字母组成,汉字也算(unicode编码就会这样)

  • isdecimal():判断指定字符是否全部由十进制的数字组成

  • isnumeric():判断指定的字符串是否全部由数字组成

  • isalnum():判断指定字符串是否全部由字母和数字组成

s = 'hello,Python'

print('1.',s.isidentifier()) # False 有, 只要非数字字母下划线都非标识符

print('2.','hello_123'.isidentifier()) # True

print('3.','\t'.isspace()) # True

print('4.','abc'.isalpha()) # True

print('5.','张三'.isalpha()) # True

print('6.','张三1'.isalpha()) # False

print('7.','123四'.isdecimal()) # False

print('8','123'.isnumeric()) # True

print('9','123哈哈哈'.isalnum()) # True

字符串操作的其它方法

字符串替换

  • replace() 第一个参数指定被替换的子串,第二个参数指定替换子串的字符串,该方法返回替换后得到的字符串,替换前的字符串不发生变化,调用该方法时可通过第三个参数指定最大替换次

字符串的合并

  • join() 将字符串合并成一个字符串,如果是字典,则只连接key

注意:如果有数字什么的不能连接,只能连接字符串

s = 'hello,Python'

print(s.replace('Python','Java')) # hello,Java

s1 = 'hello,Python,Python,Python'

print(s1.replace('Python','Java',2)) # hello,Java,Java,Python

print('|'.join(lst)) # hello|Java|Python

print(''.join(lst)) # helloJavaPython

t = ('hello','Java')

print(''.join(t)) # helloJava

字符串的比较操作

  • 运算符:>,>=,<,<=,==,!=

  • 比较规则:从第一个字符依次比较下去,直到两个字符串中的字符不相等时,其比较结果就是两个字符串的比较结果,两个字符串中的所有后续将不再比较

  • 比较原理:比较的是ordinal value(原始值),调用内置函数ord可以,得到指定字符的ordinal value ,与内置函数ord对应的是内置函数chr,调用内置函数chr时可以指定oridnal value可以得到对应的字符

字符串的切片操作

字符串是不可变类型

  • 不具备增、删、改等操作

  • 切片操作都将产生新的对象,和列[]列表一样

[start,end,step]

  • s[:5]它会从0开始且,且到4,不包含5

  • s[6:]它会从6开始,切刀最后

s = 'hello,Java'

s1 = s[:5]

print(s1)

s2 = s[6:] # hello

print(s2) # Java

a = '666888'

print(a[::2]) #668

格式化字符串

为什么要格式化字符串

  • 因为很多相同操作占取空间,大量重复操作

  • 比如:身份证号: 现居家庭住址:等等

格式化字符串的两种方式

  • %作占位符

  • %s表示字符串,%i或%d表示整数

  • %f表示浮点数

  • {}作占位符

%叫做定义的格式化字符串,%是固定符号 (name,age)是实际值

# %占位符

name = '张三'

age = 20

print('我叫%s,今年%d岁'% (name,age)) # 我叫张三,今年20岁

# {}格式化操作

print('我叫{0},今年{1}岁'.format(name,age) ) # 我叫张三,今年20岁

# f-string

print(f'我叫{name},今年{age}岁') # 我叫张三,今年20岁

# %10d,10表示宽度

print('%10d' % 99) # 99

# %f表示浮点数,%.3是小数点后三位小数

print('%.3f' % 3.1415926)

# %10.3f同时表示宽度和精度

print('%10.3f' % 3.1415926)#3.142 总宽度是10,小数点后三位

# 用{}形式也能注册 ,.3表示的一共是三位数

print('{0:.3}'.format(3.1415926))

# .3f表示3位小数

print('{0:.3f}'.format(3.1415926))

# 同时设置宽度

# print('{:10.3f}'.format(3.1415926))

为什么需要字符串的编码转换

str在内存中以UNICODE表示,将计算机中的内容传送到你的电脑上去,这时候就需要字节进行传输,这时候就需要将str转换成二进制数据传送到你的电脑上,你的电脑再进行转换成str进行展示

  • 编码:将字符串转换为二进制数据(bytes)

  • 解码:将bytes类型的数据转换成字符串类型

  • 注意:编码格式和解码格式要相同

s = '解码编码操作'

# 编码

print(s.encode(encoding='GBK')) # GBK这种编码格式中,一个中文是二个字节

print(s.encode(encoding='UTF-8')) # UFT-8这种编码格式中,一个中文是三个字节

#

# 解码

# byte代表就是一个二进制数据 (字节类型的数据)

byte = s.encode(encoding='GBK') # 编码

# print(byte.decode(encoding='UTF-8 ')) # 解码 报错,用什么编码,用什么解码

byte = s.encode(encoding='UTF-8')

print(byte.decode(encoding='UTF-8')) # 解码编码操作

输出

b'\xbd\xe2\xc2\xeb\xb1\xe0\xc2\xeb\xb2\xd9\xd7\xf7'

b'\xe8\xa7\xa3\xe7\xa0\x81\xe7\xbc\x96\xe7\xa0\x81\xe6\x93\x8d\xe4\xbd\x9c'

解码编码操作

函数

什么是函数?

  • 函数就是执行特定任务和以完成特定功能的一段代码

为什么需要函数

  • 复用代码

  • 隐藏实现细节

  • 提高可维护性

  • 提高可读性便于调试

函数的创建

  • def 函数名 ([输入参数]) :

函数体

[return xxx]

  • 函数名需要遵循字母、数字、下划线

# 这里的a,b是形式参数-形参,形参的位置是在函数的定义处

def calc(a,b):

c = a+b

return c

print(calc(10,50)) # 60 这里的10,50称为实际参数的值,简称实参

print(calc(b=50,a=10)) #=左侧的变量名称为关键字参数,自动找a和b

定义函数取奇偶数

def fun(num):

odd = [] # 存奇数

even = [] # 存偶数

for i in num:

if i%2:

odd.append(i)

else:

even.append(i)

return odd,even

lst=fun([10,21,33,66,88,99])

print(lst) # ([21, 33, 99], [10, 66, 88])

  • 如果函数没有返回值【函数执行完毕之后,不需要给调

  • 用处提供数据】 return可以省略不写

  • 函数的返回值,如果是1个,直接返回类型

  • 函数的返回值,如果是多个,返回的结果为元组

函数的参数定义

  • 函数定义默认值参数

  • 函数定义时,给形式参数设置默认值,只有与默认值不符的时候才需要传递实参

def fun(a,b=10)

print(a,b)

fun(100) #只传一个参数,b采用默认值

fun(20,30) #30将默认值10替换

个数可变的位置参数

  • 定义参数时,可能无法事先确定传递的位置实参的个数时,使用可变的位置参数

  • 使用*定义个数可变的位置形参

  • 只能定义一个,def fun(* args,*a):这样报错

  • 结果为一个元组

def fun(*args): # 函数定义时的 可变的位置参数

print(args)

fun(10)

fun(10,30)

fun(30,405,50)

"""

结果

(10,) 注意元组有, 逗号,否则为字符串了

(10, 30)

(30, 405, 50)

"""

个数可变的关键字形参

  • 定义函数时,无法事先先确定传递的关键字实参的个数时,使用可变的关键字形参

  • 使用**定义个数可变的关键字形参

  • 只能定义一个,def fun(** args, **a):这样报错

  • 结果为一个字典

def fun1(**args):

print(args)

fun1(a=10) # {'a': 10}

fun1(a=20,b=30,c=40) # {'a': 20, 'b': 30, 'c': 40}

print源码

  • 它是一个形式可变的位置参数,所以print('这里写几个都没问题')

def print(self, *args, sep=' ', end='\n', file=None):

注意:

  • 在一个函数定义过程中,既有个数可变的关键字形参,也有个数可变的位置形参,要求,个数可变的位置形参,放在个数可变的关键字形参之前

def fun(**args1,*arg2):

  • 在函数调用时的参数传递,称为位置传参

def fun(a,b,c):

print(a,end='\t')

print(b,end='\t')

print(c,end='\t')

fun(10,20,30) # 10 20 30 函数调用时的参数传递,称为位置传参

lst = [11,22,33]

# fun(lst) #报错

fun(*lst) # 11 22 33 在函数调用时,将列表中的每个元素都转换为位置实参传入

dic = {'a':111,'b':222,'c':333}

# fun(dic) #报错

fun(**dic) # 111 222 333 在函数调用时,将字段的键值对都转换为关键字实参传入

# 个数可变的关键字传参

def fun4(**args):

print(args)

fun4(a=666,b=888) # {'a': 666, 'b': 888}

函数传参其它类型

def fun5(a,b,*,c,d):

print(a)

print(b)

print(c)

print(d)

fun5(a=10,b=20,c=30,d=40) # 10 20 30 40

# fun5(10,20,30,d=40) # 错误 前两个参数采用的是位置实参传递,c,d只能采用关键字传递

fun5(10,20,c=30,d=40) # 10 20 30 40

# 这些也都是可以的

def fun5(a,b,*,c,d,**args):

print(args)

fun5(1,3,c=3,d=4,e=4) # {'e': 4}

def fun(*args,**args2):

pass

def fun(*args,**args2):

pass

def fun(a,b=10,*args,**args2):

pass

变量的作用域

  • 程序代码能访问该变量的区域

  • 根据变量的有效范围可分为

局部变量:

  • 在函数内定义并使用的变量,只在函数内部有效,局部变量使用global声明,这个变量就会成为全局变量

全局变量

  • 在函数体外定义的变量,可作用函数内外

def fun():

global age # 声明global在外部也可以使用了

age=20

print(age) # 20

fun()

print(age+1) # 21

递归函数

什么是递归函数

  • 在函数体内调用了函数本身

递归的组成部分

  • 递归调用与递归终止条件

递归的调用过程

  • 每递归调用一次函数,都会在栈内存分配的一个栈帧

  • 每执行完一次函数,都会释放相应的空间

递归的优缺点

  • 优点:占用内存多,效率低下

  • 缺点:思路和代码简单

斐波那契数列

形如1 1 2 3 5 8..每一项都前两项之和

# 斐波那契数列

def fib(n):

if n == 1 or n == 2:

return 1

else:

return fib(n-1)+fib(n-2)

print(fib(3)) # 2

# 输出前四项数组

for i in range(1,5):

print(fib(i)) # 1 1 2 3

Python的异常处理机制

  • Bug的常见类型

  • Python提供了异常处理机制,可以在异常出现时即时捕获,然后内部“消化”,让程序继续运行

多个except结构

  • 捕获异常的顺序按照先子类后父类的顺序,为了避免遗漏可能出现的异常,可以在最后增加BaseException

try...except...else结构

  • 如果try块中没有抛出异常,则执行else块,如果try中抛出异常,则执行except块

try...except...else..finally结构

  • finally块无论是否发生异常都会被执行,能常用来释放try块中申请的资源

案例1

try:

a = int(input('请输入第一个整数:'))

b = int(input('请输入第二个整数:'))

result = a/b

print('结果为:',result)

except ZeroDivisionError:

print('对不起,除数不能为0')

except ValueError:

print('只能输入数字串')

print('程序结束')

案例2

try:

a = int(input('请输入第一个整数:'))

b = int(input('请输入第二个整数:'))

result = a/b

except BaseException as e:

print('出错了',e)

else:

print('计算结果为:',result)

finally:

print('谢谢你的使用')

Python中常见的异常

  • ZeroDivisionError :除(或取模)零(所有数据类型)

  • IndexError:序列中没有此索引(index)

  • KeyError:映射中没有这个键

  • NameError:未声明/初始化对象(没有属性)

  • SyntaxError:Python语法错误

  • ValueError:传入无效的参数

traceback

  • 使用traceback模块打印异常信息

import traceback

try:

a = 1/0

except:

traceback.print_exc()

输出

  • 这些日志信息放到日志文件里面还是有用的

Traceback (most recent call last):

File "F:\pythonProject1\venv\test.py", line 3, in <module>

a = 1/0

ZeroDivisionError: division by zero

面向对象

类和对象

一切皆对象,和java一样,各编程语言一样的思想

规范:

  • 类名首字母大写,和java一样

  • 创建的规范

  • python3创建类的时候,可以不带括号,也可以带,也可以显示继承object,如果带个()空括号,其实也是隐士的继承了object。这三种方式是相等的。

class Student:

pass

类的组成

  • 类属性:类中方法外,被该类所有对象共享

  • 类方法:@classmethod修饰,使用类名直接访问的方法

  • 静态方法@staticmethod,使用类名直接调用

  • 类属性、类方法、静态方法都是用类名直接调用

  • 实例方法

# 创建的语法

class Studnet:

native_pace = '吉林' # 类属性

# 初始化方法 这个self赋值时候不用写,赋值name和age即可,self默认带

def __init__(self,name,age): # 将局部变量的值赋值给实体属性,self.name称为实例属性

self.name = name

self.age = age

# 实例方法

# self 为这个方法名,name,age的为实例属性

def eat(self): # 这个self这里必写,self单词可以变,但程序员习惯self

print('学生在吃饭')

# 在类外定义的称为函数,类之内称为方法

# 类方法

@classmethod

def cm(cls):

print('类方法')

# 静态方法中不能写self,注意

@staticmethod

def sm():

print('静态方法')

# 类之外定义的称为函数,在类之内定义的称为方法

def drink():

print('喝水')

对象的创建

  • 和java一样

  • 对象的创建又称为类的实例化

  • 语法:

  • 实例名=类名()

  • 如stu = Student()

  • 实例对象会有个类指针指向类对象

  • 类名.方法名(类的对象),实际上就是方法定义处的self

Stu1 = Student('张三',20)

Student.eat(stu1)

动态绑定属性和方法

  • Python是动态语言,在创建对象之后,可以动态地绑定属性和方法

stu1 = Studnet('张三',20)

stu2 = Studnet('李四',30)

print(id(stu1)) # 和stu2不同

print(id(stu2))

print('--------为stu2动态绑定性别属性-----------')

stu2.gender = '女' # 这点和java不一样,java没有成员变量(属性-字段),是不能指定的

# Student中没有 gender属性 能动态绑定性别 ,只属于stu2自己

print(stu2.gender) # 女

def show():

print('定义在类之外的,称函数')

stu1.show = show()

stu1.show # 定义在类之外的,称函数

stu2.show # 报错 没有胃stu2动态绑定show方法,在对象上之后函数就称为方法了

面向对象的三大特征

  • 封装:提高程序的安全性

  • 将数据(属性)和行为(方法)包装到类中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度

  • 在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前面使用两个"-"

  • 继承:提高代码的复用性

  • 如果一个类没有继承任何类,默认继承object

  • Python支持多继承(java不支持多继承)

  • 定义子类时,必须在其构造函数中调用父类的构造函数

  • 多态:提高程序的可扩展性和维护性

封装

class Student:

def __init__(self,name,age):

self.name = name

self.__age = age

def show(self):

print(self.name,self.__age)

stu = Student('张三',20)

# 在类外部使用name、age

print(stu.name) # 张三

# print(stu.__age) # 报错

print(dir(stu)) # dir()可以查看类的所有属性和方法 ,里面找到一个_Student__age

print(stu._Student__age) # 这样也能访问,但是不建议这种访问方式

class Student2:

def __init__(self,age):

self.set_age(age)

def get_age(self):

return self.__age # 不希望在外面使用,所以加上两个__

def set_age(self,age):

if 0<=age<=120:

self.__age = age

else:

self.__age = 18

stu1 = Student2(150)

stu2 = Student2(30)

print(stu1.get_age()) # 18

print(stu2.get_age()) # 30

继承

class Person(object): #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,score):

super().__init__(name,age)

self.score = score

def info(self):

super.info()# 还想用父类的info()可以super.

print(self.score)# 重写

# 测试

stu = Student('Haha',20,'1001')

stu.info() # 从父类中继承的方法 ,重写后就是Student的方法了

object类

  • object类是所有类的父类,因此所有类都有object类的属性和方法

  • 内置函数dir()可以查看指定对象的所有属性

  • Object有一个_ str_ ()方法,用于返回一个对于“对象的描述”,对于内置函数str()进程用于print()方法,帮我们查看对象的信息,所以我们经常会对__str _()进行重写,而不是输出内存地址

重写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('Haha',20)

print(stu) # 我的名字是Haha,今年{20}岁 默认调用_str_()这样的方法

多态

  • 指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度

  • Python中虽然没有数据类型,但是具备多态特征

class Animal:

def eat(self):

print('eating...')

class Dog(Animal):

def eat(self):

print('dog gnawing...')

def fun(obj):

obj.eat()

fun(Animal()) # eating...

fun(Dog()) # # dong gnawing

Java是静态,强类型语言,Python是动态语言
  • 静态语言和动态语言关于多态的区别

静态语言实现多态的三个必要特征

  • 继承

  • 方法重写

  • 父类引用执行子类对象

动态语言的多态的多态崇尚“鸭子类型”,当看到一只鸟走起来像鸭子、游泳像鸭子,收起来也像鸭子,那么这鸟就可以被称为鸭子;
在鸭子类型中,不用对象是什么类型,到底是不是鸭子,只关心对象的行为

特殊方法和特殊属性

特殊属性

  • _ dict __ :获得类对象或实例对象所绑定的所有属性和方法

  • __ len __():通过重写它,让内置函数len()的参数可以是自定义类型

特殊方法

  • _add _():通过重写它,让内置函数len()的参数可以是自定义类型

  • _new _():用于创建对象

  • _init() _:对创建的对象进行初始化

class A:

def __init__(self,name,age):

self.name = name

self.age = age

x = A('Jack',18)

print(x.__dict__) #{'name': 'Jack', 'age': 18}

print(x.__class__) # <class '__main__.A'> 所属的类

class B(A):

pass

print(B.__base__) # <class '__main__.A'> # 类的基类,如果多继承,谁在前输出谁

print(B.__bases__) # (<class '__main__.A'>,) 输出其父类类型的元素

print(B.__mro__) # 继承层次结果 B继承A继承object (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

print(A.__subclasses__())#子类列表 [<class '__main__.B'>]

a = 20

b = 100

c = a + b

d = a.__add__(b) #等同于+

print(c)

print(d)

class Student:

def __init__(self,name):

self.name = name

def __add__(self, other): # 必须在这里写,stu1.__add_(stu2)这样也报错

return self.name + other.name

def __len__(self): # 必须写在这里才能计算长度

return len(self.name)

stu1 = Student('张三')

stu2 = Student('李四')

s = stu1 + stu2 # 写了__add__方法才能加,否则报错

print(s) # 张三李四

lst = [1,2,3,4,5]

print(len(lst)) # 5

print(lst.__len__()) # 5

print(stu1.__len__()) # 2

new执行是优先于init的。new后的对象会给__ init __中的self

类的浅拷贝与深拷贝

  • 变量的赋值操作

  • 只是形成两个变量,实际上还是指向同一个对象

  • 浅拷贝

  • Python拷贝如果没特殊说明的话,一般都是浅拷贝,拷贝时,对象包含的子对象的内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象

  • 深拷贝

  • 使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同

  • 源对象和拷贝对象的所有子对象也要重新拷贝一份

浅拷贝

class CPU:

pass

class Disk:

pass

class Computer:

def __init__(self,cpu,disk):

self.cpu = cpu

self.disk = disk

cpu1 = CPU()

cpu2 = cpu1 # 这个是赋值操作

print(cpu1,cpu2) # 内存地址一样

# <__main__.CPU object at 0x000001A54423FF40> <__main__.CPU object at 0x000001A54423FF40>

print('----------------------')

disk = Disk() # 创建一个硬盘

computer = Computer(cpu1,disk) # 创建一个计算机类的对象

# 浅拷贝

import copy

computer2 = copy.copy(computer)

print(disk)

# # <__main__.Disk object at 0x000001E1026AF3D0>

print(computer,computer.cpu,computer.disk)

# computer2和computer内存地址不同,子对象的内存地址是相同的-Disk和CPU

# <__main__.Computer object at 0x000001A543EF4850> <__main__.CPU object at 0x000001A54423FF40> <__main__.Disk object at 0x000001A54423F3D0>

print(computer2,computer2.cpu,computer2.disk)

# <__main__.Computer object at 0x000001A5442928F0> <__main__.CPU object at 0x000001A54423FF40> <__main__.Disk object at 0x000001A54423F3D0>

print('---------------------------')

# 深拷贝

computer3 = copy.deepcopy(computer)

print(computer,computer.cpu,computer.disk)

print(computer3,computer.cpu,computer3.disk)

# 打印的内存地址各不同,computer、cpu、disk都拷贝了一份,内存地址变化了

# <__main__.Computer object at 0x00000265D67B3E80> <__main__.CPU object at 0x00000265D67B3FD0> <__main__.Disk object at 0x00000265D67B3EB0>

# <__main__.C

深拷贝

多态对于:动态语言关注对象的行为
静态语言:继承、方法重写、父类引用指向子类对象

模块

  • 英文为Modules

  • 一个模块可以包含N多个函数

  • 在Pyhton中一个扩展名.py的文件就是一个模块

使用模块的好处

  • 方便其它程序和脚本的导入并使用

  • 避免函数名和变量名冲突

  • 提高代码的可维护性

  • 提高代码的可重用性

自定义模块

创建模块

  • 新建一个.py文件,名称尽量不要与Python的自带的标准名称相同

  • 导入模块

  • import 模块 [as 别名]

  • from 模块名称 import 函数/变量/类

import math # 导入数学模块 每一个模块都有id、type以及它的值组成

print(id(math))

print(type(math))

print(math)

print(math.pi) # 3.141592653589793

#2051647076960

#<class 'module'>

#<module 'math' (built-in)>

print(dir(math))

from math import pi

print(pi) # 这是能直接输出的

print(pow(2,3)) # 如果不导入math,只导入from math import pi 是不能使用的

以主程序形式运行

  • 在每个模块的定义中都包括一个记录模块名称的变量_ name _,程序可以检查该变量,以确定它们在哪个模块中执行,如果一个模块不是被导入到其它程序中执行,那么它可能在解释器的顶级模块中执行。顶级模块的 _ name _变量的值为 _main _

# 开发时间:2023/2/11

def add(a,b):

return a+b

if __name__ == '__main__':

print(add(10,20)) # 只有当运行这个calc2的时候才会执行这个主程序语句,可防止其它程序调用此类运行这个

Python中的包

  • Python中的包

  • 包是一个分层次的目录结构,它将一组功能相近的模块组织在一起(包中包含N多个模块)

  • 作用:

  • 代码规范

  • 避免模块名称冲突

  • 包与目录的区别

  • 创建之后默认包含__ init __ .py文件的目录称为包

  • 目录里通常不包含_init _ .py文件

  • 包的导入

  • import 包名.模块名(import只能导入包名、模块名)

  • 用from 能导入包、模块、函数名、变量名 pageage1.module_A import ma

比如

  • 创建python软件包

  • 在下面新建pageage1,下面创建2模块-module_A.py/moduleB.py

  • 在外面创建demo.py

import pageage1.module_A as ma

# 现在就可以使用pageage1.module_A的内容了(别名叫ma)

Python中常用的内置模块

模块名

描述

sys

与Python解释器及其环境操作相关的标准库

time

提供与时间相关的各种函数的标准库

os

提供了访问操作系统服务功能的标准库

calendar

提供与日期现相关的各种函数的标准库

urllib

用于读取来自网上(服务器)的数据标准库

json

用于使用序列号和反序列化对象

re

用于在字符串中执行正则表达式匹配和替换

math

提供标准算术运算函数的标准库

decimal

用于进行准确控制精度、有效位数和四舍五入的十进制运算

logging

提供灵活的记录事件、错误、警告和调试信息等日志信息的功能

简单的代码实现

import sys

import time

import urllib.request

import math

# getsizeof是获取占用字节数

print(sys.getsizeof(20)) # 28

print(sys.getsizeof(21)) # 28

print(sys.getsizeof(True)) # 28

print(sys.getsizeof(False)) # 24

print(time.time()) # 对应秒数 1676127718.0125294

print(time.localtime(time.time())) # 将秒转成本地时间time.struct_time(tm_year=2023, tm_mon=2, tm_mday=11, tm_hour=23, tm_min=1, tm_sec=58, tm_wday=5, tm_yday=42, tm_isdst=0)

print(urllib.request.urlopen('http://ww.baidu.com').read())

print(math.pi)

第三方模块

  • Python如此强大,离不开第三方模块

  • 第三方模块的安装

  • pip install 模块名(在线安装方式-cmd安装-也是使用最多的方式)

  • 第三方模块的使用

  • import 模块名(安装导入之后我们就可以使用)

  • 在cmd窗口,我们可以输入python进入python交互模式

  • 此时import使用已经安装的模块如果能使用证明安装成功

编码格式

  • 编码格式介绍

  • 文件的读写原理

  • 文件读写操作

  • 文件对象常用的方法

  • with语句(上下文管理器)

  • 目录操作

常见的字符编码格式

  • Python的解释器使用的是Jnicode(内存)

  • py文件在磁盘上使用UTF-8存储(外存)

py默认是UTF-8,它是变长编码,1-4个字节表示1个字符,英文1个字节,汉字3个字节

文件读写原理

  • 读写俗称IO操作-先进先出,如管道一般

  • 文件到内存称为读,内存到文件称为写

  • 读写之后需要关闭资源

文件读写操作

  • 内置函数open()创建文件对象

  • 语法规则:file = open(filename,[,mode,encoding])

  • file 是被创建的文件对象,open是创建文件对象的函数,

  • filename:是要创建或打开的文件名称,

  • mode:打开模式为只读模式

file = open('a.txt','r') # 读,中括号是可选,写不写都行

print(file.readlines()) # readlines读取的是一个列表

file.close()

  • encoding:默认文本文件中字符的编写格式为gbk(所以我们在编译器中常见一打开乱码,并提示reload gbk)

常用的文件打开模式

  • 文件的类型

  • 按文件中数据的组织形式,文件分为以下两大类

  • 文本文件:存储的是普通“字符"文本,默认为unicode:字符集,可以使用记本事程序打开

  • 二进制文件:把数据内容用“字节”进行存储,无法用记事本打开,必须使用专用的软件打开,举例:mp3音频文件,jpg图片.doc文档等

打开模式

描述

r(read only)

以只读模式打开文件,文件的指针将会放在文件的开头

w(write only)

以只写模式打开文件,如果文件不存在则创建,如果文件存在,则覆盖原有内容,文件指针在文件的开头

a

以追加模式打开文件,如果文件不存在则创建,文件指针在文件开头,如果文件存在,则在文件末尾追加内容,文件指针在原文件末尾

b

以二进制方式打开文件,不能单独使用,需要与共它模式一起使用,rb,或者wb

+

以读写方式打开文件,不能单独使用,需要与其它模式一起使用,a+

文件对象的常用方法

方法名

说明

read([size])

从文件中读取size个字节或字符的内容返回。若省略[size],则读取到文件末尾,即一次读取文件所有内容

readline()

从文本文件中读取一行内容

readlines()

文本文件中的每一行都作为单独的字符串对象,并将这些对象返回到列表中返回

write(str)

将字符串str内容写入文件

writelines(s_list)

将字符串列表s_lst写入文本文件,不添加换行符

seek(offset[,whence])

把文件指针移动到新的位置,offset表示相对于hencel的位置:offset:为正往结束方向移动,为负往开始方向移动whence(从何处)不同的值代表不同含义:0:从文件头开始计算(默认值)1:从当前位置开始计算2:从文件尾开始计算

tell()

返回文件指针的当前位置,第一个字母是0,也就是从0开始

flush()

把缓冲区的内容写入文件,但不关闭文件

close()

把缓冲区的内容写入文件,同时关闭文件,释放文件对象相关资源-close()之后就不能写内容了,flush之后能close

file = open('a.txt','r')

file = seek(2) # a.txt有中国两字。一个字占取2字节(gbk),从国开始读(如果在pyCharm中写的txt,可能就是utf-8了,不是2字节)

print(file.read()) # 国

# tell

print(file.tell()) # 会把当前所有内容打印出,指向最后一个位置。如seek(2)跳过了2,如果打印hello的话只会出现llo

with语句

  • with语句可以自动管理上下文资源,不论什么原因跳出with块,都能确保文件正确的关闭,以此来达到释放资源的目的

  • 写文件时建议使用with语句形式

上下文为表达式,结果为上下文管理器

实现了__ enter__ () 方法和 __ exit()__方法 称为这个类遵守上下文管理协议,这个类的实例对象称为上下文管理器
图描述如下:

# open('logo.png','rb') with之后as之前为上下文表达式,结果为上下文管理器-->同时创建一个运行时上下文-->自动调用_enter_()方法,并将返回值赋值给src_file

with open('logo.png','rb') as src_file:

# as src_file:可选项上下文管理器对象的引用[可选项]

src_file.read() # with语句体

# 离开运行时上下文,自动调用上下文管理器的特殊方法_exit_()

with open('a.txt','r') as file:

print(file.read()) # 不用再手动close关闭了,因为离开with语句时会自动释放资源

# 开发时间:2023/2/12

# MyContentMgr实现了特殊方法__enter__(),__exit__()称为该类对象遵守了上下文管理器协议,该类对象的实例对象,称为上下文管理器

class MyContentMgr(object):

def __enter__(self):

print('enter方法被调用执行了')

return self

def __exit__(self, exc_type, exc_val, exc_tb):

print('exit方法被调用执行了')

# print('show方法被调用执行了',1/0) 即使产生异常也会调用exit方法,称为自动关闭资源

def show(self): # 实例Method

print('show方法被调用执行了')

# MyContentMgr这个类遵守上下文管理协议,它的对象就称为上下文管理器,把这个对象赋给file去存储

# 相当于file = MyContentMgr(),这时候就可以通过file调用它的方法

# with里面的所有缩进都称为with语句体

with MyContentMgr() as file:

# 这个with语句体执行之后就会自动跳出上下文管理器,调用exit方法

file.show() # exit方法被调用执行了

目录操作

  • os模块是Python内置的与操作系统功能和文件系统相关的模块

该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样。

os模块与os.path模块用于对目录或文件进行操作

  • 既然是和os有关的,那么可以调用os有关的文件

  • 不需要安装,它是自带的模块

os模块操作目录相关函数

函数

说明

getcwd()

返回当前的工作目录(文件目录)

listdir(path)

返回指定路径下的文件和目录信息

mkdir(path[,mode])

创建目录

makedirs(path1/path2...[,mode])

创建多级目录

rmdir(path)

删除目录

removedirs(path1/path2......)

删除多级目录

chidr(path)

将path设置为当前工作目录

import os

# 调用记事本

# os.system('notepad.exe')

# 直接调用可执行文件

# os.startfile('C:\\Users\\79382\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe')

os.path模块操作目录

import 导入os.path

函数

说明

abspath(path)

用于获取文件或目录的绝对路径

exists(path)

用于判断文件或目录是否存在,如果存在返回True,否则返回False

join(path,name)

将目录与目录或者文件名拼接起来

splitext()

分离文件名和扩展名

basename(path)

从一个目录中提取文件名

dirname(path)

从一个路径中提取文件路径,不包括文件名

isdir(path)

用于判断是否为路径

import os.path
print(os.path.abspath('demo13.py')) # F:\pythonProject1\venv\Scripts\demo13.py
print(os.path.exists('demo13.py')) # False
print(os.path.join('E:\\Python','demo13.py')) # E:\Python\demo13.py
print(os.path.split('E:\\vipython\\chap15\\demo13.py')) # ('E:\\vipython\\chap15', 'demo13.py')
print(os.path.splitext('demo13.py')) # ('demo13', '.py')
print(os.path.basename('E:\\vippython\\chap15\\demo13.py')) # demo13.py
print(os.path.dirname('E:\\vippython\\chap15\\demo13.py')) # E:\vippython\chap15
print(os.path.isdir('E:\\vippython\\chap15\\demo13.py')) # False 因为demo13.py是文件
获取当前目录下的指定文件
import os
path = os.getcwd() # 获取当前目录下的所有文件
lst = os.listdir(path)
for filename in lst: # 获取所有以py结尾的文件
    if filename.endswith('.py'):
        print(filename)
获取当前目录下的指定文件(包括子目录)
import os
path = os.getcwd()
# os.walk()可以遍历指定目录下所有的文件
lst_files = os.walk(path)
print(lst_files) # 获取的是一个对象
# 这个迭代器对象返回来的是一个元组
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('------------------------------')

微信公众号:索奇之家 一起探索软件、编程、数码等众多知识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

即兴小索奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值