【python基础教程,带你入门python,各种语法都列举了例子清晰易懂】

文章目录

前言

本文讲述python的基础知识,内容过多,建议收藏阅读。
如果你能把本文看完,并且把每个代码运行都自己敲打执行一遍,必能入门python!!!

在这里插入图片描述

1 Python程序基本结构

Python 程序结构涉及代码块、注释、语句分隔、语句续行、关键字与大小写等内容

1.1 代码缩进

在Java 、C/C++等语言中,用花括号表示代码块,例如:

if(x > 100){
    y = x *5 -1;
}else{
    y = 0; 
}

Python使用缩进(空格)来表示代码块。通常,语句末尾的冒号表示代码块的开始。在if、for、while、函数、类等定义中都会使用到代码块。例如:

if x > 100:
    y = x *5 -1
else:
    y = 0

在包含代码嵌套是,冒号代表语句块的开始,应注意同级代码块的缩进量应保持相同:

x = 5
if x < 0:
    print("参数X的值不合法")
    print('X < 0')
else:
    for i in [1,2,3,4,5]:
        print(i)
    print('X > 0')
print(x)

编码规范:使用空格来缩进,tab在不同环境下对应空格长度可能发生变化,在某些ide上tab键可能是8个空格长度

1. 2 代码注释

注释用于为程序添加说明文字,当Python运行程序时,会忽略掉被注释的内容。

1.2.1 单行注释

单行注释用“#”表示注释开始,“#”之后的语句不会被编译器执行。单行注释可以单独占一行,也可以放在语句末尾。

# 注释单独占一行,定义一个变量n
n = 0
---------------------------------------
b = 100  # 注释放在语句末尾,定义的变量b

1.2.2 多行注释

多行注释使用三个英文的单引号“ ‘’’ ”或者双引号“ “”" ”作为注释的开始和结束符号。

'''多行注释,这个是开头的三个单引号,
         这是一段内容
   这是结束的三个单引号'''
----------------------------------
"""多行注释,这个是开头的三个双引号,
         这是一段内容
   这是结束的三个双引号"""

1.3 语句分隔

使用分号分隔语句,从而将多条语句写在一行。

print(100);print(2+3)  

如果冒号之后的语句块只有一条语句,Python允许将语句写在冒号之后,冒号之后可以是分号分隔的多条语句。

if x > 1:y = x **2 
else:y=1;print('x <= 1')   #冒号(:)后的每一个语句缩进量相同

1.4 语句续行

通常,Python中的一条语句占一行,没有类似于Java中的分号等语句结束符号。在遇到较长的语句时,可使用语句续行符号,将长语句写在多行中。
使用“\”符号续行

if x < 100\
    and z > 10:
    y = x*5-1
else:
    y = 0

使用括号续行(包括使用圆括号()、方括号[]和大括号{}等),在使用括号时,括号内的内容可分多行书写,括号中的空白和换行符都会被忽略。

if x < 100\
    and z > 1:
    y = x*5-1
else:
    y = 100

1.5 关键字与大小写

Python中也有各种标识符,如if、for、while等,可称为关键字。
Python对大小写敏感,关键字和各种自定义的标识符(如变量名、函数名等)在使用时区分大小写。

# if 不能写成If或IF,否则在编译时python提示语法出错
>>>If 2<9:
  File "<stdin>",line I
    If 2<9:
       ^
SyntaxError: invalid syntax

ab与Ab是两个不同的变量

>>>ab = 10
>>>Ab = 20
>>>print(ab,Ab)

10 20 # 结果输出为10 20 则证明ab与Ab是两个不同的变量

在这里插入图片描述


好了,我们已经完成了第一章的学习,下面我们进入第二章。

2 输入和输出

2.1 基本输入

如果我们想要获取用户输入的信息,我们可以使用input语句。input函数用于获得用户输入数据,基本格式如下:

变量 = input (提示字符串)

其中,变量和字符串是可以省略的。用户按【Enter】键完成输入,【Enter】键之前的全部字符均作为输入内容。

>>>a = input('请输入数据:')
请输入数据:'shiting
>>>a
'shiting

其中input函数是将用户输入以字符串返回,这个特点需要我们特别注意,例如:我们在python中打出”“a = input(请输入一个整数)”,此时变量a的类型仍然是为字符串。
如果需要输入整数或小数,则需要使用int或float函数进行相应的数据类型转换

>>>a = input('请输入一个整数:')   # 实际a的类型为字符串
请输入一个整数:2
>>>a + 1        # 运行会报错,因为a是一个字符串,试图执行加法运算


# 可以改为:
a = input('请输入一个整数:')
int(a)+1    #将字符串转为整数再执行相关加法运算,ok
# 或者改为:
a = int(input('请输入一个整数:'))

另外,在使用input输入数据时,我们可以使用【Ctrl+Z】组合键中断输入;但是假如没有输入任何数据,按下【Ctrl+Z】组合键,则会产生EOFError异常

2.2 基本输出

Python3.x中使用print函数完成基本输出操作,print函数基本格式:

print(value, ..., sep=' ', end='\n', file=sys.stdout , flush=False)

参数的具体含义如下:

value–表示输出的对象。输出多个对象时,需要用 , (逗号)分隔。

sep – 用来间隔多个对象。

end – 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符。

file – 要写入的文件对象。

flush – 是否刷新缓冲区

2.2.1 省略所有参数(输出空白行)

print函数所有参数均可以省略。当无参数时,print函数输出一个空白行

>>>print()  # 无参数时,输出空白行

>>>

2.2.2 输出一个或多个对象

print函数可同时输出一个或多个对象,无论什么类型的数据都可以直接输出。

#输出一个对象
>>>print(123456)    # 123456 

>>>num = 19
>>>print(num)    #19  输出数值型变量
 
>>>str = 'Duan Yixuan'
>>>print(str)  #Duan Yixuan  输出字符串变量
 
>>>list = [1,2,'a']
>>>print(list)   #[1, 2, 'a']  输出列表变量
 
>>>tuple = (1,2,'a')
>>>print(tuple)    #(1, 2, 'a') 输出元组变量
 
>>>dict = {'a':1, 'b':2}
>>>print(dict)   # {'a': 1, 'b': 2} 输出字典变量
----------------------------------------------------------------
 
 # 同时输出多个对象
>>>print(123,'abc','com')  #123 abc com  对象之间默认用空格分隔

2.2.3 指定输出分隔符

print函数默认分隔符为空格,可用sep参数指定输出对象的分隔符号

>>>print(123,'abc','com',sep='#')   # 指定使用'#'作为输出分隔符
123#abc#com

>>>print("www", "4399", "com", sep=".")  # 指定使用'.'作为输出分隔符
www.4399.com

2.2.4 指定输出结尾符号

print函数默认以回车换行符号( \n)作为输出结尾符号,即在输出后会换行,后面的print函数的输出会在新的一行开始。可用end参数指定输出结尾符号

>>>print("abc");print(000)   # 一行写完多条输出print语句,仍会每一条都换行
abc
000

>>>print('abc',end='+');print(000)  #指定使用”+“作为结尾符号,输出在一行
abc+000 

2.2.5 指定输出到文件

print 函数默认输出到标准流(即sys.stdout)。可用 file参数 指定输出到特定文件。

>>>file1 = open('data.txt','w')  # 打开文件
>>>print(123,'abc',45,'book',file = file1)  # 用file参数指定输出到文件
>>>file1.close()  # 关闭文件
>>>print(open('data.txt').read())  # 输出从该文件中读出的内容
123 abc 45 book

2.3 高级输出

2.3.1 使用%格式化输出

在C语言中,我们可以使用printf(“%-0.3d”,num)之类的形式,实现数据的的格式化输出
在python中,我们也可以实现类似的操作: %是一个占位符

%格式符相应作用
c字符及其ASCII码
s字符串
d有符号整数(十进制)
f浮点数字(用小数点符号)
u无符号整数(十进制)
o无符号整数(八进制)
x无符号整数(十六进制)
X无符号整数(十六进制大写字符)
e浮点数字(科学计数法)
E浮点数字(科学计数法,用E代替e)
g浮点数字(根据值的大小采用%e或%f)
G浮点数字(类似于%g)
p指针(用十六进制打印值的内存地址)
n存储输出字符的数量放进参数列表的下一个变量中

常用格式化输出:%d %f %s ,

num = 156         # 整数
print('%d' %num)  # 156
print('%f' %num)  # 156.000000  默认精度为6
print('%s' %num)  # 156

num = 156.1415    # 浮点数
print('%d' %num)  # 156
print('%f' %num)  # 156.141500 默认精度为6
print('%s' %num)  # 156.1415

num = '156'       # 字符串
print('%d' %num)  # TypeError: %d format: a number is required, not str
print('%f' %num)  # TypeError: must be real number, not str
print('%s' %num)  # 156

nun = [1,4]       # 列表
print('%s' %num)  # [1,4]


#同时输出多个变量用()
num = 156.1415  
n = 456
print('%d,%f' %(n,num))  # 456,156.141500

2.3.2 使用format格式化输出

format()–该函数把字符串当成一个模板,通过传入的参数进行格式化,并且使用大括号‘{}’作为特殊字符代替‘%’,且不用相应的格式字符

num = 156                # 整数
print('{}'.format(num))  # 156

num = 156.1415           # 浮点数
print('{}'.format(num))  # 156.1415

num = '156'              # 字符串
print('{}'.format(num))  # 156


#同时输出多个变量
n = 456
num = 156.1415  
print('{},{}'.format(n,num))  # 456,156.1415

相对基本格式化输出采用‘%’的方法,format()功能更强大,
优点:
1.带数字编号,可调换顺序,即“{1}”、“{2}”
2.带关键字,即“{a}”、“{tom}”

num = 156.1415  
n = 456
print('{1},{0}'.format(n,num))  # 通过索引控制
156.1415456     # 即format(n,num)中{0}=n,{1}=num

print('{a},{b}'.format(a=n,b=num))  # 通过关键字控制
156.1415,456      # 即format(n,num)中{0}=n,{1}=num
456,156.1415      # 即format{a=n,b=num}中指定{a}=n,{b}=num

2.3.3 使用f格式化输出

f-string用大括{ }表示被替换字段,其中直接填入替换内容即可。

num = 156              # 整数
print(f'{num}')        # 156

num = 156.1415         # 浮点数
print(f'{num}')        # 156.1415

num = '156'            # 字符串
print(f'{num}')        # 156

#同时输出多个变量
n = 456
num = 156.1415  
print(f'{n}{num}')  # 456,156.1415

2.3.4 最小字段宽度和精度

最小字段宽度:转换后的字符串至少应该具有该值指定的宽度。
如果是*(星号),则宽度会从值元组中读出。

精度:点(.)后跟精度,表示输出值的精度大小
如果需要输出实数,精度值表示出现在小数点后的位数。
如果需要输出字符串,那么该数字就表示最大字段宽度。
如果是*,那么精度将从元组中读出。
用%格式化输出

num = 156.1415     #最小字段宽度和精度支持各种格式化输出
print('**********')  # 用来判断宽度
print('%10f' %num)  # 字段宽10
print('%.3f' %num)  # 精度3,四舍五入
print('%10.3f' %num)  # 字段宽10,精度3
print('%010.3f'%num)  #010表示字宽10,不够用0填充
print('%+010.3f'%num)  # 添加+ 表示显示正负号
print('%-10.3f'%num)  # 添加负号表示左对齐

#执行结果为:
**********
156.141500
156.142
   156.142
000156.142
+00156.142
156.142 

用format()格式化输出,同样需要跟%输出一样,只是多了{:}

num = 156.1415     #最小字段宽度和精度支持各种格式化输出
print('**********')  # 用来判断宽度
print('{:10f}'.format(num));   # 字段宽度10
print('{:.3f}'.format(num))    # 精度3
print('{:10.3f}'.format(num))  # 字段宽10,精度3
print('{:010.3f}'.format(num))  #010表示字宽10,不够用0填充
print('{:+010.3f}'.format(num))  # 添加+ 表示显示正负号
print('{:<10.3f}'.format(num))  # 添加<表示左对齐

#执行结果为:
**********
156.141500
156.142
   156.142
000156.142
+00156.142
156.142

制表符\t,可以占用四个字节。 第二章节内容完结啦。

在这里插入图片描述


3 python变量

C、C++和Java等都是属于静态数据类型语言,即要求变量在使用前必须声明其数据类型。例如,我们需要定义一个变量为x,其数据类型为int

int x;

但对于python属于动态数据类型语言,他不需要对变量进行声明即可使用。

3.1 变量与对象

x = 5

对于上面的赋值语句,python在执行时总共执行了如下几个步骤:
第一步:创建表示整数5的对象。(注意:在python中所有的数据都是以对象的方式存在,学会了python,你就学会了创建对象)
第二步:检查变量x是否存在,若不存在则创建它。
第三步:建立变量x到对象5之间的引用

上面说的可能有些复杂,可以看完全文的内容后,再回来了解。

3.2 变量理解

在python中使用变量,需要理解下面几点:
1、变量在第一次赋值时被创建,再次出现时可以直接使用
2、严格来说变量没有数据类型的概念。数据类型属于对象,类型决定了对象在内存中的存储方式
3、变量引用了对象。当在表达式中使用变量时,变量立即被其引用的对象替代。
4、所以变量在使用前必须对其进行赋值

x = 5      # 创建对象5,第一次使用,创建变量x, 引用对象5
print(x + 3) 
#执行结果为:
8

对同一个变量赋值不同的数据类型,则会改变变量的类型

x = 5
x = 'yyds'
print(x)
#执行结果为:
yyds

3.3 变量命名

3.3.1 命名规则

变量的命名规则应包含如下:

  • 必须以下划线或字母开头,不能以数字开头
  • 变量名称只能包含下划线、字母或者数字
  • 变量名区分大小写
  • 禁止使用python保留字
myname1 = "须佐"
my_name_2 = "须佐"
_myname3 = "须佐"

避免使用如下样式:

  • 前后有下划线的变量名通常为系统变量,例如:namedoc
  • 以一个下划线开头的变量(如_name)不能被from…import*语句从模块导入
  • 以两个下划线开头、末尾无下划线的变量(如__abc)是类的私有变量

3.3.2 命名法则

驼峰式命名法,混合使用大小写字母来构成变量和函数的名字。包含:骆驼法则和帕斯卡法则
骆驼法则(Camel):又名小驼峰命名(lowerCamelCase),除第一个单词之外,其他单词首字母大写。

TaskRepository taskRepository			 #成员变量			 
androidStudio = "安卓开发工具"      		 #局部变量

帕斯卡法则(Pascal):又名大驼峰命名(CamelCase),每个单词的首字母都大写。

class TaskDate()     #类名
Login				 #命名空间

蛇形法则:每个单词都以下划线字符分隔。

get_uername()
test_login01 = 'z'   #测试方法名
PI = 3.1415926   	 #常量
LAST_DATA            #枚举名称

命名规范
1、模块名和包名尽量短小,并且全部使用小写字母,可以使用下划线,如:mymodule.py,module_name.py,common包名
2、类采用单词首字母大写形式(即Pascal)。
3、函数、类的属性和方法的命名规则同模块的类似,也是全部小写字母,多个字母间用下划线“”分隔。
4、常量命名时采用全部大写字母,可以使用下划线。
5、使用单下划线“
”开头的模块变量或者函数是受保护的,在使用from xxx import * 语句从模块中导入时这些变量或函数不能被导入。

3.4 变量赋值

赋值语句用于创建变量、建立变量到对象的引用。python中有多种赋值语句:简单赋值、序列赋值、多目标赋值、增强赋值等。
(1)简单赋值

x =100    #为一个变量建立对象引用

(2)序列赋值
序列赋值可以一次性为多个变量赋值。python会顺序匹配变量名和值。

n, m = 1, 2        # 使用省略圆括号的元组赋值
print(n, m)        # 输出:1,2

(a, b) = (3, 4)	   # 使用元组赋值
print(a, b)   	   # 输出:3,4  

x, y, z="kpo"	   # 用字符串赋值
print(x, y, z)     # 输出:'k','p','o'

注意可以在变量名之前使用“*”,为变量创建列表对象引用。此时,不带星号的变量匹配一个值,剩余的值会作为带星号变量的列表对象

x, *y = 'cctest'   # x匹配第一个字符,剩余字符作为列表匹配y
print(x, y)        # 输出:'c','ctest'

(3)多目标赋值
可以使用“=”,为连续多个变量赋同一个值

n=m=p= 520        # 将520赋值给变量n、m、p
print(n, m, p)    # 输出:520,520,520

前面几章节的内容都比较简单,接下来开始进入重点

在这里插入图片描述

4 数据类型

数据类型决定了程序如何存储和处理数据。Python中完善的数据类型系统,使得在Python程序中可以轻松完成各种数据处理,python中的内置数据类型如下

数字类型: int, float, complex
序列类型: str, list, tuple, range
映射类型: dict
套装类型: set, frozenset
布尔类型: bool
二进制类型: bytes, bytearray, memoryview

标准数据类型如下:
不可变类型(3 个):Number(数字)、String(字符串)、Tuple(元组);
可变类型(3 个):List(列表)、Dictionary(字典)、Set(集合)。

可变、不可变区分依据是保存数据的源内存空间是否允许修改
1、不可变类型:数字、字符串、元组
源内存空间中数据不允许修改, 如果想要修改, 只能开辟新内存空间,让变量引用指向新内存空间数据的地址
2、可变类型:字典、列表、集合
源内存空间中的数据可以修改,不需要开辟新内存空间,只要在源内存基础上修改数据

4.1 Number 数字类型

数字 是程序处理的一种基本数据,Python 数字数据类型用于存储数值。
数据类型是不允许改变的,这就意味着如果改变数字数据类型的值,将重新分配内存空间。
在变量赋值时 Number 对象将被创建:

var1 = 1
print(id(var1))   # 2621878588880
var1 = 10
print(id(var1))   # 2621878592144

id()函数可以查询变量的内存地址,我们可以看到在对var1变量进行再次赋值后,其内存地址改变了,说明数字类型是一个不可变类型

可以通过使用del语句删除单个或多个对象的引用

del var1,var2

Python中核心对象包含的数字类型包括: 整型(int) 、浮点型(float)、复数(complex)、布尔类型(boole)

4.1.1 int 整型

整型就是不带小数点的数,一般的整型都是十进制。在Python 3里,只有一种整数类型 int,表示为长整型,没有 python2 中的 Long。理论上来说,只要计算机的内存空间足够,整数可以无穷大。

>>>2**100 # 输出2的100次方
1267650600228229401496703205376
>>>3**100 # 输出3的100次方
515377520732011331036461129765621272702107522001

Python还允许将整型表示为二进制、八进制、十六进制。

  • 二进制:以0b或0B开头,后面跟二进制数字(0、1)如:0b1001、0B1003
  • 八进制:以0o或0O开头,后面跟八进制数字(0~7)如:0o1002、0O1003
  • 十六进制:以0x或0X开头,后面跟十六进制数字(0~9、A ~ F)字母大写或者小写都可以。如:0x12AB、0X231BD

不同进制只是整数的不同书写形式,程序运行时都会处理为十进制数。这个念书变量在程序中使用时,都会生成一个整数对象

可以使用int函数将一个字符串按指定进制转换为整数。int函数基本格式如下:

int(x,基数= 10# 如果X不是数字或如果基数给出,则X必须是一个字符串
>>>int('110')     # 111       # 默认按十进制转换
>>>int('110',2)     # 6       # 按二进制转换
>>>int('110',8)    # 72       # 按八进制转换
>>>int('110',10)   # 110      # 按十进制转换
>>>int('110',16)   # 272      # 按十六进制转换

>>>int(110,2)   # 基数给出,X必须为字符串  错误

int函数中第一个字符可以是正负号,其他字符不能包含小数及其他符号。

>>>int(+12)    
>>>int('+12')  # +12
>>>int('-12')  # -12

>>>int('+-123')  # 字符串中同时包含了正负号 错误
>>>int('12.3')   # 字符串中包含了小数       错误
>>>int('123asd')  # 字符串中包含了字母      错误

python中提供了内置函数bin(x)、oct(x)和bex(x)用于将整数转换为对应进制的字符串。

>>>bin(21)   # '0b10101'  #转换为二进制字符串
>>>oct(21)   # '0o25'     #转换为八进制字符串
>>>hex(21)   # '0x15'     #转换为十六进制字符串

4.1.2 float 浮点数类型

12.5、2.、3.0、12.3e+10等都是合法的浮点数常量。float()函数来创建浮点数
float()函数基本格式如下:

float(X)  # X为数字或者字符串构成的浮点数
>>>float(12.0)  # 12.0
>>>float(+12.0)  # +12.0
>>>float(-12.0)  #-12.0
>>>float('12.2333')  #12.2333

>>>float('wqhfaf')  #字符串包含字母, 错误

4.1.3 complex 复数类型

复数常量表示为“实部+虚部”形式,虚部以j或J结尾。如2+3j、2+3J。可用complex()函数来创建复数

complex (实部,虚部)
>>>complex(2,3)  # 2+3j 
>>>complex(2)  # 2+0j

4.1.4 boole 布尔类型

bool类型标识 True 和 False,常用语表达式是否为True or False

4.1.4.1 计算表达式

比较两个值,将计算表达式结果并返回布尔值答案:

print(1 > 2)        # False

if 1 == 2:          # True
    print("aaaa")   
else:
    print('bbbb')
4.1.4.2 True 布尔真值

True表示真值,几乎任何值都会被评估,任何非空的字符串、列表、元组、集合、字典都是True

bool("abc")            # True
bool(123)              # True
bool(["yys", "age"])   # True
4.1.4.3 False 布尔假值

False表示空值(例如()、[]、{}、‘’、数字0)及计算为None的值

bool(0)     # False
bool("")    # False
bool(())    # False
bool([])    # False
bool({})    # False
bool(None)  # False

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

a = True
print(type(a)) #输出 <class 'bool'>

此外还可以用 isinstance 来判断:

a = 111
isinstance(a, int)  # 使用isinstance函数判断变量 a 是否是整型
# 输出结果为布尔值,True or False

注意:
Python3 中,boole 是 int 的子类,True 和 False 可以和数字相加, True==1、False==0 会返回 True.
在 Python2 中是没有布尔型的,它用数字 0 表示 False,用 1 表示 True

4.1.5 运算符

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

  • 算术运算符
  • 比较运算符
  • 赋值运算符
  • 位运算符
  • 成员运算符
  • 身份运算符
4.1.5.1 运算符

python支持基本的算术运算:加法(+)、减法(-)、乘法(*)、除法(/)、取整除(//)、取余(%)、幂(**)

a, b=8, 5

c = a + b   # 13     两个数相加
d = a - b   # 3      两个数相减
e = a * b   # 40     两个数相乘
f = a / b   # 1.6    a除以b  
g = a // b  # 1      取整除   往小的方向取整数,返回向下取整后的结果
h = a % b   # 6      返回除法的余数
j = a ** b  # 32768  返回a的b次方

注意:在整数除法中,除法 / 总是返回一个浮点数

4.1.5.2 比较运算符

python中的比较运算符有:大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)、不等于(!=)

a,b=1020

print(a > b)    # False   
print(a < b)    # True     
print(a == b)   # False
print(a >= b)   # False
print(a <= b)   # True
print(a != b)   # True
4.1.5.3 赋值运算符

python中的赋值运算符有:简单赋值(=)、加法赋值(+=)、减法赋值(-=)、乘法赋值(*=)、除法赋值(/=)、取整除赋值(//=)、取模赋值(%=)、幂赋值(**=)

a,b=21,10
c = a + b    # 31

c += a       # 等效于 c = c + a
c -= a       # 等效于 c = c - a 
c *= a       # 等效于 c = c * a
c /= a       # 等效于 c = c / a
c //= a      # 等效于 c = c // a
c %= a       # 等效于 c = c % a
c **= a      # 等效于 c = c ** a
4.1.5.4 位运算符

按位运算符是把数字看作二进制来进行计算的,python中的位运算符有:按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移动(<<)、右移(>>)

a = 60            # 60 = 0011 1100 
b = 13            # 13 = 0000 1101

c = a & b      # 如果两个相应位都为1, 则该位的结果为1, 否则为0  # 12 = 0000 1100 
c = a | b      # 如果两个相应位都为0, 则该位的结果为0, 否则为1  # 61 = 0011 1101
c = a ^ b      # 如果两个相应位相异, 则该位的结果为1, 否则为0   # 49 = 0011 0001 
c = a ~ b      # 把每个二进制位取反, 即把1变为0, 把0变为1       # -61 = 1100 0011
c = a << 2     # 把每个二进制位左移若干位,高位丢弃,低位补0    # 240 = 1111 0000
c = a >> 2     # 把每个二进制位右移若干位,高位补0,低位丢弃    # 15 = 0000 1111 
4.1.5.5 逻辑运算符

python支持的逻辑运算符有:与(and)、或(or)、非(not)

a , b= 10 , 20

print(a and b)  # 如果 a 为 False,返回 a 的值,否则返回 b 的计算         # True 
print(a or b)   # 如果 a 是 True,返回 a 的值,否则返回 b 的计算值        # True
print(not a)    # 如果 a 为 True,返回 False 。如果 a 为 False,它返回 True。  # False 
4.1.5.6 成员运算符

除了以上的一些运算符之外,Python还支持成员运算符:在(in) 和 不在(not in )

a , b= 10 , 20
list = [1, 2, 3, 4, 5 ]

print(a in list)      # 如果在序列中找到值返回 True,否则返回 False     # False  
print(b not in list)  # 如果在序列中没有找到值返回 True,否则返回 False  # True 
4.1.5.7 身份运算符

身份运算符用于比较两个对象的存储单元,python有身份运算符:是(is) 和 不是(not is)

a , b= 10 , 20

print(a is b)    # 判断是不是引用自一个对象,相同返回 True,否则返回 False
print(a not is b) # 判断是不是引用自不同对象, 不同返回 True,否则返回 False

注意:is 和 == 两者不一致
is的作用是用来检查对象的标识符是否一致,即比较两个对象在内存中是否拥有同一块内存空间。即 a is b 是 id(a) == id(b)

4.1.5.8 运算符优先级

运算符优先级一览表,列出了从最高到最低优先级的所有运算符,同一行表示优先级相同。在同一个表达式中,按照优先级从高到低依次计算。优先级相同则按照从左到右的顺序计算

运算符描述
**乘方(指数)
+x, -x, ~x正,负,按位非 NOT
+*, @, /, //, %乘,矩阵乘,除,整除,取余
+, -加,减
<<, >>左移,右移
&按位与
^按位异或
按位或
in,not in, is,is not, <, <=, >, >=, !=, ==身份、成员、比较运算符
not
and
or
=,-=,+=,*=,/=,//=,**=赋值系列

简单来说,运算符优先级按类别排序:算术 > 位 > 身份 >成员 > 比较 > 逻辑 > 赋值

4.2 String 字符串类型

字符串是字符的容器,一个字符串可以存储任意数量的字符。除了数字,字符串是 Python 中最常用的数据类型,

4.2.1 初识字符串

4.2.1.1 定义字符串

字符串在python中有多种定义形式:

  • 单引号定义:name = '阴阳师'
  • 双引号定义:name = "阴阳师"
  • 三引号定义:name = '''阴阳师'''

三引号定义方式与多行注释写法一样,同样支持换行操作

4.2.1.2 创建字符串

我们可以使用单引号(‘’)或双引号(“”),也可用str()函数来创建字符串
创建字符串很简单,只要为变量分配一个值即可。例如:

x1 = '阴阳师'
x2 = "yys"
x = '''阴阳师'''
x = str('阴阳师')

创建空字符串可以使用:x=''或者x=str('')

4.2.1.3 引号嵌套

当需要定义的字符串本身是包含:单引号、双引号自身时?该怎么写

  • 单引号定义方式,可以内含双引号
  • 双引号定义方式,可以内含单引号
  • 可以使用转义字符(\)将引号解除效用,转变成普通字符串
x1 = '我的阴阳师名称"名字"'    
x2 = "I'm yys"
x3 = '阴阳师中我的名字:\'yys\''

4.2.2 访问字符串中的值

4.2.2.1 字符串是序列

字符串str是文本序列类型,可以支持序列类型的各种操作。
字符串的截取格式:变量[头下标:尾下标:步长]

 
# 如一个字符串: 'z  i  u  v  c'
# 从前面索引:    0  1  2  3  4
# 从后面索引:   -5 -4 -3 -2 -1

注意:计算机中索引值以 0 为开始值,-1 为从末尾的开始位置。

4.2.2.2 获取特定位置单个字符

可以根据索引,来获取特定位置的的字符,如下:

s = 'yys'

print(s[0])     # 获取头位置字符,即:y
print(s[-1])    # 获取末尾位置字符,即:s
print(s[1])     # 获取索引为1处的字符, 即:y

python中没有字符数据类型,单个字符就是长度为1的字符串

4.2.2.3 切片

可以使用切片语法返回一系列字符串,格式s[start:end:length],
start指定开始索引,end指定结束索引,length指定步长,返回s[start]至s[end]之间的所有字符,不包括s[end]

正步长
当步长为正时,end必须在start的右侧,且不能等于start。步长默认为1

正索引切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从前面索引:      0  1  2  3  4

print(s[3:1])     # 正步长,end在start右侧,切片为空
print(s[1:1])     # end等于start,则切片为空
print(s[1:3])     # 输出索引 1 到 4 位置之间的字符,不包含索引4,即:iuv

负索引切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从后面索引:     -5 -4 -3 -2 -1

print(s[-2:-4])   # 正步长,end在start右侧,切片为空
print(s[-3:-3])     # end等于start,切片为空
print(s[-4:-1])  # 输出索引 -4 到 -1 位置之间的字符,不包含索引-1,即:iuv

负步长
当步长为负时,end必须在start的左侧,且不能等于start

正索引切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从前面索引:      0  1  2  3  4

print(s[1:3:-1])     # 负步长,end不在start的左侧,切片为空
print(s[1:1:-1])     # end等于start,切片为空
print(s[3:1:-1])     # 输出索引 3 到 1 位置之间的字符,不包含索引1,即:vu

负索引切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从后面索引:     -5 -4 -3 -2 -1


print(s[-4:-2:-1])   # 负步长,end不在start的左侧,切片为空
print(s[-4:-4:-1])  # end等于start,切片为空
print(s[-2:-4:-1])   # 输出索引 -2 到 -4 位置之间的字符,不包含索引1,即:vu

省略开始或结束索引,切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从前面索引:      0  1  2  3  4
# 从后面索引:     -5 -4 -3 -2 -1

print(s[:3:1])  # 省略开始索引,输出 开始 到 3 位置的字符,不包含索引3,即:ziu
print(s[2::1])  # 省略结束索引,输出 2 到 结束 位置的字符,不包含索引3,即:ziu
print(s[::-1]) # 表示字符串逆序输出:cvuiz

4.2.3 字符串基本操作

4.2.3.1 字符串拼接

可以使用 ‘+’ 运算符,来连接或组合多个字符串:

a = "Hello"
b = "World"

c = a + b
print(c)    # 返回 "Hello" 和 "World" 字符串拼接结果,即:HelloWorld

d = a + ' ' + b
print(d)    # 在"Hello" 和 "World" 字符串之间拼接个空格,即:Hello World
4.2.3.2 字符串遍历

range()函数遍历

4.2.3.3 成员运算符

in:判断字符串中是否包含指定字符

txt = "yys tins is shijian zui 好玩"
print("yys" in txt)      # 如果字符串中包含给定的字符,返回True
print("lol" in txt)      # 如果字符串中不包含给定的字符,返回False

not in:判断字符串中是否不包含指定字符

txt = "yys tins is shijian zui 好玩"
print("lol" not in txt)  # 如果字符串中不包含给定的字符,返回True
print("yys" in txt)      # 如果字符串中包含给定的字符,返回False
4.2.3.3 字符串格式化

字符串格式化常用三种操作:%s、format()、f-string
最基本的用法是将一个值插入到一个有字符串格式符 %s 的字符串中,如下:

print("我叫 %s 今年 %d 岁!" % ('小羽', 1))%s 

字符串格式化操作符辅助指令:

符号功能
*定义宽度或者小数点精度
-用做左对齐
+在正数前面显示加号( + )
<sp>在正数前面显示空格
%‘%%‘输出一个单一的’%’
*定义宽度或者小数点精度

详细可查看第2章的高级输出

4.2.4 常用内置函数和方法

len() – 统计字符串长度
语法格式:len(str)
参数:str–字符串

s = "this is CCTV!"

print(len(s))     # 返回字符串长度,包含空格,即:13

count() – 统计字符串里某个字符出现的次数
语法格式:str.count(sub, start=0,end=len(string))
sub – 搜索的子字符串
start – 开始索引,默认为0
end – 结束索引,默认为字符串的长度

s = "this is CCTV!"

print(s.count('i'))     # 返回整个字符串中,字符 'i' 出现次数 ,即 2
print(s.count('i',0,5)) # 返回索引 0 到 5 字符串中,字符 'i' 出现次数,即 1

find() – 检测字符串中是否包含指定字符串
语法格式:str.find(str, beg=0, end=len(string))
str – 指定检索的字符串
beg – 开始索引,默认为0。
end – 结束索引,默认为字符串的长度

s = "this is CCTV!"
 
print(s.find('s'))         # 找到了,返回开始的索引值,即:3
print(s.find('is', 1))    #  找到了,返回开始的索引值,即:2
print(s.find('sss', 0 , 5))  # -1 ,没找到返回-1

类似的有:rfind() --从右开始匹配,检测字符串中是否包含指定字符串

index() – 检测字符串中是否包含指定字符串
语法格式:str.index(sub, beg=0, end=len(string))
sub – 检测的字符串
beg – 开始索引,默认为0。
end – 结束索引,默认为字符串的长度

s = "this is CCTV!"
 
print(s.index('s'))         # 找到了,返回开始的索引值,即:3
print(s.index('is', 1))    #  找到了,返回开始的索引值,即:2
print(s.index('sss', 0 , 5))  # -1 ,没找到否则抛出异常,即报错

注意:index() 方法与 find() 方法一样,只不过如果 sub 不在 string中会报一个异常。
类似的有:rindex() --从右开始匹配,检测字符串中是否包含指定字符串

join() – 将序列中的元素以指定的字符连接生成一个新的字符串
语法格式:sub.join(seq)
参数:
seq – 要连接的元素序列,元组或者列表
sub – 为指定字符

seq = ("y", "y", "s") # 字符串序列

print('.'.join(seq))   # 将序列 seq 中的字符一个个以'.'相连得到字符串,即:'y.y.s'

replace() – 替换字符串
语法格式:str.replace(old, new, max)
old – 原字符串
new – 新字符串
max – 可选参数,最大替换次数

s = "this is CCTV!"

print(s.replace('is','ws'))   # 用'ws'字符串替换原字符中的'is'字符串,即:'thws ws CCTV!' 

split() – 通过指定分隔符对字符串进行切片,
语法格式:str.split(sub="", num=string.count(str))
sub – 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等
num – 分割次数。默认为 -1, 即分隔所有

s = "this is CCTV!"

print(s.split())   # 返回分割后的字符串列表,即:['this','is','CCTV!']

endswith() – 检测字符串是否以指定后缀结尾
语法格式:str.endswith(suffix, start=0 end=len(string))
suffix – 该参数可以是一个字符串或者是一个元素。
start – 开始索引,默认为0
end – 结束索引,默认为字符串的长度

s = "this is CCTV!"

print(s.endswith('i'))         # False
print(s.endswith('CCTV!'))     # True

类似的有:startwith()–检测字符串是否以指定前缀开始

isdigit():检测字符串是否只由数字组成,只对正整数有效,负数及小数均返回不正确。
max():返回字符串中最大的字母
min():返回字符串中最小的字母
capitalize():将字符串的首字母变成大写,其他字母变小写
swapcase():将字符串的大小写字母进行相互转换,将大写变为小写,小写变为大写
lower():转换 string 中所有大写字符为小写

Python 使用反斜杠 \ 来转义特殊字符或在字符串前面添加一个 r,表示原始字符串:

print(r'this is CCTV!')

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

4.3 List 列表类型

4.3.1 初识列表

4.3.1.1 列表定义

List(列表) 是写在方括号 [] 之间、用逗号分隔开的元素列表,是 Python 中使用最频繁的数据类型。
列表可以完成大多数集合类的数据结构实现。它支持数字,字符串甚至别的数据类型组合

list1 = list(['yys', '游戏' , 18])
lsit2 = ['yys', '游戏' , 18]
4.3.1.2 创建列表

创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可。或者使用 list 函数

list1 = ['yys', '游戏' , 18, Ture]
lsit2 = [1, 2, 3, 4]
list1 = list(('yys', '游戏' , 18))

创建空列表可以使用:x=[] 或者 x = list()

4.3.1.3 列表嵌套

列表可以包含各种数据类型,包括列表,如下

list1 = [['yys', '游戏' , 18], [1, 2, 3], []]

4.3.2 访问列表中的值

4.2.2.1 列表是序列

和字符串一样,列表同样可以被索引和截取,列表被截取后返回一个包含所需元素的新列表
列表的截取格式:mylist[start:end]

# 如一个列表   : ['yys', 'zz', '1', '3', 'x']
# 从前面索引:     0      1    2    3    4
# 从后面索引:    -5     -4   -3   -2   -1
4.2.2.2 获取特定位置列表元素

可以根据索引,来获取特定位置的的列表元素,如下:

list1 = list(['yys', '游戏' , 18])
print(list[0])       # 获取头位置列表元素,即:'yys'
print(list[-1])        # 获取尾位置列表元素,即:'18'
print(list[1])        # 获取索引为 1 处列表元素,即:'游戏'
4.2.2.3 切片

同样,可以使用切片语法返回一系列列表,格式mylist[start:end:length],
start指定开始索引,end指定结束索引,返回s[start]至s[end]之间的所有元素,不包括s[end],length指定步长
正步长
当步长为正时,end必须在start的右侧,且不能等于start。步长默认为1

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从前面索引:      0      1    2    3    4

print(mylist[3:1])      # 正步长,end在start右侧,切片为空
print(mylist[1:1])      # end等于start,切片为空
print(mylist[1:3])     # 输出索引 1 到 4 位置之间的元素,不包含索引4,即:['zz', '1', '3']

负索引切片

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从后面索引:     -5     -4   -3   -2   -1


print(mylist[-1:-4])      # 正步长,end在start右侧,切片为空
print(mylist[-1:-1])      # end等于start,切片为空
print(mylist[-4:-1])     # 输出索引 -4 到 -1 位置之间的列表元素,不包含索引-1,即:['zz', '1', '3']

负步长
当步长为负时,end必须在start的左侧,且不能等于start

正索引切片

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从前面索引:      0      1    2    3    4

print(mylist[1:3:-1])     # end不在start的左侧
print(mylist[1:1:-1])     # end等于start,切片为空
print(mylist[3:1:-1])     # 输出索引 3 到 1 位置之间的字符,不包含索引1,需要逆序:['3','1']

负索引切片

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从后面索引:     -5     -4   -3   -2   -1


print(s[-4:-2:-1])   # end不在start的左侧
print(s[-4:-4:-1])  # end等于start,切片为空
print(s[-2:-4:-1])   # 输出索引 -2 到 -4 位置之间的列表元素,不包含索引1,需要逆序即:['3','1','zz']

省略开始或结束索引,切片

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从前面索引:      0      1    2    3    4
# 从后面索引:     -5     -4   -3   -2   -1

print(mylist[:3])  # 省略开始索引,输出 开始 到 3 位置的字符,不包含索引3,即:['yys', 'zz', '1']
print(mylist[2:])  # 省略结束索引,输出 2 到 结束 位置的字符,不包含索引3,即:['1', '3', 'x']
print(mylist[::-1])  # 逆序输出列表,即['x','3','1','zz','yys']

4.3.3 列表基本操作

4.3.3.1 列表拼接

可以使用 ‘+’ 运算符,来连接或组合多个列表:

list1 = [1997, 2000, 2]
list2 = [4, 5, 6]

print(list1 + list2)    # 返回列表拼接的结果,即:[1997, 2000, 2, 4, 5, 6]
4.3.3.2 添加列表元素

1.末尾添加
将元素添加到列表的末尾,可以使用 append()

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

list1.append(88)   # 在末尾添加元素
print(list1)       # 即:[1,2,3,4,5,88]

2.指定位置添加
将元素添加到列表中的指定位置前面,可以使用 insert()

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

list1.insert(1, 88)     # 在索引1位置前面添加元素
print(list1)            # 即:[1,88,2,3,4,5]

3.合并两个列表
将一个列表中的元素附加到当前列表,可以使用 extend()

list1 = [1,2,3,4,5]
list2 = [88,77,66]

list1.extend(list2)   # 在list1末尾附加列表2元素
print(list1)          # 即:[1,2,3,4,5,88,77,66]
4.3.3.3 更新列表元素

1.更改单个元素值
更改特定位置元素值,需要使用索引

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

list1[1] = 88       # 将索引1位置元素值更改为88
print(list1)      ,即:[1,88,3,4,5]

2.更改多个元素值
更改特定位置元素值,需要使用索引范围

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

list1[1:3] = [88,77]    # 将索引1到索引3位置,不包括索引3,元素值更改
print(list1)            # 即:[1,88,77,4,5]
4.3.3.4 查找列表元素

1.成员运算符
可以判断某个元素是否属于这个列表,可以用 in 或 not in

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

print(1 in list1)            # 1属于这个列表,即:True
print(3 not in list1)        # 3属于这个列表,即:False

2.查找列表元素索引
查找列表中某个值得索引位置,可以使用index()

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

print(list.index(3))            # 查找元素值3的索引,即:2
4.3.3.5 删除列表元素

1.删除指定值
将列表中特定值删除,可以使用remove()

list1 = [1,2,3,4,5]
list1.remove(5)     # 将列表中删除值为5的元素
print(list1)        # 即:[1,88,3,4]

2.删除指定索引
将列表中指定索引值删除,可以使用pop()

list1 = [1,2,3,4,5]
list1.pop(2)        # 将列表中删除索引为2的元素
print(list1)        # 即:[1,2,4,5]

3.删除列表
删除列表可以使用del关键字

list1 = [1,2,3,4,5]
del list1[0]      # 将列表中删除索引为0的元素
print(list1)      # 即:[1,2,4,5]

del list    # 将列表删除

4.清空列表
清空列表可以使用 clear()

list1 = [1,2,3,4,5]
list1.clear()      # 将列表中的元素清空
print(list1)      # 即:[]

4.3.4 列表常用函数和方法

函数/方法描述返回值
len(list)统计列表元素个数返回个数
max(list)统计列表元素最大值返回最大值
min(list)统计列表元素最小值返回最小值
list.count(obj)统计某个元素在列表中出现的次数返回次数
list.index(obj)从列表中找出某个值第一个匹配项的索引位置返回索引位置
list.pop([index=-1])移除列表中的一个元素(默认最后一个元素)返回该元素的值
list.append(obj)在列表末尾添加新的对象无返回值,会修改原列表
list.extend(seq)在列表末尾追加另一个序列中的多个值无返回值,会修改原列表
list.insert(index, obj)将对象按指定索引插入列表无返回值,会修改原列表
list.remove(obj)移除列表中某个值的第一个匹配项无返回值,会修改原列表
list.sort( key=None, reverse=False)对原列表进行排序无返回值,会修改原列表排序
list.reverse()反向排序列表中元素无返回值,会修改原列表排序
list.clear()清空列表无返回值,会修改原列表
list.copy()复制列表返回一个列表的浅复制

列表是一个有序且可变的集合,允许成员重复
注意:List中的元素是可以改变的

4.4 Tuple 元组类型

4.4.1 初始元祖

4.4.1.1 元祖定义

Python 的元组与列表类似,不同之处在于元组的元素不能修改,元祖用小括号(),列表使用方括号[]

tup1 = ('yys', '游戏', 18, True)
tup2 = (1, 2, 3, 4, 5 )
4.4.1.2 创建元祖

元组创建很简单,只需要在小括号()中添加元素,并使用逗号隔开即可,也可以使用tuple函数

tup1 = ('yys', '游戏', 18, True)
tup2 = tuple((1, 2, 3, 4, 5))

创建空元祖可以使用:tup = () 或者 tup = tuple()

元组中只包含一个元素时,需要在元素后面添加逗号 , ,否则括号会被当作运算符使用:

tup1 = (50)
type(tup1)     # 不加逗号,类型为整型   <class 'int'>

tup1 = (50,)
type(tup1)     # 加上逗号,类型为元组   <class 'tuple'>

注意:元祖元素的数据类型可以是任何数据类型:字符串、整型、布尔数据类型或者嵌套元祖

4.4.2 元组跟列表区别

元组的各种操作及函数跟列表基本一致
关键区别在于:元组中的元素不可被修改,即元组是不可变的

所谓元组的不可变指的是元组所指向的内存中的内容不可变,但是其内容中的内容是可变的

tup = ('r', 'u', 'n', 'o', 'o', 'b')
tup[0] = 'g'    # 对元组元素修改会报错

tup = (1,2,[122,[2]],5,8)
tup[2] = 'g'  # 当对元组中的元素对象操作时,一样会报错
tup[2][1] = 'g'  # 当对元组中的元素对象里面的元素对象操作时,则不会报错
tuple1 = tuple(('yys', '游戏' , 18))
print(tuple)             # 输出完整元组
print(tuple[0])          # 输出元组的第一个元素

注意:元组的元素不能修改

4.5 Set 集合类型

4.5.1 初识集合

4.5.1.1 集合定义

集合(set)是由一个或数个形态各异的大小整体组成的,构成集合的事物或对象称作元素或是成员,集合写在大括号 { } 里面,元素之间用逗号隔开。

myset = {'yys','玉藻前','10086'}
myset = {'yys'}
4.5.1.2 创建集合

可以使用大括号 { } 或者 set() 函数创建集合

myset = {'yys','玉藻前','10086'}
thisset = set(('yys','玉藻前','10086'))

创建空集合可以使用:myset = set(),不可以使用myset={} 是用来创建空集合,因为这是创建空字典的方法

4.5.2 基本操作

4.5.2.1 访问集合值

集合是一个无序的不重复的元素序列,不能通过索引访问

4.5.2.2 添加元素

s.add()
将元素 x 添加到集合中,如果元素已存在,则不进行任何操作

myset = {'yys','玉藻前','10086'}

myset.add(110)  # 将元素 110  添加到集合中 
myset.add('yys')  # 如果元素已存在,不进行任何操作

s.update()
将元素 x 添加到集合中,如果元素已存在,则不进行任何操作,x可以是列表,元组,字典

myset = {'yys','玉藻前','10086'}

myset.update([1,4])   # 将元素 1,4 一个个添加到集合中 
print(myset)   # {1, 4 'yys','玉藻前','10086'} 
4.5.2.2 移除元素

s.remove()

元素 x 从集合 s 中移除,如果元素不存在,则会发生错误

myset = {'yys','玉藻前','10086'}

myset.remove('yys')   # 移除'yys'
print(myset)   # {'玉藻前','10086'}
myset.remove('yys')   # 元素不存在,报错

s.discard()

元素 x 从集合 s 中移除,如果元素不存在,不会发生错误

myset = {'yys','玉藻前','10086'}

myset.remove('1111')   # 移除'111',元素不存在,不报错
print(myset)   # {'yys','玉藻前','10086'}

**s.pop() **

随机删除集合中的一个元素

myset = {'yys','玉藻前','10086'}
myset.pop()  # set 集合的 pop 方法会对集合进行无序的排列,然后删除这个无序排列集合的第一个元素
4.5.2.3 计算集合元素个数

len(s)
计算集合中元素个数。

myset = {'yys','玉藻前','10086'}
len(myset)   # 3
4.5.2.4 清空集合

s.clear()

myset = {'yys','玉藻前','10086'}
myset.clear()  # 清空集合
4.5.2.5 成员运算符

in:判断元素是否在集合中

myset = {'yys','玉藻前','10086'}

print("yys" in myset)      # 元素在集合中,返回True
print("lol" in myset)      # 元素不在集合中,返回False

not in:判断元素是否不在集合中

myset = {'yys','玉藻前','10086'}

print("lol" not in myset)   # 元素不在集合中,返回True
print("yys" in myset)       # 元素在集合中,返回False

4.5.3 集合常用函数

方法描述返回值
add()添加元素无返回值,直接修改原集合
update()给集合添加元素无返回值,直接修改原集合
pop()随机移除元素无返回值,直接修改原集合
remove()移除指定元素返回移除的元素,且修改原集合
discard()移除指定元素无返回值,直接修改原集合
copy()拷贝一个集合返回原集合
clear()移除集合中的所有元素无返回值,直接修改原集合
union()返回两个集合的并集,重复的元素只会出现一次返回两个集合的并集

注意:集合中的元素是可以改变的

4.6 DICtionary 字典类型

4.6.1 初识字典

4.6.1.1 字典定义

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

字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合,可以提供基于 key 检索 value 的场景

生活中的字典是:      python中的字典是:
[][含义]          [key][value]

字典的每个键值对 key=>value 用冒号 : 分割,每个对之间用逗号(,)分割,整个字典包括在花括号 {} 中 ,如下:

d = {key1 : value1, key2 : value2, key3 : value3 }
tinydict = {'name': 'yys', 'age': 18, 'cop': 'wy'}

字典中,键(key)必须使用不可变类型,值可以取任何数据类型。key 必须唯一,否则会遗漏部分键值对,如下:

tinydict = {'name': 'yys', 'age': 18, 'age':19 } 

print(tinydict)   # 输出tinydict = {'name': 'yys','age':19 } ,重复的key只会保留最后一个的键值对

注意:字典中的 key 不允许重复,重复添加等同于覆盖原有的数据

4.6.1.2 创建字典

可以使用花括号 {} 函数创建字典

hashmap = {'name': 'yys', 'age': 18, 'cop': 'wy'}

创建空字典可以使用:hashmap = {} 或者 hashmap = dict()
注意:dict 作为 Python 的关键字和内置函数,变量名不建议命名为 dict。

4.6.1.3 嵌套字典

字典的 value 可以是任意数据类型,所以 value 也可以是一个字典

stu_score_dict = {'周杰伦': {'语文': 100, '数学': 90}, '林俊杰': {'语文': 90, '数学': 88}}

# 写成另一种通俗易懂的排列
stu_score_dict = {
                '周杰伦': {'语文': 100, '数学': 90}, 
                '林俊杰': {'语文': 90, '数学': 88}
}

4.6.2 基本操作

4.6.2.1 访问字典值

字典是无序的对象集合,字典同集合一样,不可以使用下标索引(偏移存取),字典当中的元素是通过键来存取的。
访问字典中的值,只需要把相应的键放入到方括号中:

my_dict = {'name': 'zzz','code':1, 'age': 18}

print (my_dict['one'])       # 输出键为 'one' 的值
print (my_dict)          # 输出完整的字典

如果用字典里没有的键访问数据,会输出错误:

my_dict = {'name': 'zzz','code':1, 'age': 18}

print (my_dict['yys'])       # 程序报错,KeyError: 'yys'
4.6.2.2 添加字典元素

语法:dict[key]=value , 结果:字典被修改,新增一个键值对

my_dict = {'name': 'zzz', 'age': 18}

my_dict['sex']= 'boy'  # 新增一个键值对
print(my_dict)     # 输出添加后的结果,{'name': 'zzz', 'age': 18, 'sex':'boy'}
4.6.2.3 更新字典元素

语法:dict[key]=value , 结果:字典被修改,键值对被更新
原因:因为字典中 key 不可以重复,所以对已存在的key 进行上述操作,就是更新 value 值

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

my_dict['sex']= 'girl'  # 修改键sex 的值 
print(my_dict)     # 输出修改后的结果,{'name': 'zzz', 'age': '18', 'sex':'girl'}
4.6.2.4 删除字典元素

语法1:dict.pop(key) , 结果:获取指定key 的值,同时字典被修改,字典中指定key 的数据被删除

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

print(my_dict.pop('sex'))   # 删除键 sex ,并返回结果: 'boy'
print(my_dict)     # 输出删除后的结果,{'name': 'zzz', 'age': 18}

语法2:del dict[key] , 结果:删除 字典中指定key 的数据

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

del my_dict[sex]   # 删除键 sex 
print(my_dict)     # 输出删除后的结果,{'name': 'zzz', 'age': 18}

同时,del 还可以删除整个字典,语法:del dict

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

del my_dict         # 删除字典
print(my_dict)      # 程序报错,NameError: name 'my_dict' is not defined
4.6.2.5 清空字典

语法:dict.clear() ,结果:清空元素

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

my_dict.clear()        # 删除字典
print(my_dict)      # 输出清空后的结果,{}
4.6.2.6 获取字典全部的key

语法:dict.keys()

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

print(my_dict.keys())      # 输出结果,dict_keys(['name', 'age', 'sex'])
4.6.2.7 成员运算符

in:判断键是否在字典中

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

print("name" in my_dict)      # 元素在集合中,返回True
print("lol" in my_dict)      # 元素不在集合中,返回False

not in:判断键是否不在字典中

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

print("lol" not in my_dict)   # 元素不在集合中,返回True
print("name" in my_dict)       # 元素在集合中,返回False

4.6.3 字典常用方法和内置函数

函数/方法描述返回值
len(dict)计算字典元素个数返回键的总数
max(dict)求的是 key 的最大值返回键的最大值
min(dict)求的是 key 的最小值返回键的最小值
dict.fromkeys()创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值返回新字典
dict.get(key, default=None)返回指定键的值,如果键不在字典中返回 default 设置的默认值返回指定键的值
dict.setdefault(key, default=None)和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default返回键的值
dict.update(dict2)把字典参数 dict2 的 key/value(键/值) 对更新到字典 dict 里无返回值,会修改原字典
dict.items()以列表返回视图对象,是一个可遍历的key/value 对返回key/value 对的列表
dict.keys()以列表返回视图对象,是一个可遍历的key 集返回 key 视图对象
dict.values()以列表返回视图对象,是一个可遍历的value 集返回 value 视图对象
pop(key[,default])删除字典 key(键)所对应的值,返回被删除的值。返回被删除的值
popitem()反向排序列表中元素返回并删除字典中的最后一对键和值
dict.clear()删除字典内所有元素无返回值,会修改原列表
dict.copy()复制字典返回一个字典的浅复制

注意:视图对象不是列表,不支持索引,可以使用 list() 来转换为列表。

4.7 数据类型通用特性

不同的数据类型尽管各自有各自特点,但是他们也有一些相通的操作

4.7.1 for循环遍历

在遍历上,5类数据类型都支持for循环遍历

注意:列表、元组、字符串支持while循环,字典、集合不支持(无法下标索引)

4.7.2 len() 统计元素个数

语法:len(容器)

my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_str = 'abcde'
my_set = {1, 2, 3, 4, 5}
my_dict = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}

print((len(my_list)))    # 输出:5
print((len(my_tuple)))   # 输出:5
print((len(my_str)))     # 输出:5
print((len(my_set)))     # 输出:5
print((len(my_dict)))    # 输出:5

4.7.3 max() 统计最大元素

语法:max(容器)

my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_str = 'abcde'
my_set = {1, 2, 3, 4, 5,}
my_dict = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}

print((max(my_list)))    # 输出:5
print((max(my_tuple)))   # 输出:5
print((max(my_str)))     # 输出:'e'
print((max(my_set)))     # 输出:5
print((max(my_dict)))    # 输出:'key5'  得到的是最大的键

字符串使用ascii 码比较大小,字典返回最大的键

4.7.4 min() 统计最小元素

my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_str = 'abcde'
my_set = {1, 2, 3, 4, 5,}
my_dict = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}

print((min(my_list)))    # 输出:1
print((min(my_tuple)))   # 输出:1
print((min(my_str)))     # 输出:'a'
print((min(my_set)))     # 输出:1
print((min(my_dict)))    # 输出:'key1'  得到的是最小的键

4.7.5 sorted() 排序

sorted() 函数会返回一个排序列表,不改变原有序列
sorted(容器,reverse=False),reverse = False表示升序排列

my_list = [2, 3, 4, 1, 5]
my_tuple = (2, 3, 1, 4, 5)
my_str = 'deabc'
my_set = {2, 1, 3, 4, 5,}
my_dict = {'key2': 2, 'key3': 3, 'key1': 1, 'key4': 4, 'key5': 5}

print((sorted(my_list)))    # 输出:[1, 2, 3, 4, 5]
print((sorted(my_tuple)))   # 输出:[1, 2, 3, 4, 5]
print((sorted(my_str)))     # 输出:['a', 'b', 'c', 'd', 'e']
print((sorted(my_set)))     # 输出:[1, 2, 3, 4, 5]
print((sorted(my_dict)))    # 输出:['key1', 'key2', 'key3', 'key4', 'key5']

注意:排序后,全部的数据类型都会变为列表

4.7.6 数据类型转换

python 是弱类型语言,跟 C语言强类型语言不一样,它并不需要声明变量的数据类型
Python 数据类型转换可以分为两种:隐式类型转换 和 显式类型转换

4.7.6.1 隐式类型转换

在隐式类型转换中,Python会自动将一种数据类型转换为另一种数据类型,不需要我们去干预。例如:

num_int = 123
num_flo = 1.23
num_new = num_int + num_flo

在运算时,python会自动将较低数据类型(整数)就会转换为较高数据类型(浮点数)以避免数据丢失

4.7.6.2 显式类型转换

转列表:list(容器)

print((list(my_tuple)))   # 输出:[1,2,3,4,5]
print((list(my_str)))     # 输出:['a','b','c','d','e']
print((list(my_set)))     # 输出:[1,2,3,4,5]
print((list(my_dict)))    # 输出:['key1', 'key2', 'key3', 'key4', 'key5']

转元组:tuple(容器)

print((list(my_list)))   # 输出:(1,2,3,4,5)
print((list(my_str)))     # 输出:('a','b','c','d','e')
print((list(my_set)))     # 输出:(1,2,3,4,5)
print((list(my_dict)))    # 输出:('key1', 'key2', 'key3', 'key4', 'key5')

转字符串:str(容器)

print((str(my_list)))   # 输出:[1,2,3,4,5]
print((str(my_tuple)))     # 输出:(1,2,3,4,5)
print((str(my_set)))     # 输出:{1,2,3,4,5}
print((str(my_dict)))    # 输出:{'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5},字典转为字符串才会保留value

只有字典转为字符串才会保留value

转集合:set(容器)

print((set(my_list)))   # 输出:{1, 2, 3, 4, 5}
print((set(my_tuple)))     # 输出:{1, 2, 3, 4, 5}
print((set(my_str)))     # 输出:{'d', 'a', 'e', 'c', 'b'}
print((set(my_dict)))    # 输出:{'key2', 'key5', 'key4', 'key1', 'key3'}, 仅保留键,保持无序

数据类型转为集合,重复元素的会被去重
转字典:dict(容器)
转字典需要满足一定的条件,因为一定要满足键值对这个概念,所以一般的列表、元组、字符串、集合都无法转为字典

在显式类型转换中,使用预定义函数将用户对象的数据类型转换为所需的数据类型。
常用的预定义函数如下:

函数描述
int(x [,base])将x转换为一个整数
float(x)将x转换到一个浮点数
complex(real [,imag])创建一个复数
str(x)将对象 x 转换为字符串
tuple(s)将序列 s 转换为一个元组
set(s)转换为可变集合
dict(d)创建一个字典。d 必须是一个 (key, value)元组序列。
frozenset(s)转换为不可变集合
chr(x)将一个AScii码转换为字符
ord(x)将一个字符转换为对应AScii码
oct(x)将一个整数转换为一个2进制字符串
oct(x)将一个整数转换为一个八进制字符串
hex(x)将一个整数转换为一个十六进制字符串

这些函数返回一个新的对象,表示转换的值,用法举例:

var = int(200) # 强调var为整型
var = dict(name="yys", age=188)    # 强调var为字典

# 进制转换
i = 23
bin(i) # 转换成二进制0b10111

4.8 推导式

Python 推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。
Python 支持各种数据结构的推导式:

  • 列表(list)推导式
  • 字典(dict)推导式
  • 集合(set)推导式
  • 元组(tuple)推导式

4.8.1 列表推导式

列表推导式格式为:

[表达式 for 变量 in 列表] 
[out_exp_res for out_exp in input_list]

或者 

[表达式 for 变量 in 列表 if 条件]
[out_exp_res for out_exp in input_list if condition]
  • out_exp_res:列表生成元素表达式,可以是有返回值的函数
  • for out_exp in input_list:迭代 input_list 将 out_exp 传入到 out_exp_res 表达式中
  • if condition:条件语句,可以过滤列表中不符合条件的值

例子:过滤掉长度小于或等于3的字符串列表
在没有学习列表推导式前,我们的正常写法是这样的:

names = ['yys','timlin','bobo','wen','wendi']
new_names = []
for name in names:
    if len(name)>3:
        new_names.append(name)
print(new_names) 

使用列表推导式,仅仅只需一句话就可以将for循环的内容写完

names = ['yys','timlin','bobo','wen','wendi']
new_names = [name for name in names if len(name)>3]
print(new_names)     # ['timlin','bobo','wendi']

列表推导式写法是将for语句简化,但其提升的效率极高

又如例子:计算 30 以内可以被 3 整除的整数:

 multiples = [i for i in range(30) if i % 3 == 0]

扩展
语句格式也可以为:结果值1 if 判断条件 else 结果2 for 变量名 in 原列表
如:[i if i % 3 else [] for i in range(30)]
但是 else不可以省略,原理的话应该是使用了三目运算符
i if i % 3 else [] 可以看做是一个表达式

python 的列表推导比 for 循环、while 循环要快很多。分析了下原因:列表推导内的迭代在解释器内是以 C 语言的速度运行的 (一般是 for 循环的两倍,对大型文件操作而言,用列表推导效果尤其明显), while 语句是纯粹用 Python 代码写成,所以速度最慢。

4.8.2 字典推导式

字典推导基本格式:

{key_expr: value_expr for value in collection}{key_expr: value_expr for value in collection if condition}

例子:
使用字符串及其长度创建字典:

listdemo = ['Google','Runoob', 'Taobao']
# 将列表中各字符串值为键,各字符串的长度为值,组成键值对
newdict = {key:len(key) for key in listdemo}
print(newdict)      # {'Google': 6, 'Runoob': 6, 'Taobao': 6}

字典推导式基本结构与列表推导式一致,区别是

  • 字典推导式中的表达式一定要键值对
  • 外层要使用{}

4.8.3 集合推导式

集合推导式基本格式:

{expression for item in Sequence}{expression for item in Sequence if conditional}

例子:
判断不是 abc 的字母并输出:

a = {x for x in 'abracadabra' if x not in 'abc'}
print(a)    # {'d', 'r'}

字典推导式基本结构与列表推导式一致,区别是:

  • 外层要使用{}

4.8.4 元祖推导式

元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组。
元组推导式基本格式:

(expression for item in Sequence)(expression for item in Sequence if conditional)

例子:
生成一个包含数字 1~9 的元组:

tpl = (x for x in range(1,10))
print(tuple(tpl))       # (1, 2, 3, 4, 5, 6, 7, 8, 9)

元组推导式和列表推导式的用法区别:

  • 元组推导式是用()圆括号
  • 另外元组推导式返回的结果是一个生成器对象,需要使用tuple()转换成元祖

在这里插入图片描述

这就开始学晕了吗?加油后面继续!

5. 各种控制语句

5.1 条件控制语句if-else

5.1.1 if语句的基本格式

程序中的判断语句:

if 判断的条件:
    条件成立时,要做的事

如下:

age = 18 

if age >= 18:      当条件为真时,执行if里面代码块的内容
    print('我已经成年了')    # 输出:我已经成年了

注意

  1. 判断语句的结果,必须是布尔类型:True或False
  2. 归属if判断的代码语句块,需要填充4个空格缩进

5.1.2 if-else语句的基本格式

if 判断的条件:
    条件成立时,要做的事
else:
    不满足条件时,要做的事

如下:

age = int(input"请输入你的年龄:")

if age >= 18:  # 当条件为真时,执行if里面代码块的内容
    print('你已经成年了')    # 输出:我已经成年了
    
else:   # 当条件为假时,执行else里面代码块的内容
    print('你未成年了')    # 输出:我未成年了

注意:else和if同级,else里面的内容也要使用缩进

5.1.3 if-elif-else语句的基本格式

if 条件1:
    条件1成立时,要做的事
elif 条件2:
    条件2成立时,要做的事
else:
    以上条件都不满足时,要做的事

如下案例:

age = int(input"请输入你的年龄:")

if age >= 18:  # 当条件为真时,执行if里面代码块的内容
    print('你已经成年了')    # 输出:你已经成年了
elif age <4:  # 当条件为真时,执行if里面代码块的内容
    print('你不可以游玩')    # 输出:你不可以游玩


else:   # 当条件为假时,执行else里面代码块的内容
    print('虽然未成年,但是也可也玩')    # 输出:虽然未成年,但是也可也了

5.1.4 if嵌套

可以通过多个if来控制不同的条件判断

if 条件1:
    条件1成立时,要做的事
    if 条件2:
        条件2成立时,要做的事
    else:
    条件2不满足时,要做的事
else:
    条件1不满足时,要做的事
  • 嵌套语句可以用于多条件和多层次的逻辑判断中
  • 嵌套语句可以根据需求,自由组合if -elif-else
  • 嵌套语句一定要注意空格缩进,py中通过空格缩进来决定层次关系

5.2 循环控制语句

5.2.1 while控制语句

while循环语法格式:

while 条件:
    条件满足时,要做的事

1、while的条件需要布尔类型
2、需要规划循环终止条件,否则将无限循环
3、while需要跟if一样,需要空格缩进

5.2.2 while 循环使用 else 语句

while…else…
如果 while 后面的条件语句为 false 时,则执行 else 的语句块。
语法格式如下:

while <expr>:
    <statement(s)>
else:
    <additional_statement(s)>

# expr 条件语句为 true 则执行 statement(s) 语句块,如果为 false,则执行 additional_statement(s)。

如下:

count = 0
while count < 5:
   print (count, " 小于 5")
   count = count + 1
else:
   print (count, " 大于或等于 5")

注意:while循环的循环条件时自定义的,自行控制循环条件

5.2.3 for循环控制语句

for基础语法格式:

for 临时变量 in 待处理数据集:
    循环满足条件时执行的代码

例如遍历一个字符串:

# 定义一个字符串str_t
str_t = 'name'

# 使用for循环处理字符串
for x in str_t:
    print(x)

for循环只能从被处理的数据集中,依次取出内容进行处理。
理论上来说,for循环是无法构建无限循环的(被处理数据集无法无限大)
for循环是一种轮询机制,对一批内容进行逐个处理

5.2.4 for循环使用 else 语句

for…else
在 Python 中,for…else 语句用于在循环结束后执行一段代
语法格式如下:

for item in iterable:
    # 循环主体
else:
    # 循环结束后执行的代码

当循环执行完毕(即遍历完 iterable 中的所有元素)后,会执行 else 子句中的代码,如果在循环过程中遇到了 break语句,则会中断循环,此时不会执行 else 子句。

sites = ["age", "yys","time-s","lol"]
for site in sites:
    if site == "yys":
        print("找到阴阳师!")
        break
    print("循环数据 " + site)
else:
    print("没有循环数据!")
print("完成循环!")

在执行上面的脚本时,在循环到 "yys"时会跳出循环体。所以else语句不会被执行

5.2.5 for语句中的range语句

range格式有三种

range(num)range(num1,num2)range(num1,num2,step)
语法1
range(num)
获得一个从0开始,到num结束的数字序列(不含num本身)
如:range(5)得到的数据是:0,1,2,3,4

语法2
range(num1,num2)
获得一个从num1开始,到num2结束的数字序列(不含num2本身)
如:range(5,10)得到的数据是:5,6,7,8,9

语法3
range(num1,num2,step)
获得一个从num1开始,到num2结束的数字序列(不含num2本身),数字之间的步长为step(默认为1)
如:range(5,10,2)得到的数据是:5,7,9

5.2.6 for循环的变量作用域

for基础语法格式:

for 临时变量 in 待处理数据集:
    循环满足条件时执行的代码

临时变量,在编程规范上,作用范围仅限定在for循环的内部

如果在for循环外部去访问这个临时变量:

  • 实际上是可以访问到的
  • 但是编程规范上不允许、不建议这么做
  • 如需访问临时变量,可以预先在循环外定义它

5.2.7 循环的嵌套

循环的嵌套跟if的嵌套类似

for循环 或 while循环:
    循环满足时要做的事情
    ...
    for循环 或 while循环:
        循环满足时要做的事情
        ...

注意缩进,嵌套for和while都是通过缩进来确定层次关系(即自己控制的内容)
for循环和while循环可以相互嵌套使用

5.2.8 循环中断break及continue

break:
直接结束所在循环

continue:
中断所在循环的当次执行,直接进入下一次循环

注意:

  • break及continue 都能在for和while循环中使用
  • 在嵌套的循环中,break及continue 都只能作用在所在循环中,无法控制上层循环

至此第五章内容结束!
在这里插入图片描述

6. 函数

6.1 函数的定义

函数:是组织好的,可以重复使用的,用来实现特定功能的代码段,能提高应用的模块性,和代码的重复利用率
Python 中使用 def 关键字来定义函数。
函数的定义:

def 函数名(参数列表):
    函数体
    return 返回值

函数的调用:

函数名(参数)

例如:

def say_hi():      
    print("hi 我是yys")
    return False

say_hi()

注意:

  • 参数可以省略,但仍需要在函数名后加入()
  • 返回值可以省略
  • 函数必须先定义在使用

6.2 函数参数

函数传入参数的作用使得在函数运行的时候,可以接受外部传入的数据,传入多个参数时,需要逗号隔开
使用方式有:

def add(x,y):
    result = x + y
    return result

c = a(2,3)

形式参数:函数定义中的参数 ,如上 (x,y) 称之为形式参数
实际参数:函数调用中的参数,如上 (2,3) 称之为实际参数

函数的传入参数可以有以下几类:

  • 位置参数
  • 关键字参数
  • 默认参数
  • 不定长参数

6.2.1位置参数

位置参数:调用函数时根据函数定义的参数位置来传递参数,须以正确的顺序传入函数。

def printme(name,age):
   "打印任何传入的字符串"
   print (f'你的名字是{name},年龄{age})
   return
 
printme()   # TypeError: printme() missing 1 required positional argument: 'str'

printme('bob',18) 

注意
传递的参数与定义的参数的顺序及个数必须一致

6.2.2 关键字参数

关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名自动匹配传入的参数值

def printinfo( name, age ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
printinfo( age=50, name="runoob" )

此例子可以得出,在函数调用时只需要带上关键字参数(形参带上),就可以让形参自动对应实际参数对应值
注意
函数调用时,如果有位置参数,那么位置参数必须在关键字参数的前面,但是关键字参数之间不存在先后顺序

6.2.3 默认参数

调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入 age 参数,则使用默认值:

def printinfo( name, age = 35 ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
printinfo( name="runoob" )

此例子可以看出,如果一开始在定义函数时就给形参设置了默认值,那么在实际调用时不传入该形参,就会使用默认值
注意
默认参数一定要在关键字或者位置参数后面

6.2.4 不定长位置参数 *args

即不清楚实际会传入的参数有多少,需要能处理比当初声明时更多的参数,使用不定长参数.
在定义的形式参数前面加了星号 * 的,则此参数会以元组(tuple)的形式存在,接收不定长数量的参数传入

def printinfo( arg1, *vartuple ):
   "打印任何传入的参数"
   print (arg1)
   print (vartuple)
 
printinfo( 70, 60, 50 )

一般来顺分配原则是必需参数会对应相应位置的实际参数值,剩余的全归类为不定长位置参数

6.2.5 不定长关键字参数 **kwargs

如果在参数前面加了两个星号 ** ,则参数会以字典的形式导入

def printinfo( arg1, **vartuple ):
   "打印任何传入的参数"
   print (arg1)
   print (vartuple)
 
printinfo(1, a=2,b=3)

顺序一般是:先必须参数、再关键字参数(包含默认参数)、然后是不定长位置参数、不定长关键字参数

6.3 匿名函数

Python 使用 lambda 来创建匿名函数。
函数的定义中:

  • def 关键字,可以定义带有名称的函数
  • Lambda关键字,可以定义匿名函数(无名称)

有名称的函数,可以无限重复使用
匿名函数,只可临时使用一次

匿名函数的语法:

lambda 参数列表:表达式
lambda [arg1 [,arg2,.....argn]]:expression
  • lambda 是关键字,表示定义匿名函数
  • 表达式就是函数的执行逻辑,只能写一行,而不是一个代码块。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

lambda 的参数形式:
无参数 lambda : 表达式
一个参数 lambda 参数 : 表达式
默认参数 lambda key=value : 表达式
不定长位置参数 lambda *args : 表达式
不定长关键字参数 lambda **kwargs : 表达式

例子:

sum = lambda a,b:a+b
    sum(a,b)

6.4 函数作为参数传递

将一个函数名A作为参数 ,传入到另一个函数B中。如:

def test_func(func):
    result = add(1,2)
    print(result)

def add(x,y):
    return x+ y
    
test_func(add)
  • test_func需要一个函数作为参数传入,这个函数需要接收2个数字进行计算,计算逻辑由被传入函数来决定
  • add函数接收2个函数进行计算
  • test_func(add)将函数add 作为参数,传入到了test_func函数中使用,最终在test_func函数内部,由传入的add函数,完成计算操作

在上面这个例子中,计算逻辑的传递,而非数据的传递
任何逻辑都可以行定义一个函数作为函数参数传递

6.5 函数的返回值

函数的返回值:在函数执行完成后,返回给函数调用者的结果
语法:

return [表达式]

return 语句用于退出函数,选择性地将一个表达式返回给调用方。
注意

  • 不带参数值的 return 语句返回 None
  • 函数体在遇到 return 语句时就会返回,所以 return 后的代码不会执行

扩展:
None表示:空的、无意义的
其类型是:<class 'NoneType'>

应用场景:

  1. 用在函数返回值上
    函数返回的 None,表示函数返回了空的意思,等效于 return None
  2. 用在if判断上
    在if判断中,None 等同于 False
  3. 用在声明无意义的变量上
    定义变量,但暂时不需要变量有具体的值。如:name = None

6.6 函数的说明文档

就是通过多行注释,在函数定义和函数体之前给函数添加注释,用于辅助理解函数的作用

def func(x):
    """
    函数说明
    :param x:
    :return:
    """
    return 
  • 函数说明 – 用于简洁描述此函数功能
  • :param: – 用于解释参数
  • :return: – 用于解释返回值

6.6 函数的嵌套

函数跟循环控制语句一样,可以嵌套,即:

def func1():
    return true

def func2():
    c = func1()
    return c

c2 = func2()

即将一个定义的函数在另一个函数里面调用,那么在调用func2时,就会先执行func1

6.7 变量的作用域

变量的作用域是指变量的作用范围(变量可以在哪用,不可以在哪用)
py中有四种作用域:

  • L(Local):最内层,包含局部变量,比如一个函数/方法内部。
  • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,A(B()) ,那么对于 B 中的变量来说,A 中的作用域就为 nonlocal。
  • G(Global):当前脚本的最外层,比如当前模块的全局变量。
  • B(Built-in): 包含了内建的变量/关键字等

扩展:python中变量查找是遵循LGB原则,即优先在局部作用域(local scope)中对变量进行查找,失败则在闭包或者外层嵌套函数的外部作用域(enclosing scope)中查找,没有找到则在全局作用域(global scope)中进行查找,最后尝试再内建作用域(build-in scope)内查找

规则顺序: L –> E –> G –> B
总结:在局部找不到,便会去局部外的局部找(例如闭包/嵌套),再找不到就会去全局找,最后去内置中找。

局部变量 Local
局部变量是指变量是定义在函数体内的变量,即变量只在函数体内部生效

def A():
    num =100
    print(num)
    
A()
print(num)   # 报错,num未定义

在函数外部调用函数内部定义的变量是非法的,因为局部变量在函数体外无法使用

非全局变量/非局部变量 Enclosing

def outer():
    num = 2  # 闭包函数外的函数中,定义一个局部变量
    def inner():
        print(num)  # 输出外部局部变量的值2 
        num = 3 重新定义一个局部变量
        print(num)
    inner()
    print(num)
    
outer()  # 2, 3, 2
  • 在此例函数outer,知道我们可以在嵌套函数内部使用外部函数定义的局部变量
  • 在函数里面,对变量进行修改,其实是重新定义了一个局部变量,并对其赋值,其不影响外部函数的非全局变量num
  • 所以在最后print(num)是输出仍然是2

如果需要在函数内部实现对全局变量的修改,需要使用关键字 nonlocal

def outer():
    num = 10
    def inner():
        nonlocal num   # 用nonlocal声明内部函数的局部变量num 为非全局变量
        num = 100
        print(num)
    inner()
    print(num)
    
outer()  # 10,100,100   最后输出的print(num)时,此时的num已被inner()成功修改

全局变量 Global
指变量在函数体内、外都能生效

num = 100

def A():
    print(num)

def B():
    print(num)  # 输出全局变量的值
    num = 50    # 重新定义一个局部变量num
    print(num)  # 输出局部变量的值

A()     # 100
B()     # 100 ,50
print(num)  # 100 
  • 在此例函数A,知道我们可以在函数内部使用外部定义的全局变量
  • 函数B,可以让我们了解,当在函数里面,对变量进行修改,其实是重新定义了一个局部变量,并对其赋值,其不影响外部的全局变量
  • 所以在最后print(num)是输出仍然是100

如果需要在函数内部实现对全局变量的修改,需要使用关键字 global

num = 100

def C():
    global num  # 将内部的局部变量num定义全局变量
    num =20     
    print(num)

C()     # 20
print(num)  # 20  最后输出的print(num)时,此时的num已被C()成功修改

在这里插入图片描述

7.文件

7.1 文件的编码

7.1.1 什么是文件

一般来说,我们在计算机中编写的数据会存储在内存中,但是内存中存放的数据在计算机关机后即会消失。如果要长久保存数据,就要使用硬盘、光盘、U盘等设备。为了便于数据的管理和检索,引入了“文件”的概念

一篇文章、一段视频、一个可执行的文件都可以被保存为一个文件,并且赋予一个文件名。操作系统以文件为单位管理磁盘中的数据。文件可分多种类别:

  • 文本文件:TXT等
  • 视频文件:WMV、AVI、MPEG、DV、MOV、MOD等
  • 音频文件:MP3、WAV、FLAC、WMA、MIDI、CDA等
  • 图像文件:jpg、png、gif等
  • 可执行文件:.exe、.sys等

7.1.2 编码规则

为什么需要使用编码?
我们知道,计算机底层的机器语言只识别0和1,对于丰富的文本内容计算机又该如何识别呢?我们是怎么转化的呢?
可以使用编码技术(密码本)将内容翻译成0和1存储在计算机中
编码技术:使用特定的翻译规则,将内容翻译成二进制0和1,不同的编码技术,翻译的结果不一样,所以写入和打开文件的编码技术要一致
文件的编码技术有:UTF-8、GBK、Big5
UTF-8是目前全球通用的编码格式,除非特别要求,一般默认使用此编码格式

7.2 文件的常用操作

文件操作的步骤:

  • 打开
  • 读写
  • 关闭

7.2.1 文件的打开操作

Python 对文件进行操作,需要使用open() 方法用于打开文件,并返回文件对象
完整的语法格式为:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
参数说明:

  • file:文件路径(相对或者绝对路径),必需参数
  • mode:文件打开模式,可选,默认只读
  • buffering:设置缓冲,可选,默认-1
  • encoding:编码格式,可选,一般为UTF-8
  • errors: 报错级别,可选
  • newline: 区分换行符,可选
  • closefd: 传入的file参数类型,可选
  • opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。可选

常用的格式为:open(file,mode,encoding='UTF-8')

mode参数:

参数描述文件指针位置
r以只读方式打开文件,默认模式位于文件的开头
rb以二进制格式打开一个文件用于只读,一般用于非文本文件如图片等位于文件的开头
r+打开一个文件用于读写位于文件的开头
rb+以二进制格式打开一个文件用于读写,一般用于非文本文件如图片等位于文件的开头
w打开一个文件只用于写入。如果文件不存在,则创建新文件位于文件的开头(原内容会被清空)
wb以二进制格式打开一个文件只用于写入。如果文件不存在,则创建新文件位于文件的开头(原内容会被清空)
w+打开一个文件用于读写。如果文件不存在,则创建新文件位于文件的开头(原内容会被清空)
wb+以二进制格式打开一个文件用于读写。如果文件不存在,则创建新文件位于文件的开头(原内容会被清空)
a打开一个文件用于写入。如果文件不存在,则创建新文件位于文件的结尾
ab以二进制格式打开一个文件用于写入。如果文件不存在,则创建新文件位于文件的结尾
a+打开一个文件用于读写。如果文件不存在,则创建新文件位于文件的结尾
ab+以二进制格式打开一个文件用于读写。如果文件不存在,则创建新文件位于文件的结尾

注意:

  • 默认为文本模式,如果要以二进制模式打开,加上 b
  • 默认是以只读方式打开文件
  • w 和 a都是写入,但是两者文件指针的位置不一样,w 文件指针位于开头,会覆盖原本内容;a文件指针位于结尾,不会覆盖原本内容

举例:

f = open('cc.txt','r',encording="UTF-8")

7.2.2 文件的关闭操作

文件的关闭一般都是用close()方法,文件打开操作完毕后,必须进行关闭操作
close() 方法用于关闭一个已打开的文件。关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误

语法格式:file.close()

7.2.3 文件的读取操作

文件的读取有四种方法:

  • read() 从文件读取指定的字符数
  • readline() 从文件读取整行
  • readlines() 用于读取所有行(一次性读取,直到结束符 EOF)并返回列表
  • for line in 文件对象

read()
用于从文件读取指定的字符数(文本模式 t)或字节数(二进制模式 b)
语法格式:file.read([size])
参数: size: 从文件中读取的字符数(文本模式)或字节数(二进制模式),默认为 -1,如果未给定参数 size 或 size 为负数则表示读取整个文件
返回值:返回读取到的内容

举例,读取文件的内容:
cc.txt文件内容如下:

这是第一行
这是第二行
这是第三行
这是第四行
这是第五行
# 打开文件
fd = open("cc.txt", "r+",encording="UTF-8")
print ("文件名为:{}".format(fd.name)

line = fo.read(10)          # 读取10个字符
print ("读取的字符串: {}".format(line)

fd.close()  # 关闭文件

总结:read()方法,可以指定需要读取的字符数量

readline()
用于从文件读取整行,包括 “\n” 字符。行的切分是" \n "字符
语法格式:file.readline([size])
参数: size: 从文件中读取的字符数(文本模式)或字节数(二进制模式),默认为 -1,如果未给定参数 size 或 size 为负数则返回指定大小的字节数,包括 “\n” 字符

当执行readline() 时,code会扫描文件中的每一个字节,直到找到一个 \n 位置,然后停止并读取此前的文件内容。并且fileobject 会记录每次调用readline()后的对于读取位置,这样readline()下次被调用的时候就会读取下一行。

举例,读取文件内容:
cc.txt文件内容:

1:www.runoob.com
2:www.runoob.com
3:www.runoob.com
4:www.runoob.com
5:www.runoob.com
fd = open("cc.txt", "r+",encording="UTF-8")  打开文件,获得一个文件对象
print ("文件名为:{}".format(fd.name)

line = fd.readline()   # 读取第一行,并将读取位置指针置于第一行末尾
print ("读取第一行:{}".format(line)

line = fd.readline(5)   # 读取第二行的前5个字符,并将读取位置指针置于第二行末尾
print ("读取到的字符串:{}".format(line)

fd.close()  # 关闭文件

注意:

  • 每次调用readline()的fileobject会记录此次读取位置,这样readline()下次被调用的时候就会读取下一行
  • '\n’也会包含在读取的字符串中,常用 strip() 对头尾的空白字符处理

readlines()
用于读取所有行(按照行的方式一次性读取,直到结束符 EOF)并返回列表,每一行的数据为一个元素
语法格式:file.readlines()
返回值:返回列表,包含所有的行

举例,读取文件内容:
cc.txt文件内容:

1:www.runoob.com
2:www.runoob.com
3:www.runoob.com
4:www.runoob.com
5:www.runoob.com
fd = open("cc.txt", "r+",encording="UTF-8")  打开文件,获得一个文件对象
print ("文件名为:{}".format(fd.name)

for line in fd.readlines():                          #依次读取每行  
    line = line.strip()                             #去掉每行头尾空白  
    print ("读取到的数据:{}".format(line)

fd.close()  # 关闭文件

for line in 文件对象
for 循环读取文件行
格式:for line in 文件对象
每一个临时变量 line 都记录了文件的一行数据

fd = open("cc.txt", "r+",encording="UTF-8")  打开文件,获得一个文件对象
print ("文件名为:{}".format(fd.name)

for line in fd:
    print ("读取到的数据:{}".format(line) 

fd .close() # 关闭文件

7.2.4 文件的写入操作

写入操作常用方法有:

  • write() 向文件中写入指定字符串
  • writelines() 向文件中写入一序列的字符串, 换行需要加入’\n’

write()
用于向文件中写入指定字符串。
如果文件打开模式带 b,那写入文件内容时,str (参数)要用 encode 方法转为 bytes 形式
语法格式:file.write([str])
参数:str – 要写入文件的字符串
返回值:返回写入的字符长度。

在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的

seek() 方法用于移动文件读取指针到指定位置。
语法格式:file.seek(offset,whence=0)
参数:

  • offset – 开始的偏移量,也就是代表需要移动偏移的字节数,如果是负数表示从倒数第几位开始。
  • whence:表示要从哪个位置开始偏移:
  • 0 代表从文件开头开始算起,
  • 1 代表从当前位置开始算起,
  • 2 代表从文件末尾算起

举例,
cc.txt文件内容如下:

1:www.runoob.com
2:www.runoob.com
3:www.runoob.com
4:www.runoob.com
5:www.runoob.com
fd = open("runoob.txt", "r+",encording="UTF-8")
print("文件名为: {}".format(fd.name))
 
str = "6:www.runoob.com"
fd.seek(0, 2)  # 重新设置文件指针移动到末尾
line = fd.write( str )

fd.seek(0,0)   # 重新设置文件指针移动到开头
for index in range(6):
    line = next(fd)
    print("文件行号{}{}".format(index, line))

fd.flush()  # 刷新 将内存中的文件写入硬盘,可以让文件在未关闭下仍然可以更新内容
fd.close()  # 内置了flush方法,关闭文件

注意:

  • 操作文件时,需要注意文件指针的位置,如 mode=‘w’ 和 mode=‘a’
  • 直接调用write(),内容并未真正写入文件,而是积攒在程序的内存中,称之为缓冲区
  • 当调用flush的时候,内容会真正的写入文件,避免频繁的操作硬盘,导致效率下降

writelines()
用于向文件中写入一序列的字符串。
这一序列字符串可以是由迭代对象产生的,如一个字符串列表。换行需要制定换行符 \n。
语法格式:file.writelines([str])
参数:str – 要写入文件的字符串序列
返回值:该方法没有返回值。

fd = open("cc.txt", "w+")
print ("文件名为: ", fd.name)
seq = ["菜鸟教程 1\n", "菜鸟教程 2"]  # 字符串序列,换行需要加入'\n'
fd.writelines(seq)      # 写入字符串序列

fd.close()    # 关闭文件

注意:

  • 无返回值
  • 换行需要加入’\n’

7.3 os模块的使用

待补充

在这里插入图片描述

8. 异常

8.1 异常的定义

异常是指程序在运行过程中发生了错误

bug就是指异常的意思,因为历史上有因虫子导致计算机故障的案例,所以,bug就代表软件出现错误

8.2 异常的捕获

为什么要捕获bug?
因为当程序遇到bug时,会有两种情况:

  1. 整个程序因为一个bug停止运行
  2. 对bug进行提醒,整个程序继续运行

当没有对bug进行处理时,我们的程序就只会走第一种情况,但是实际上,我们更希望程序走第二种情况
所以捕获异常作用:提前假设某处会发生异常,当真的发生异常时,可以按照我们预先准备的情况发生

8.2.1 捕获常规异常

基本语法:

try:
    可能发生异常的代码
except:
    出现异常时执行的代码

举例:尝试以’r’模式打开文件,如果文件不存在,则以’w’模式打开
try:
f = open(‘cc.txt’,‘r’)
except:
f =open(‘cc.txt’.‘w’)

8.2.2 捕获特定异常

基本语法:

try:
    可能发生异常的代码
except 异常类型:
    出现异常时执行的代码

当需要捕获特定异常时,把该异常类型放在except后面

举例:尝试打印name变量,如果name变量未定义,则提示错误信息

try:
    print(name)
except NameError as e:  # 捕捉特定的 NameError 异常
    print('name变量定义错误')

注意:

  1. 如果尝试执行的代码异常类型与要捕获的不一致,则无法捕获异常
  2. 一般try下方只放一行尝试执行的代码

8.2.3 捕获多个异常

基本语法:

try:
    可能发生异常的代码
except 异常类型组:
    出现异常时执行的代码

当需要捕获多个异常时,可以把要捕获的异常类型用元组形式书写在except后面

举例:
待补充。。。

注意:

  • 未正确设置捕获异常类型,则无法捕获异常

8.2.4 捕获全部异常

基本语法格式:

try:
    可能发生异常的代码
except exception:
    出现异常时执行的代码

通常捕获全部异常使用捕获exception类型对象
另一种写法就是捕获常规异常的写法

8.2.4 异常的else语句

try…except…else
try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。

基本语法格式:

try:
    可能发生异常的代码
except exception:
    出现异常时执行的代码
else:
    没有异常时要执行的代码  

else 子句将在 try 子句没有发生任何异常的时候执行。

8.2.5 异常的finally语句

try…except…else…finally
表示有没有异常都要执行的语句
基本语法格式:

try:
    可能发生异常的代码
except Exception:
    出现异常时执行的代码
else:
    没有异常时要执行的代码 
finally:
    有没有异常都要执行的代码

总结:

  • 在异常中,else和finally都是可选的,可写可不写
  • 捕获全部的异常可以用:except 或 except Exception
  • 可以对异常改用别名,except [异常 as 别名]:

8.3 异常的传递

异常是具有传递性的
简单来说就是当你调用一个函数时,可以其嵌套调用的函数会发生异常,如果其没有对异常进行捕获,那么该异常就会传递到当前调用的函数上。
举例:

def func01():
    print('这是func01开始')
    num = 1 / 0    # 除数为0,引发异常
    print('这是func01结束')
    
def func02():
    print('这是func02开始')
    func01()    # 调用func01 函数
    print('这是func02结束')

def main():
    try:
        func02()    # 调用func02
    except Exception:
        print(Exception)

main() 

在上述的例子中,当主函数中的func02调用到func01函数时,发生异常,func01函数没有对其进行捕获,异常就会传递到func02函数,func02函数也没有对这个异常进行捕获,该异常就会传递到main函数中,被main函数捕获。

注意:

  • 当所有函数都没有捕获异常时,程序会报错

8.4 抛出异常

为什么还要手动设置异常呢?首先要分清楚程序发生异常和程序执行错误,它们完全是两码事,程序由于错误导致的运行异常,是需要程序员想办法解决的;但还有一些异常,是程序正常运行的结果,比如用 raise 手动引发的异常。
Python 使用 raise 语句抛出一个指定的异常
基本语法格式:raise [exceptionName [(reason)]]
[] 里的参数为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。

三种用法:

  • raise:该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
  • raise 异常类名称:表示引发执行类型的异常。
  • raise 异常类名称(描述信息):表示在引发指定类型的异常的同时,附带异常的描述信息。

举例:
raise默认引发 RuntimeError异常

try:
    a = input("输入一个数:")
    if(not a.isdigit()):
        raise
except Exception as e:
    print("引发异常:", repr(e)) 
输入一个数:a
引发异常: RuntimeError('No active exception to reraise')

注意:

  • 需要使用repr()函数,才能看到异常名称类型,
  • 如果使用format()函数则只能看到异常说明信息

raise引发当前上下文中捕获的异常,即except 块中的异常

try:
    a = input("输入一个数:")
    if(not a.isdigit()):
        raise ValueError("a 必须是数字")
except ValueError as e:
    print("引发异常:", repr(e))
    raise
输入一个数:a
引发异常: ValueError('a 必须是数字')
Traceback (most recent call last):
  File "E:\project.py\Leetcode\August\sads.py", line 8, in <module>
    raise ValueError("a 必须是数字")
ValueError: a 必须是数字

raise 异常类名称raise 异常类名称(描述信息):引发指定异常。

try:
    a = int(input("输入一个数:"))
    if a == 0:
        raise ZeroDivisionError("除数不能为零")
except ZeroDivisionError as e:
    print("引发异常:", repr(e))
输入一个数:0
引发异常: ZeroDivisionError('除数不能为零')

8.5 Python 模块

模块是 Python 程序架构的一个核心概念

  • 每一个以扩展名 py 结尾的 Python 源代码文件都是一个 模块
  • 模块名 同样也是一个 标识符,需要符合标识符的命名规则
  • 在模块中定义的 全局变量 、函数、类 都是提供给外界直接使用的 工具
  • 模块 就好比是 工具包,要想使用这个工具包中的工具,就需要先 导入 这个模块

8.5.1 模块的导入

模块在使用前需要先导入,模块的导入语法如下:
[from 模块名] import [模块 | 类 | 变量 | 方法 | *] [as 别名]
[]是可选的意思,表示里面的参数可以省略
常用的导入方式有:

  • import 模块名
  • import 模块名 as 别名
  • from 模块名 import *
  • from 模块名 import 类、变量、方法等
  • from 模块名 import 类、变量、方法等 as 别名

注意

一个模块只会被导入一次,不管你执行了多少次 import。这样可以防止导入模块被一遍又一遍地执行。

使用 import 语句的时候,Python 解释器是怎样找到对应的文件的呢?

Python 的搜索路径,搜索路径是由一系列目录名组成的,Python 解释器就依次从这些目录中去寻找所引入的模块。

8.5.1.1 import 语句

基本语法:

import 模块名
import 模块名、模块名

模块名.功能名()

通过 import 导入模块后,就可以通过 模块名.功能名 来使用模块中任意内容

举例:导入time模块:

import time  # 首先导入内置的time模块

print('开始')
time.sleep(3) # 必须以“模块名.对象名//模块名.方法名”的形式进行访问
print('结束')

注意:

  • 当引用一个解释器未安装/定义的模块时,会引发ModuleError的错误
  • 按住 Control键 + 鼠标左键点击,可进入该模块的文件
  • 引入模块后,可以通过 模块名. 使用任意功能
  • 模块的导入一般写在开头位置
  • 模块的功能被使用后,导入语句会高亮,否则会置灰
8.5.1.2 from … import 语句

基本语法:

from 模块名 import 功能名
from 模块名 import 功能名, 功能名

功能名()

相比于直接import 直接导入整个模块
通过 from 导入模块,可以确切导入模块中的具体某个或者某几个功能。

举例:导入time模块中的sleep()方法:

from time import sleep() # 导入time模块中的sleep() 方法

print('开始')
sleep(1)  # 直接使用对象“对象名//方法名”访问
print('结束')

相比于import导入,使用 from 这种方式仅导入明确指定的对象(函数),在使用该功能时,不需要在前面加入模块名
注意:

  • 使用from导入模块,在使用导入的功能时,可以直接用功能名()
  • 仅可以使用导入的功能,不可以使用模块中未导入的其他功能
from math import sin,cos,tan  # 可以一次从一个文件中导入多个函数

当然from 也可也把全部的功能导入进来,只需使用如下声明:from modname import *
这种导入与improt导入类似,只是在使用功能时,写法不一样使用

8.5.1.3 as 别名

基本语法:

# 给模块定义别名
import 模块名 as 别名

# 给功能定义别名
from 模块名 import 功能名 as 别名

作用:给部分过长的模块名/功能名 更改为简短的名称
举例:

import time as t # 将time模块更改名为 t

print('开始')
t.sleep(3)    # 必须以“别名.对象名//别名.方法名”的形式进行访问
print('结束')
from time import sleep as sl   # 将time模块中的sleep 方法更改为sl别名

print('开始')
sl(1)
print('结束')

注意:

  • 使用as将模块名或者方法名更改别名后,无法再使用原模块名或方法名,其属于未定义内容
  • 模块的导入一般写在开头位置

8.5.2 自定义模块

  • 每个py文件都可以当作一个模块,模块的名字即是文件的名字
  • 自定义模块名必须符合标识符的命名规则
8.5.2.1 定义模块

有些时候需要自定义一些模块。
新建模块的方法:
举例:新建一个Python文件,命名为my_module.py,并定义test函数:
my_module.py

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

使用 import 导入my_module 模块,调用 my_module.py 中的 test 方法

import my_module

my_module.test(10,20)
8.5.2.2 调试模块

__name__属性
每个模块都有一个__name__属性,当其值是’main’时,表明该模块自身在运行,否则是被引入
这一属性很重点,方便调试,一般我们在单个文件中调试函数是如下:

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

但是上面这样的写法,当文件被导入其他文件时,就会调用test()

def test(a,b):
    print(a+b)
    
if __name__ == '__main__':
    print('程序自身在运行')
    test() 
else:
    print('我来自另一模块')

使用__name__属性,这样可以让文件程序自身运行时执行相应的调试功能test() ,非自身运行时,不执行调用test()

# 模块1代码
def my_test(a, b):
    print(a + b)

# 模块2代码
def my_test(a, b):
    print(a - b)
   
# 导入模块和调用功能代码
from my_module1 import my_test
from my_module2 import my_test

# my_test函数是模块2中的函数
my_test(1, 1)

注意:

  • 一个模块如果是在该模块自身运行: _ name _ == ‘_ main _’
  • 一个模块被另一个程序引入时:_ name _ != ‘_ main _’
  • 如果使用from … import …或from … import *导入多个模块的时候,且模块内有同名功能。当调用这个同名功能的时候,调用到的是后面导入的模块的功能。

__all__属性
==可以控制import * 能够导入的内容==

如果存在一个叫做 all 的列表变量,那么在使用 from ,module import * 的时候就把这个列表中的所有名字作为模块方法导入。

举例:有个模块my_module.py的文件内容如下:

__all__ = ["testA"]

def testA():
    print('testA')
    
def testB():
    print('testB')

在另一个文件中,使用import * 导入

from my_module import *

testA()       #只能导入testA函数
testB()    # testB函数报红,说明没有这个函数

因为在_ all _ 的列表中,没有 testB 这个函数,所以上面引用 testB 函数失败

8.5.3模块的查找路径

当导入一个模块,Python解析器对模块位置的搜索顺序是:

  • 当前目录
  • 如果不在当前目录,Python则搜索在shell变量PYTHONPATH下的每个目录。
  • 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/

模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

注意:

  • 自己的文件名不要和已有模块名重复,否则导致模块功能无法使用
  • 使用from 模块名 import 功能的时候,如果功能名字重复,调用到的是最后定义或导入的功能。

8.6 包

8.6.1 包的概念

将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py 文件,那么这个文件夹就称之为包。

  • 包 是一个 包含多个有联系的模块组织在一起 的 特殊目录(文件夹)
  • 目录下有一个 特殊的文件__init__.py
  • 包名的 命名方式 和变量名一致,小写字母 + _

作用:使用 import 包名 可以一次性导入 包 中 所有的模块

init.py 文件的作用是将文件夹变为一个Python模块,我们在导入一个包时,
实际上是导入了它的__init__.py文件,这样我们可以在__init__.py文件中批量导入我们所需要的模块,
而不再需要一个一个的导入。

8.6.2 创建包

一般操作[New] — [Python Package] — 输入包名 — [OK] — 新建功能模块(有联系的模块)。

注意:新建包后,包内部会自动创建__init__.py文件,这个文件控制着包的导入行为。

示例
新建包mypackage
新建包内模块:my_module1.pymy_module2.py
my_module1.py

print(1)


def info_print1():
    print('my_module1')

my_module2.py

print(2)


def info_print2():
    print('my_module2')

8.6.3 导入包

模块和包的导入方法基本一致,只是需要写清楚这个模块来源哪个包
import 包名.模块名
基本语法:

# 导入
import 包名.模块名

# 调用功能
包名.模块名.功能名()

举例:

# 导入my_package.my_module1 
import my_package.my_module1

# 调用
my_package.my_module1.info_print1()

from 包名.模块名 import 功能名
基本语法:

# 导入
from 包名.模块名 import 功能名

# 调用功能
功能名()

举例:

# 从 my_package.my_module1 里导入 info_print1 函数
from my_package.my_module1 import info_print1

# 调用
info_print1()

import 语法中的item总结:

import item.subitem.subsubitem 这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字。

import 语法会首先把 item 当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,抛出一个 :exc:ImportError 异常。

from package import item 这种形式,对应的 item 既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。

as 别名
跟前面module的用法一致

_ all _属性
导入语句遵循如下规则:如果包定义文件 _ init .py 存在一个叫做 _ all _ 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。
注意all _属性仅能控制from package import * 导入的

8.6.4 导入第三方包

对于一个第三方的包,如果我们想使用其中的功能的话,那么我门首先需要导入这个包
例如:导入requests包:

如果使用pycharm,可以在设置-解释器环境里面安装包。
在命令提示符中,可以使用 pip 工具来安装

pip安装包
基本用法:pip install packagename

pip的网络优化
由于pip时连接的国外的网站进行包的下载,所以有时候会下载失败或者速度很慢
优化做法,让其连接国内的网站进行包的安装:
基本语法:pip install packagename -i 网址 --trusted-host 网址的顶级域名
参数:

  • packagename:需要安装的包名
  • -i :表示切换,后接需要更改的连接网址
  • –trusted-host :表示信任,后接前面连接网址的顶级域名

举例:
安装:pip install packagename -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
卸载:pip uninstall packagename -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

常用的国内镜像源
中国科学技术大学 : https://pypi.mirrors.ustc.edu.cn/simple
豆瓣:http://pypi.douban.com/simple/
阿里云:http://mirrors.aliyun.com/pypi/simple/
清华大学:https://pypi.tuna.tsinghua.edu.cn/simple

8.6.5 包的访问路径

相对路径访问
package/
– – init.py
– – subpackage1/
– – – – init.py
– – – – moduleX.py
– – – – moduleY.py
– – – – – – def spam()
– – subpackage2/
– – – – init.py
– – – – moduleZ.py
– – ---- – – def eggs()
– – moduleA.py
– – – – def foo()
假设当前文件是moduleX.pysubpackage1 / __ init__.py,则以下是新语法的正确用法:(.py文件不是模块)

同级文件目录下引用
引用moduleY.py文件中的方法: import moduleY

不同级文件目录下引用
引用 import subpackage2// from subpackage2 import py文件中的方法

#  .表示当前目录,对于`moduleX.py`文件,当前目录路径为:package/subpackage1/
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY

# ..表示上一级目录,对于`moduleX.py`文件,当前目录路径为:package/
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo

# ...表示上上一级目录
from ...package import bar
from ...sys import path

父目录调用子目录
例如 moduleA.py 调用subpackage2中的 moduleZ.py 文件
父目录调用子目录,可以使用以下两种方式

# 方式一
from subpackage2 import moduleZ  

# 方式二
from subpackage2.moduleZ import eggs 
from subpackage2.moduleZ import *  

推荐常用方式二

同级目录下文件的调用
例如moduleX.py件调用subpackage2中的moduleZ.py文件

import sys
sys.path.append('../B')    sys.path.append(os.path.split(os.getcwd())[0])
from B.B1 import *

在这里插入图片描述

9. 面向对象

面向对象编程(Object-oriented Programming,简称OOP)是一种编程范例,它提供了一种结构化程序的方法,以便将属性和行为捆绑到单个对象中。面向对象编程OOP将现实世界的实体建模为软件对象,以及与之相关的数据,并可以执行某些功能。
对象是面向对象编程范例的核心,不仅在函数编程中表示数据,而且在程序的整体结构中也是如此

三大特性
封装、继承、多态

封装 :根据 职责 将 属性方法 封装 到一个抽象的 类 中

封装的意义
将属性和方法放到一起做为一个整体,然后通过实例化对象来处理;
隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了;
对类的属性和方法增加 访问权限控制。

9.1 类和对象

9.1.1 类的定义

:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法
类就是封装

类大体结构为:

  • 类:
    • 类属性
    • 实例属性
    • 类方法
    • 实例方法

在Python中,定义类是通过class关键字来实现的

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>

在Python中定义类很简单,使用关键字class既可,后面接上类的名称(需要使用大驼峰命名)

在Python 3中,定义新类时,Python 3隐式使用object作为父类;在python2.X中,需要主动指定使用

# Python 2.x类定义:
class ClassNameobject):
    <statement-1>
    .
    .
    .
    <statement-N>

(object)表示该类对象继承自Python内置的类对象object,Python中所有的类对象都继承自一个统一的基类:object

9.1.2 对象的定义

对象:python中一切皆对象。 上述的类其实也是一个对象object.
语法解析,当解释器执行class语句时,就会创建一个类对象,类的数据类型是type类型

# 定义一个类对象
class Dog:
    pass

注意
对象包括两个数据成员(类变量和实例变量)和 类方法

9.2 实例化对象

将抽象对象转变为实体化对象,就是实例化对象
实例化一个类是通过在类名后面加小括号“()”来实现
类的实例化就是创建一个类的实例,类的具体对象
根据类对象创建实例对象基本语法: 变量名 = 类名([实参])

# 定义类对象
class Dog:
    
    name = '大黄'
    
# 类对象
dog1 = Dog

# 实例对象
dog2 = dog1() 

注意:python的类,带括号是实例化,不带括号是赋值
具体需要了解一个_ new _ 方法

9.3 类属性

类属性通常用于保存与类相关的常量或配置信息,类属性是属于类的。
类属性:定义在类里面,类方法外面的变量就是类属性
类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用

9.3.1 定义类属性

属性的定义方法跟变量的定义方法类似,保持一致的命名规则
如下是定义一个空属性name :

class Dog:
    
    name = None  # 名字

9.3.2 访问类属性

访问公有类属性可以分为:类外部访问类内部访问

9.3.2.1 类外部访问

类外部访问可以通过两种方式访问类属性:

  1. 创建一个类之后,可以通过类名访问其属性
  2. 类实例化后,可以通过实例名访问其属性

属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name。

注意:推荐类属性使用 类名.name 方式操作访问

当某个实例调用类属性时,它们访问的是类属性的副本,这意味着当类属性的值发生改变时,所有实例都会受到影响

通过类名访问其属性
调用方法:类名.name
如下:

#类定义
class People:
    # 定义基本属性
    name = '小美'
    age = 18

# 直接通过类名访问其属性
print("我叫:%s,今年:%s岁" % (People.name, People.age))

输出结果:

我叫:小美,今年:18岁

通过实例名访问其属性
调用方法:实例名.name

class People:
    # 定义基本属性
    name = '小美'
    age = 18

a = People()
print("我叫:%s,今年:%s岁" % (a.name, a.age))

输出结果:

我叫:小美,今年:18岁
9.3.2.1 类内部访问

类内部访问也分为类方法访问和实例方法访问

类方法访问类属性
类方法访问类属性需要使用cls关键字
cls 关键字
cls 关键字是类方法定义的时候,必须要填写的参数

  • 它用来表示类自身的意思
  • 当我们使用类对象调用方法的时候,cls 会被python自动传入
  • 在类方法的内部,想要访问类的类变量,必须使用cls
  • cls 在传参的过程时候可以忽略
class People:
    # 定义基本属性
    name = '小美'
    age = 18
    
    @classmethod
    def adc(cls):
        print("我叫:%s,今年:%s岁" % (name, age)) # 报错,类内部使用应该用self来绑定如:cls.name, cls.age

实例方法访问类属性
实例方法访问类属性需要使用self关键字

self 关键字
self关键字是实例方法定义的时候,必须要填写的参数

  • 它用来表示实例自身的意思
  • 当我们使用类对象调用方法的时候,self会被python自动传入
  • 在实例方法的内部,想要访问类的类变量,必须使用self
  • self在传参的过程时候可以忽略

举例:

class People:
    # 定义基本属性
    name = '小美'
    age = 18
    
    def adc(self):
        print("我叫:%s,今年:%s岁" % (name, age)) # 报错,类内部使用应该用self来绑定如:self.name, self.age

9.3.3 修改类属性

修改一个类属性的值有两种方法

  • 对象名.属性名 = 数据 ----> 直接修改
  • 对象名.方法名() ----> 间接修改

对象名.属性名 = 数据 ----> 直接修改

class People:
    # 定义基本类属性
    name = '小美'
    age = 18

#定义两个实例化对象
a=People()
b = People()

# 通过类名.变量名来修改基本属性
People.name = '小帅'
People.age = 24
print("我叫:%s,今年:%s岁" % (People.name, People.age))

# 通过实例名.变量名来修改基本属性
a.name = "小梅"
a.age = 25
print("我叫:%s,今年:%s岁" % (a.name, a.age))

# 检查没有主动修改的b实例对象中类属性值有无改变
print("我叫:%s,今年:%s岁" % (b.name, b.age))

输出结果:

我叫:小帅,今年:24岁
我叫:小梅,今年:25岁
我叫:小帅,今年:24岁

详解:

  1. 类对象名.变量名访问的方式可以更改了类属性,从上述中实例b的输出可知
  2. 实例对象名.变量 = 数据 默认是给实例对象添加实例属性,并不能操作类属性

注意

  1. 类属性只能通过类对象修改,不能通过实例对象修改
  2. 如果类属性和实例属性同名,实例对象名只能操作实例属性

对象名.方法名() ----> 间接修改
需要先了解方法的知识才比较好懂这个内容

class Boy:
    name = 'silver'  # 私有变量
    
    def chName(self,name): # 定义一个方法,使得在外部可以调用
        self.name = name
        
b = Boy()
b.chName('逍遥')
print(b.name)  输出结果:'逍遥'

通过调用方法,来修改属性

9.4 类方法

在类中可以定义函数用来记录行为
类中定义的行为(函数)叫做类方法,也叫做成员方法

9.4.1 定义类方法

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

class A(object):
    name = 'I am Class A'
 
    @classmethod
    def class_method(cls, s):
        print("调用类方法")

a = A()
A.class_method()
a.class_method()

9.4.2 访问类方法

有两种访问方式:

  • 使用类直接调用
  • 使用实例调用
class A(object):
    name = 'I am Class A'
 
    @classmethod
    def class_method(cls, s):
        print("调用类方法")

a = A()
A.class_method()
a.class_method()

能够通过实例对象和类对象去访问。类方法通常使用类直接调用,也可以用实例调用(不推荐)。当实例调用的时候,Python会将实例的最底层类(即实例直接所属类)型传入cls参数中

注意:类方法是无法调用实例属性的
举例子:

class A(object):
    def __init__(self):
        self.age = 18
        
    @classmethod
    def class_method(cls):
        print("调用实例属性%s "%(cls.age))  # 出错,类无age属性

a = A()
A.class_method()
a.class_method()

运行结果:

    print("调用实例属性%s " % (cls.age))  # 出错,类无age属性
AttributeError: type object 'A' has no attribute 'age'

类方法没有实例属性,无法调用该属性

9.5 实例属性

实例属性是从属于实例对象的属性,也称为“实例变量”,其跟类变量不一样
类体中,所有函数内部:以self.变量名的方式定义的变量,称为实例属性或实例变量
实例变量就是一个用 self 修饰的变量

9.5.1 定义实例属性

定义实例属性需要使用我们的魔法构造方法:_ init _
_ init _() 方法也称之为构造方法:

  1. 在创建类对象的时候,会自动执行_ init _() 方法
  2. 在创建类对象的时候,将传入参数传递给 _ init _ 方法使用

_ init _() 方法无需主动调用,在创建新的类对象时会自动调用,其可以传入参数也可也不传入参数

9.5.1.1 不传参数方式定义

举例:

class Lange:
    
    # 魔法构造方法
    def __init__(self):   
        self.name = "中文"
        self.address = "http://"
        
    # 下面定义了一个say实例方法
    def say(self):
        self.age = 13
        
clang = Lange()
print(clang.name)
print(clang.address)
print(clang.age)

输出结果:

"中文"
"http://"
报错:AttributeError: 'Lange' object has no attribute 'age'

Lange 类中,nameaddress 以及 age 都是实例变量。但是Lange类的实例对象都会包含 nameadd 实例变量,而只有调用了 say() 方法的实例对象,才包含 age 实例变量

9.5.1.2 传参方式定义
class Student:

    # 魔法构造方法
    def __init__(self, name):
        self.name = name  # 此时实例变量name等于外部传入的参数name

s = Student('小红')
print(s.name)

输出结果:

小红

此例中,此时实例变量name等于外部传入的参数name。这使得类具有很好的扩展性

9.5.2 访问实例属性

在类内部访问
使用:self.name
例如:

class Student:

    # 魔法构造方法
    def __init__(self):
        self.name = "中文"


    # 下面定义了一个say1实例方法
    def say1(self):
        print("我的名字是:%s" %self.name) 


    # 下面定义了一个say2实例方法
    def say2(self):
        print("我的名字是:%s" %name)


s = Student()
print(s.say1())
print(s.say2())

输出结果:

我的名字是:中文
NameError: name 'name' is not define

在上面的例子中,在类方法中,调用实例变量需要使用self关键字
结合之前的学习,在类方法中,调用类变量也需要使用self关键字

在类外部调用
使用:实例对象名.name

class Student:

    # 魔法构造方法
    def __init__(self):
        self.name = '小红'  

s = Student()
print(s.name)  #使用实例对象名.name调用
print(Student.name) #使用类对象名.name调用

输出结果:

小红
AttributeError: type object 'Student' has no attribute 'name'

在上述例子中,调用实例变量只能使用 实例对象名.name 调用

总结
在类方法中,不管调用实例变量还是类变量,都需要使用self关键字
在类外部,调用实例变量只能使用 实例对象名.name 调用

9.5.3 添加实例属性

可以在对象实例化后,再给对象添加实例属性
举例:

class Student:

   # 魔法构造方法
   def __init__(self):
       self.name = '小红'  

s = Student()
s.age = 18  # 新增一个实例属性,age

在前面类变量中提到通过实例对象可以访问类变量,但无法修改类变量的值。这是因为,通过实例对象修改类变量的值,不是在给“类变量赋值”,而是定义新的实例变量
实例变量只能通过对象名访问,无法通过类名访问。

9.6 实例方法

9.6.1 实例方法定义

在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例
定义语法

def 方法名(self, 形参1, ....., 形参n):
    方法体

9.6.2 调用实例方法

在类内部调用实例方法时,需要使用self关键字
但是在类外部调用实例方法时,无需传入self参数
如:

class Student:
    name = '小蓝'
    
    # 定义实例方法,并且使用self关键字
    def say_1(self):
        # 在方法的内部,想要访问类的类变量,必须使用self
        print("hello 大家好,我叫做%s"%(self.name)) 
    
    # 定义实例方法,并且使用self关键字,外部传入参数
    def say_2(self,msg):
        print("时间过得真快,%s"%(msg))
    
    # 内部调用实例方法
    def say_3(self):
        print("我是方法3") 
        self.say_1()     

stu = Student()
stu.say_1()                 # 类外部调用实例方法
stu.say_2("我已经15岁了")   # 类外部调用实例方法
stu.say_3() 

输出结果:

hello 大家好,我叫做小蓝
时间过得真快,我已经15岁了
hello 大家好,我叫做小蓝

总结

  • self 表示类对象本身的意思
  • 在方法的内部,想要访问类的类变量,必须使用self
  • self 虽然出现在形参列表中,但是无需理会

9.7 私有属性

对于部分属性和行为不希望对外公开或者开放使用。所以有了私有属性这个概念

9.7.1 定义私有属性

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

私有属性也可也分为私有类属性和私有实例属性
举例:

class Boy:
    __name = 'silver'  # 私有类属性
    
    def __init__(self):
        __age = 18    # 私有实例属性

9.7.2 访问私有属性

9.7.2.1 类内部访问

私有属性,可以在类内部通过self或者cls调用

class Boy:
    __name = 'silver'  # 私有变量
    
    def __init__(self):
        self.__age = 18     # 私有实例属性
    
    def get1(self):      # 类内部,实例方法调用
        print("实例方法调用:%s %s"%(self.__name, self.age))
    
    @classmethod
    def get2(cls):      # 类内部,类方法调用
        print("类方法调用:%s %s"%(cls.__name))  

总结:
无论是公有还是私有属性
在类内部,实例方法调用需要 self 调用类或者实例属性
在类内部,类方法调用需要 cls 调用类属性, 但是无法调用实例属性

9.7.2.2 类外部访问

私有属性不能在类的外部被使用或直接访问,通用方法:定义一个可以调用的公有方法

class Boy:
    __name = 'silver'  # 私有变量
    
    def getName(self):
        print(self.__name)
    
a = Boy()
a.getName()

通过定义公有方法,使得私有属性可以在外部调用

9.8 私有方法

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

9.8.1 定义私有方法

私有方法也可也分为私有类方法和私有实例方法
举例:

class A(object):
    
    __name = '小明'
    
    def __init__(self):
        self.__age = 18

    @classmethod        
    def __class_method(cls):  # 定义私有类方法
        print("调用私有类属性%s " % (cls.__name)) 
    
    def __self_method(self):  # 定义私有实例方法
        print("调用私有实例属性%s " % (self.__age)) 

9.8.2 访问私有方法

9.8.2.1 类内部访问

私有方法,可以在类内部通过self或者cls调用

class A(object):
    
    __name = '小明'
    
    def __init__(self):
        self.__age = 18

    @classmethod        
    def __class_method(cls):  # 定义私有类方法
        print("调用私有类属性%s " % (cls.__name)) 
    
    def __self_method(self):  # 定义私有实例方法
        print("调用私有实例属性%s " % (self.__age)) 
    
     @classmethod      
    def get1(cls):  # 
        print("调用私有类方法 ") 
        cls.__class_method()
    
    def get2(self):  # 
        print("调用私有实例方法 ") 
        self.__self_method()  
        
9.8.2.2 类外部访问

私有属性不能在类的外部被使用或直接访问,通用方法:定义一个可以调用的公有方法

class A(object):
    __name = '小明'

    def __init__(self):
        self.__age = 18

    @classmethod
    def __class_method(cls):  # 定义私有类方法
        print("调用私有类属性%s " % (cls.__name))

    def __self_method(self):  # 定义私有实例方法
        print("调用私有实例属性%s " % (self.__age))

    @classmethod
    def get1(cls):  #
        print("调用私有类方法 ")
        cls.__class_method()

    def get2(self):  #
        print("调用私有实例方法 ")
        self.__self_method()


a = A()
a.get1()
a.get2()

运行结果:

调用私有类方法 
调用私有类属性小明 
调用私有实例方法 
调用私有实例属性18

注意:

  • 类的属性和方法,在对象实例化时,会被实例化为实例方法,所以cls类属性和类方法,可以用 self 来访问,但是实例属性和实例方法,不能被 cls访问
9.8.3 属性和方法总结

调用属性总结

  • 类内部
    • 实例方法中需要self.name调用类属性或者实例属性
    • 类方法中需要cls.name调用类属性
  • 类外部
    • 推荐用类名.属性名调用类属性
    • 推荐用对象名.属性名调用实例属性,虽然也可调用类属性,但不推荐
    • 只能通过调用公有方法来间接调用私有属性

调用方法总结

  • 类内部
    • 实例方法中需要self.method()调用类方法或者实例方法
    • 类方法中需要cls.method()调用类方法
  • 类外部
    • 推荐用类名.方法名()调用类方法
    • 推荐用对象名.方法名()调用实例方法,虽然也可调用类方法,但不推荐
    • 只能通过调用公有方法来间接调用私有方法

私有属性和方法总结

  • 命名:都是以双下划线__作为开头
  • 访问限制:无法通过类对象直接访问 ,本类中内部可以访问;
  • 继承:都不会被子类继承,子类也无法访问
  • 作用:通常用来处理类的内部事情,不通过对象处理,起到安全作用。

9.9 内置魔法方法

除了前面使用到的_ init _ 构造方法,python中还存在一些内置的类方法,各自有各自的功能,统称为魔法方法。
魔法方法:

  • _ init _ 构造方法,在生成对象时自动调用
  • _ new _ 生成方法,在生成对象时调用
  • _ str _ 字符串方法
  • _ del _ 析构方法
  • _ call _ 当对象被当作函数调用时,自动调用
  • _ eq _ == 符号比较方法

9.9.1 _ new _ 生成对象方法

__new__魔术方法返回的就是self的内存地址

  1. 如果不在__new__方法里面调object的__new__方法就不会创建对象,__init__不会被执行;
  2. 如果不在__new__方法里面return创建好的对象,__init__不会被执行
class Test:
    def __new__(cls, *args, **kwargs):
        print("我是__new__方法")
        obj = object.__new__(cls)
        print(obj)
        return obj

    def __init__(self):
        print(self)
        print("我是__init__方法")

a = Test()

运行结果:

我是__new__方法
<__main__.Test object at 0x123902f70>
<__main__.Test object at 0x123902f70>
我是__init__方法

对象初始化时执行__new__,目的是为该对象分配内存空间。
对象初始化时一般先执行__new__,再执行__init__,如果缺少__new__返回的对象,那么将不会执行__init__

9.9.2 _ str _ 字符串方法

__str__方法用于返回对象的描述信息:

  • 如果不使用__str__方法,直接print,或者return,返回的是对象的内存地址。
  • 如果在__str__中定义了描述信息,print或者return时,返回的就不是内存地址,显示更友好,实现了类到字符串的转化。

举例:
不使用__str__方法

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age

stu = Student('小花',20)
print(stu)    # 输出类对象地址
print(str(stu))  # 将类对象转化为字符串

运行结果:

<__main__.Student object at 0x000001CD8B6ED340>
<__main__.Student object at 0x000001CD8B6ED340>

当类对象需要被转换为字符串时,会输出内存地址。

使用__str__方法
可以自定义方法内容,通过__str__方法来控制类转化为字符串的行为

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"name={self.name},age={self.age}"

stu = Student('小花',20)
print(stu)
print(str(stu))

运行结果:

name=小花,age=20
name=小花,age=20

_ str _ 字符串方法 相当于是对 str 运算符重载
还有一个魔术方法__repr__,与__str__类似,当同时出现时,str__优先级高于__repr

9.9.3 _ del _ 析构方法

对象被删除的时候调用此方法:

  1. 对象在内存中被释放时,自动触发执行;
  2. 此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以__del__()的调用是由解释器在进行垃圾回收时自动触发执行的
class Test:

    def __init__(self):
        print("初始化对象")

    def __del__(self):
        print("对象被删除了")

a = Test()
print("end")

运行结果:

初始化对象
对象被删除了

9.9.4 _ call _ 方法

默认自动调用,把类实例当成函数执行的时候会触发__call__方法,对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
举例:

class Test:

    def __call__(self, *args, **kwargs):
        print("调用了__call__")
   
        
a = Test()        
a()

运行结果:

调用了__call__

9.9.5 _ eq _ == 符号比较方法

调用相等判断的时候自动调用

class Test:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        print(self.age)
        print(other.age)
        return self.age == other.age  #判断当前的跟其他的



t1 = Test("狗子", 22)
t2 = Test("小李", 23)
print(t1 == t2) 

运行结果:

22
23
False

当调用了 == 符号时,就会去自动调用__eq__ 方法

9.10 继承

继承: 实现代码的重用,相同的代码不需要重复的编写

作用:继承就是可以获取另外一个类的静态属性或者普通方法,(并非所有成员)。让类和类之间产生父子关系,子类可以拥有父类的静态属性和方法。

9.10.1 继承的基础语法

在Python中,新建的类可以继承一个或者多个父类,其中:

  • 父类又可以称为基类或者超类,新建的类称为派生类或子类
  • 子类 继承自 父类,可以直接 使用 父类中已经封装好的公有方法,不需要再次开发
  • 子类 封装 子类特有的 属性和方法

继承又可以分为:单继承多继承
继承的基本语法:
单继承

class 类名(父类名):

    pass

多继承

class 类名(父类名1, 父类名2):

    pass

9.10.2 单继承

子类继承一个父类,不仅可以调用子类定义方法,也调用父类中的方法
单继承举例:

# 定义一个类使用4g通话,再定义一个类使用5g通话
class iphone: # 定义一个父类iphone
    name = '苹果手机'
    
    def call_by_4g(self):
        print("4g通话")

# 定义一个子类iPhone8 继承至父类
class iphone8(iphone): 
    face_id = '100001'
    
    def call_by_5g(self):
        print("新功能,5g通话")
        
        
phone = iphone8()
print(phone.name)    # 打印父类的name属性
phone.call_by_4g()   # 调用父类的方法
phone.call_by_5g()   # 调用子类方法

继承具有传递性:
如果C 类从 B 类继承,B 类又从 A 类继承,那么 C 类就具有 B 类和 A 类的所有属性和方法

9.10.2 多继承

子类继承多个父类,不仅可以调用子类定义方法,也调用父类中的方法
举例:

class NFCReader:
     nfc_type = '第三代'
     producer = "MM"
     
    def read_card(self):
        print("nfc读卡")
    
    def write_card(self):
        print("nfc写卡")

class RemoteControl(self):
    rc_type = "第二代"
    
    def control(self):
        print("红外遥控")
    
class MYphone(NFCReader, RemoteControl):
    pass

phone = MYphone()
phone.read_card()  # 调用父类的读卡功能
phone.control()  # 调用父类的红外遥控功能

MYphone 这个类继承了 NFCReader 和 RemoteControl 两个父类,所以它具有两个类所拥有的全部功能

父类之间 存在 同名的属性或者方法
继承多个父类,如果有同名的成员(属性和方法),那么默认以(从左到右的)继承顺序为优先级

class NFCReader:
     nfc_type = '第三代'
     producer = "MM"
     
    def read_card(self):
        print("nfc读卡")
    
    def write_card(self):
        print("nfc写卡")

class RemoteControl(self):
    producer = "NN"
    rc_type = "第二代"
    
    def control(self):
        print("红外遥控")
    
class MYphone(NFCReader, RemoteControl):
    pass

phone = MYphone()
phone.producer()  # 输出结果为:"MM"

注意:开发时,应该尽量避免这种容易产生混淆的情况!
—— 如果 父类之间 存在 同名的属性或者方法,应该 尽量避免 使用多继承

Python 中的 MRO —— 方法搜索顺序
Python 中针对 类 提供了一个 内置属性 mro 可以查看 方法 搜索顺序
MRO 是 method resolution order,主要用于 在多继承时判断 方法、属性 的调用 路径
在搜索方法时,是按照 mro 的输出结果 从左至右 的顺序查找的:

  1. 如果在当前类中 找到方法,就直接执行,不再搜索
  2. 如果没有找到,就继续查找下一个类中是否有对应的方法,如果找到,就直接执行,不再搜索
  3. 如果找到最后一个类,还没有找到方法,程序报错

9.10.3 方法重写

子类继承父类的方法和属性后,可以进行复写。
即:再子类中重写定义同名的属性或方法

class iphone: # 定义一个父类iphone
    name = '苹果手机'
    
    def call_by(self):
        print("使用4g通话")


class Myphone(iphone): 
    name = '这是我的苹果手机'   # 复写父类属性
    
    def call_by(self):
        print("新功能,可以使用5g通话")  # 复写父类方法
        
myphone = Myphone()
print(myphone.name)   # 输出, '这是我的苹果手机'
myphone.call_by()   # 输出, '新功能,可以使用5g通话'

9.10.4 调用父类同名成员

一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果在类内部需要使用被复写的父类成员,需要使用以下两种调用方式:

  1. 使用类名调用父类成员, 具体为: 父类名.name \ 父类名.method
  2. 使用super()调用父类成员,具体为:super().name \ super().method

使用类名调用父类成员
举例:

class iphone:  # 定义一个父类iphone
    name = '苹果手机'

    def call_by(self):
        print("使用4g通话")


class Myphone(iphone):
    name = '这是我的苹果手机'  # 复写父类属性

    def call_by(self):
        print("新功能,可以使用5g通话")  # 复写父类方法

    def call_by_parent(self):
        print("调用父类的属性和方法,")
        print(iphone.name)
        iphone.call_by(self)


myphone = Myphone()
myphone.call_by_parent() 

运行结果:

调用父类的属性和方法,
苹果手机
使用4g通话

注意:

  1. 需要注意再使用类名.method() 调用父类方法时,需要传入参 数self
  2. 不推荐使用这种方法调用,因为一旦 父类发生变化,方法调用位置的 类名 同样需要修改

使用super()调用父类成员
举例:

class iphone:  # 定义一个父类iphone
    name = '苹果手机'

    def call_by(self):
        print("使用4g通话")


class Myphone(iphone):
    name = '这是我的苹果手机'  # 复写父类属性

    def call_by(self):
        print("新功能,可以使用5g通话")  # 复写父类方法

    def call_by_parent(self):
        print("调用父类的属性和方法,")
        print(super().name)
        super().call_by()


myphone = Myphone()
myphone.call_by_parent() 

运行结果同上,

super类
在 Python 中 super 是一个 特殊的类,super() 就是使用 super 类创建出来的对象
使用的场景:就是在 重写父类方法时,调用 在父类中封装的方法实现

注意:

  1. 使用super.method() 调用父类方法时,不需要传入参 数self
  2. 只可以在子类内部调用给你父类的同名成员,子类的实例对象默认都是调用子类复写后的
  3. 子类对象不能在自己的方法内部,直接访问父类的 私有属性 或 私有方法,可以通过父类的公有方法间接访问

9.11 类型注解

python在3.5版本之后引入了类型注解,以方便静态类型检查工具、IDE等第三方工具进行类型检查,起提示的作用,对 Python 程序的运行不会产生任何影响
类型注解:在代码中涉及数据交互的地方,提供数据类型的注解

主要功能:

  1. 帮助第三方IDE工具(如Pycharm)对代码进行类型检查,做代码提示
  2. 帮助开发者对变量进行类型注解

主要分为:变量类型注解、函数类型注解、容器类型注解

提示:按快捷键 ctrl + p 可以查看提示

9.11.1 变量类型注解

Python 是动态语言,其显著特点是在声明变量时,你不需要显式声明它的类型,不用纠结类型声明、类型转化等麻烦事
举例:

age = 20
print(age+1)

上面例子中虽然代码里没有明确指定 age 的类型,但是程序运行时隐式推断出它是 int 类型,因此可以顺利执行 age + 1 的动作。但是:如果变量的类型有错,编辑器、IDE等工具无法在早期替你纠错,只能在程序运行阶段才能够暴露问题。
所以,引入了类型注解方法,来明确的声明变量的类型。
基础语法:变量名: 数据类型 = 值
如:

var_1: int = 18
var_2: float = 3.5
var_3: str = 'abc'
var_4: bool = False
var_5: list = []

扩展-- 类对象类型注解

class Student:
    pass

stu: Student = Student()

语法是:对象名: 抽象类名 = 抽象类名()

9.11.2 容器类型注解

列表、字典、元组等包含元素的复合类型,用简单的 list,dict,tuple 不能够明确说明内部元素的具体类型。
因此要用到 typing 模块提供的复合注解功能

from typing import List, Dict, Tuple

my_list: List[int] = [1,2,3]
my_tuple: Tuple(str,int,bool) = ("yys", 889, True)
my_set: Set[int] = {1,2,3}
my_dict: Dict[str, int] = {"yys": 889}

在Python 3.9+ 版本后,内置的容器类型就支持了复合注解

my_list: list[int] = [1,2,3]
my_tuple: tuple(str,int,bool) = ("yys", 889, True)
my_set: set[int] = {1,2,3}
my_dict: dict[str, int] = {"yys": 889}

注意:

  1. 元组类型设置类型注解时,需要将每个元素都标记出来
  2. 字典类型设置类型注解时,需要2个类型,第一个是key,第二个是value

9.11.3 函数类型注解

函数和方法的形参及返回值都可以进行类型注解
函数和方法的形参类型注解
基本语法:

def 函数方法名(形参名: 类型, 形参名: 类型,......):
    pass

举例:

def add(x: int, y: int):
    return x + y

当调用add函数时,按下ctrl+p可以查看提示x和y的变量类型

函数和方法的返回值类型注解
基本语法:

def 函数方法名(形参名: 类型, 形参名: 类型,......) -> 返回值类型:
    pass

举例:

def add(x: int, y: int) -> int:
    return x + y
    
print(add(1,2))    

注意:返回值类型注解需要使用符号:->

9.11.4 Union类型注解

当列表或者字典等数据类型中存储的数据类型为混合类型时,就需要使用Union进行联合类型注解
语法:Union[类型1, 类型2......]

from typing import Union

# 使用Union对列表内的数据类型,进行联合类型注解
my_list: list[Union[str, int]] = [1,2,'yys']
# 使用Union对字典内的数据类型,进行联合类型注解
my_tuple: dict[str, Union[str, int]] = {'yys': '招财', 'age': 18}

Union类型注解也可也运用在函数(方法)形参及返回值中

Union的使用总结:

  • 导包:from typing import Union
  • 使用:Union[类型1, 类型2…]

虽然python是一门动态语言,但是对于在项目中使用来说,希望大家写好类型注解,编译器能在我们调用时提前进行检查,能减少我们程序出错的概率

9.12 多态

多态定义:不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
总结:

  1. 多态 可以 增加代码的灵活度
  2. 以 继承 和 重写父类方法 为前提
  3. 是调用方法的技巧,不会影响到类的内部设计

步骤:

  1. 定义父类,并提供公共方法
  2. 定义子类(继承父类),并重写父类方法
  3. 传递子类对象给调用者,可以看到不同子类执行效果不同

举例子,“需求:警务人员和警犬一起工作,警犬分2种:追击敌人和追查毒品,携带不同的警犬,执行不同的工作”:



# 1. 定义父类,提供公共方法: 警犬 和 人
class Dog(object):
 def work(self):  # 父类提供统一的方法,哪怕是空方法
     pass


# 2. 定义子类,子类重写父类方法:定义2个类表示不同的警犬
class ArmyDog(Dog):   # 继承Dog类
 def work(self):   # 子类重写父类同名方法
     print('追击敌人...')


class DrugDog(Dog):
 def work(self):
     print('追查毒品...')


# 定义人类
class Person(object):
 def work_with_dog(self, dog):  # 传入不同的对象,执行不同的代码,即不同的work函数
     dog.work()    # 在方法内部,直接让 狗对象 调用 work 方法


# 3. 创建对象,调用不同的功能,传入不同的对象,观察执行的结果
ad = ArmyDog()
dd = DrugDog()


jingyuan = Person()
jingyuan.work_with_dog(ad)
jingyuan.work_with_dog(dd)

恭喜你,你已经学完了python基础的全部内容。完结撒花!
在这里插入图片描述

以上是笔者学习过程中的笔记,如有错误,欢迎大家指正
参考资料:
官方文档:https://docs.python.org/zh-cn/3/index.html
菜鸟编程:https://www.runoob.com/python3/python3-tutorial.html
视频资料:https://www.bilibili.com/video/BV1qW4y1a7fU

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值