75.字符串的创建与驻留机制
- 字符串
- 在Python中字符串是基本数据类型,是一个不可变的字符序列
- 什么叫字符串驻留机制呢?
- 仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串的驻留池中,Python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量
- 仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串的驻留池中,Python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量
#实例
a='Python'
b="Python"
c='''Python'''
print(a,id(a)) #输出变量a,查看id地址
print(b,id(b))
print(c,id(c))
-
驻留机制的几种情况(交互模式)
- 字符串的长度为0或1时
- 符合标识符的字符串
- 字符串只在编译时进行驻留,而非运行时
- [-5,256]之间的整数数字
-
sys中的intern方法强制2个字符串指向同一个对象
-
PyCharm对字符串进行了优化处理 打开Python交互式进行测试
-
字符串的长度为0或1时
- 符合标识符的字符串
- 下面这个就是符合标识符的字符串了,可以看到id内存地址均为3424
- 字符串只在编译时进行驻留,而非运行时
- python是一种解释型语言,但实际上它的解释器也可以理解成编译器,它负责将python代码编译成字节码,也就是.pyc文件,
[-5,256]之间的整数数字
- 字符串驻留机制的优缺点
- 当需要值相同的字符串时,可以直接从字符串池里拿来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串是会比较影响性能的。
- 在需要进行字符串拼接时建议使用str类型的join方法,而非+,因为join()方法是先计算出所有字符中的长度,然后再拷贝,只new一次对象,效率要比"+"效率高
76.字符串的常用操作_字符串的查询操作
- 可以把字符串看成是字符的列表,所以字符串与列表查的操作是非常相似的,但区别就在于,当获得字符串中指定的索引时,除了有Index外,还有rindex、find以及rfind方法,
#实例
s='hello,hello'
print(s.index('lo')) #运行结果3
print(s.find('lo')) #运行结果3
print(s.rindex('lo')) #运行结果9
print(s.rfind('lo')) #运行结果9
#实例
#print(s.index('k')) #运行结果为ValueError: substring not found 译文:子串没找到
print(s.find('k')) #运行结果为-1 -->-->查找最后一次出现的位置,不存在返回-1;建议用不抛异常这种方法
#print(s.rindex('k')) #运行结果为SyntaxError: unexpected EOF while parsing 译文:解析时出现意外
print(s.rfind('k')) #运行结果为-1 -->查找最后一次出现的位置,不存在返回-1
77.字符串的常用操作_字符串的大小写转换操作方法
#实例
print('---字符串中的大小写转换的方法---')
s='hello,python'
a=s.upper() #转大写后会产生一个新的字符串对象(通俗讲就是会添加一个内存空间,内存地址会变)
print(a,id(a)) #转换后;运行结果为HELLO,PYTHON 2969352950256
print(s,id(s)) #转换前;运行结果为hello,python 2969352985584
b=s.lower() #转换后会产生一个新的字符串对象
print(b,id(b)) #运行结果为hello,python 1939784160688
print(s,id(s)) #运行结果为hello,python 1939783867376
print(b==s) #内容相同
print(b is a) #运行结果为false,也就是说内容是相同的,内存地址不同,没有字符串驻留机制
#print(s.lower(),id(s.lower()))
#print(s,id(s))
s2='hello,Python'
print(s2.swapcase()) #运行结果为HELLO,pYTHON -->小写转大写,大写转小写
print(s2.title()) #运行结果为Hello,Python -->每个单词首字母都转大写,其它都转小写
78.字符串的常用操作_字符串内容对齐操作的方法
#实例(很像文档中的左对齐、居中对齐、右对齐)
s='hello.Python' #声明一个变量
print('---居中对齐.center()---')
print(s.center(20,'*')) #运行结果为****hello.Python**** -->设置s变量的字符串为居中20个字符,hello,Python为12个字符,20-12=8因此指定星号*为两侧填充内容
print('---左对齐.ljust()---')
print(s.ljust(20,'*')) #
print(s.ljust(10)) #运行结果为hello.Python -->设置参数小于字符串字符长度且不指定第二个参数,将返回原字符
print(s.ljust(20)) #运行结果为hello.Python -->不指定第二个参数,输出结果后面是相应的空格
print('---右对齐.rjust()---')
print(s.rjust(20,'*')) #运行结果为********hello.Python
print(s.rjust(20)) #运行结果为 hello.Python
print(s.rjust(10)) #运行结果为hello.Python
print('---右对齐.zfill() 使用0进行填充---')
print(s.zfill(20))
print(s.zfill(10))
print('-8910'.zfill(8))
#运行结果
---居中对齐.center()---
****hello.Python****
---左对齐.ljust()---
hello.Python********
hello.Python
hello.Python
---右对齐.rjust()---
********hello.Python
hello.Python
hello.Python
---右对齐.zjust() 使用0进行填充---
00000000hello.Python
hello.Python
-0008910
79.字符串的常用操作_字符串的劈分
#实例
print('---split()--从字符串的左边开始劈分,默认的劈分字符是空格字符串,返回的值都是一个列表---')
s='hello world Python'
lst=s.split()
print(lst)
print('---split()--通过参数sep指定劈分字符串是的劈分符---')
s1='hello|world|Python'
print(s1.split(sep='|'))
print('---split()--通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独做为一部分---')
print(s1.split(sep='|',maxsplit=1))
print('---rsplit()--从字符串的右边开始劈分,默认的劈分字符是空格字符串,返回的值都是一个列表---')
print(s.rsplit())
print('---rsplit()--以通过参数sep指定劈分字符串是的劈分符---')
print(s1.rsplit('|')) #可以指定分隔符
print('---rsplit()--通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独做为一部分---')
print(s1.rsplit(sep='|',maxsplit=1)) #从右边指定分割次数为1
#运行结果
---split()--从字符串的左边开始劈分,默认的劈分字符是空格字符串,返回的值都是一个列表---
['hello', 'world', 'Python']
---split()--通过参数sep指定劈分字符串是的劈分符---
['hello', 'world', 'Python']
---split()--通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独做为一部分---
['hello', 'world|Python']
---rsplit()--从字符串的右边开始劈分,默认的劈分字符是空格字符串,返回的值都是一个列表---
['hello', 'world', 'Python']
---rsplit()--以通过参数sep指定劈分字符串是的劈分符---
['hello', 'world', 'Python']
---rsplit()--通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独做为一部分---
['hello|world', 'Python']
80.字符串的常用操作_字符串判断的相关方法
#字符串遍历补充
print('---直接遍历---')
source='appke,tiger,banana'
for sh in source:
print(sh)
print('---下标遍历---')
for index,sh in enumerate(source):
print(index,end='')
print(sh)
print('---range遍历---')
for index in range(len(source)):
print(index)
print('---迭代器---')
for sh in iter(source):
print(sh)
#实例
'''判断指定的字符串是不是合法的标识符'''
s='hello,python'
print('1',s.isidentifier()) #运行结果为false
print('2','hello'.isidentifier()) #运行结果为true
print('3','张三_'.isidentifier()) #运行结果为true
print('4','张三_123'.isidentifier()) #运行结果为true
'''判断指定的字符串是否全部由空白字符组成(回车、换行,水平制表符)'''
print('5','\t'.isspace()) #运行结果为true
'''判断指定的字符串是否全部由字母组成'''
print('6','abc'.isalpha()) #运行结果true
print('7','张三'.isalpha()) #运行结果为true
print('8','张三1'.isalpha()) #运行结果为false
'''判断指定字符串是否全部由十进制的数字组成'''
print('9','123'.isdecimal()) #运行结果为true
print('10','123四'.isdecimal()) #运行结果为false
print('11','ⅡⅡⅡ'.isdecimal()) #运行结果为false
'''判断指定的字符串是否全部由数字组成'''
print('12','123'.isnumeric()) #运行结果为true
print('13','123四'.isnumeric()) #运行结果为true
print('14','ⅡⅡⅡ'.isnumeric()) #运行结果为true -->验证罗马数字也是数字
'''判断指定字符串是否全部由字母和数字组成'''
print('15','abc1'.isalnum()) #运行结果为true
print('16','张三123'.isalnum()) #运行结果为true
print('17','abc!'.isalnum()) #运行结果为false
81.字符串的常用操作_替换与合并
#实例
print('---.replace()字符串替换__两个参数---')
s='hello,Python'
print(s.replace('Python','Java'))
print('---.replace()字符串替换__三个参数---')
s1='hello,Python,Python,Python'
print(s1.replace('Python','Java',2))
print('---.join()字符串合并---')
lst=['hello','java','Python']
print('|'.join(lst))
print(''.join(lst)) #为空会把三个单词连在一起组成新字符串
print('*'.join('Python')) #会把Python当作字符串序列进行连接
#运行结果
---.replace()字符串替换__两个参数---
hello,Java
---.replace()字符串替换__三个参数---
hello,Java,Java,Python
---.join()字符串合并---
hello|java|Python
hellojavaPython
P*y*t*h*o*n
82.字符串的比较操作
- 字符串的比较操作
- 运算符:>,>=,<,<=,==,!=
- 比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下一个字符,依次比较下去,直到两个字符串中的字符不相等时,其比较结果就是两个字符串的比较结果,两个字符串中的所有后续字符将不再被比较
- 比较原理:两上字符进行比较时,比较的是其ordinal value(原始值),调用内置函数ord可以得到指定字符的ordinal value。与内置函数ord对应的是内置函数chr,调用内置函数chr时指定ordinal value可以得到其对应的字符
#实例
print('apple'>'app') #true
print('apple'>'banana') #false -->相当于97>98吗?当然不大于所以为false
print(ord('a'),ord('b'))
print(ord('杨')) #26472 -->看下杨的原始值是多少
print(chr(97),chr(98)) #a b -->能输出a和b说明它们互为相反的操作
print(chr(26472)) #杨 -->26472原始值会得到对应字符码?输出结果为杨,答案是会
'''==与is的区别 ==比较的是value值 is比较的是id内存是否相等'''
a=b='Python'
c='Python'
print(a==b) #True
print(a==c) #True
print(a is b) #True
print(a is c) #True
print(id(a)) #3004608322480
print(id(b)) #3004608322480
print(id(c)) #3004608322480 -->abc内存都一直的原因是,字符串常量内存驻留机制,有相同的内容会指向同一个id内存空间
83.字符串的切片操作
- 字符串是不可变类型
- 不具备增、删、改等操作
- 切片操作将产生新的对象
#s[:5] -->不指定起始位置切到索引为5的位置实际切到4
#s[6:] -->不指定结束位置从索引为6的位置一直切到最后,而切出的字符串将从0重新开始表示
#s1+!+s2 --> +号是连接符,因此s1+!+s2几十将hello加上!加上Python组成新字符串,而索引从0重新开始标识
#实例
s='hello,Python'
s1=s[:5] #由于没有指定起始位置,所以从0开始切到索引为4的元素
s2=s[6:] #由于没有指定结束位置,所以切到字符串最后一个元素
s3='!' #将叹号赋值给s3
new_str=s1+s3+s2 #将切出来的两个字符串s1和s2与s3叹号通过连接符+连接,赋值给new_str
print(s1)
print(s2)
print(new_str)
print('---验证id内存地址是否相同---')
print(id(s))
print(id(s1))
print(id(s2))
print(id(s3))
print(id(new_str)) #答案是不相同的,由此可见每一次切出来的都是一个新的字符串
print('---切片[start:end:step] 完整的写法---')
print(s[1:5:1]) #从1开始截到5(不包含5),步长为1
print(s[::2]) #默认从0开始,没有写结束,默认到字符串最后一个元素,步长为2,两个元素之间的索引间隔为2
print(s[::-1]) #默认从字符串的最后一个元素开始,到字符串的第一个元素结束,因为步长为负数
print(s[-6::1]) #从索引为-6开始,到字符串最后一个元素结束,步长为1
#运行结果
hello
Python
hello!Python
---验证id内存地址是否相同---
3091268033584
3091270854256
3091270918576
3091263557744
3091270920432
---切片[start:end:step] 完整的写法---
ello
hloPto
nohtyP,olleh
84.格式化字符串
- 解析:字符串的拼接操作会产生很多新的字符串会造成空间的浪费,所以这时候就需要使用格式化字符串就可以了(按一定格式输出的字符串)。
#我的名字叫:{0},今年{1}岁了,我真的叫:{0}'.format(name,age)解析
#所有format(name)都会用0去替换
#实例
'''格式化字符串常用基本用法'''
print('---格式化字符串一:%作占位符---')
name='某酷'
age=20
print('我叫%s,今年%d岁' % (name,age)) #固定符号百分号 name和age是一个元组(此时name就会添加到%s位置,age就会添加到%d位置)
print('---格式化字符串二:{}作占位符---')
print('我叫{0},今年{1}岁'.format(name,age))
print('---格式化字符串三:f-string---')
print(f'我叫{name},今年{age}岁') #这种写法前面加个f就代表”格式化字符串“
#除了这三种,还有一些表示宽度和精度怎么使用
print('---表示宽度d---')
print('%d' % 99)
print('%10d' % 99) #在%d中间加上值,表示宽度,10个宽度就代表10个字符的宽度
print('hellohello')
print('---表示精度f---')
print('%f' % 3.1415926)
print('%.3f' % 3.1415926) #如想保留三位小数,在%f中间加上.3即可
print('---同时表示宽度和精度---')
print('%10.3f' % 3.1415926) #一共总宽度为10字符,小数点后三位;在%f中间加上10.3即可
print('---不使用%,使用{}也可以实现---')
print('{0}'.format(3.1415926)) #花括号{}内索引不写也可以,但建议在花括号{}多的情况下要写一下
print('---不使用%,使用{}也实现精度控制---')
print('{0:.3}'.format(3.1415926)) # .3表示的是一共3位数,如果想表示小数要在后面加f
print('{0:.3f}'.format(3.1415926)) #冒号:前面的0代表的是占位符的顺序,也就是format()内的第几个,与索引类似
print('---不使用%,使用{}同时实现宽度和精度的控制---')
print('{0:10.3f}'.format(3.1415926)) #占位符0,宽度10个字符,保留后三位小数
#运行结果
---格式化字符串一:%作占位符---
我叫某酷,今年20岁
---格式化字符串二:{}作占位符---
我叫某酷,今年20岁
---格式化字符串三:f-string---
我叫某酷,今年20岁
---表示宽度d---
99
99
hellohello
---表示精度f---
3.141593
3.142
---同时表示宽度和精度---
3.142
---不使用%,使用{}也可以实现---
3.1415926
---不使用%,使用{}也可以实现---
3.14
3.142
85.字符串的编码与解码
- 编码与解码的万式
-
- 编码:将字符串转换为二进制数据(bytes)
- 解码:将bytes类型的数据转换成字符串类型
解析:例如将A计算机数据传到B计算机中,需要使用字节进行传输,这时候就需要将str字符串转换成二进制数据传送到B计算机,尔后B计算机再将二进制数据转换成字符串显示。
#实例
s='夏天的风'
print('---编码---')
print(s.encode(encoding='GBK')) #在GBK这种编码格式中,一个英文占两个字节(输出结果前面的b'表示bits类型二进制),夏天的风4个字符8个字节
print(s.encode(encoding='utf-8')) #在UTF-8这种编码格式中,一个中文占三个字节
print('---解码---')#byte代表一个二进制数据(字节类型的数据),注意:编码和解码的格式要相同。
byte=s.encode(encoding='GBK') #编码
print(byte.decode(encoding='GBK')) #解码
byte=s.encode(encoding='UTF-8') #编码
print(byte.decode(encoding='UTF-8')) #解码
#运行结果
---编码---
b'\xcf\xc4\xcc\xec\xb5\xc4\xb7\xe7'
b'\xe5\xa4\x8f\xe5\xa4\xa9\xe7\x9a\x84\xe9\xa3\x8e'
---解码---
夏天的风
夏天的风
86.函数的定义与调用
内容导学:1、函数的创建和调用;2、函数的参数传递;3、函数的返回值;4、函数的参数定义;5、变量的作用域;6、递归函数
- 函数的创建和调用
-
- 什么是函数
-
- 函数就是执行特定任和以完成特定功能的一段代码
- 为什么需要函数
-
- 复用代码
- 隐藏实现细节
- 提高可维护性
- 提高可读性便于调试
- 函数的创建
解析: 输出的print函数,输入的input函数,以及可以获取对象类型的type函数,获取对象标识的id函数等等,这些都叫做函数,而这些函数是执行特定任务,每个函数都有自己的独立功能,完成特定功能的一段代码。使用函数可以实现代码的复用。在python中函数的定义使用def,函数的名字是自己起的,但需要遵守函数名的命名规则(字母数字下划线)。
#解析
def calc(a,b): #calc是函数名,a和b是是输入参数起到占位符的作用
c=a+b #a和b的和存到了c当中
return c #结束这个函数同时把a+b的结果给调用数
#实例
#语句执行流程:1.calc函数名,a和b是占位符;2.a+b结果赋给c;3.结束函数同时将结果提交给调用数;4.函数名为calc的两个a和b占位符分别值为10和20,赋值给result(结合上面函数a+b故等于30);5.print输出result
'''函数创建'''
def calc(a,b): #a和b占了两个变量的位置;称为形式参数,简称形参,形参的位置是在含义的定义处
c=a+b
return c #结束这个函数,同时将结果提交调用数
'''函数调用__位置实参'''
result=calc(10,20) #10,20称为实际参数的值,简称实参,实参的位置是函数的调用处
print(result) #运行结果为30
'''关键字实参'''
res=calc(b=10,a=20) #赋值名称相同的形参占位符
print(res) #运行结果为30,虽然结果是一样的,但传递的方式不一样,会根据等号=左侧的名字传;另外等号=左侧变量的名称称为“关键字参数”
88.函数参数传递的内存分析
提示:形式参数和实际参数名称可以不相同
#实例
'''函数定义'''
def fun(arg1,arg2): #定义函数def,函数名fun,arg1作为第一个形参,arg2作为第2个形参
print('arg1',arg1) #输出arg1的值
print('arg2',arg2) #输出arg2的值
arg1=100 #arg1值更改为100
arg2.append(10) #arg2追加了一个10
print('arg1',arg1) #再次输出arg1的值
print('arg2',arg2) #再次输出arg2的值
#因为上述语句函数的执行,没有携带任何结果,所以这里return可以不写,也就是不需要把结果给调用数(如果要写直接return即可)
#return
'''函数调用'''
n1=11
n2=[22,33,44]
print('n1',n1)
print('n2',n2)
fun(n1,n2) #将位置传参,arg1,arg2是函数定义出的形参,n1,n2是函数调用处的实参(实参名称与形参名称可以不一致)
print('n1',n1)
print('n2',n2)
'''总结:在函数调用过程中,进行参数的传递
如果是不可变对象,在函数体的修改不会影响实参的值(例如本案例中对arg1进行修改为100,但最后还是以11输出,因其是不可变对象)
如果是可变对象,在函数体的修改会影响到实参的值(例如本案例中向arg2追加append了一个10,因列表是可变对象)
#运行结果
n1 11
n2 [22, 33, 44]
arg1 11
arg2 [22, 33, 44]
arg1 100
arg2 [22, 33, 44, 10]
n1 11
n2 [22, 33, 44, 10]
89.函数的返回值
#实例
print('---布尔复习---')
print(bool(0)) #false #4/2=2余0,为0是false
print(bool(8)) #true #3/2=1余1,1不为0是true
def fun(num): #函数定义,函数名为fun,传入一个形参num
odd=[] #存奇数
even=[] #存偶数
for i in num: #使用for去遍历num列表
if i%2: #如果i与2的布尔值为true(布尔值为true说明是一个奇数)
odd.append(i) #奇数的列表append追加
else: #否则
even.append(i) #偶数的列表append追加
return odd,even #函数结束时将奇数odd,偶数even的列表返回
'''函数调用'''
lst=[10,29,34,23,44,53,55]
print(fun(lst))
'''函数的返回值
(1)如果函数没有返回值(函数执行完毕后,不需要给调用处提供数据) return可以省略不写
(2)函数的返回值,如果是1个,直接返回类型
(3)函数的返回值,如果是多个,返回的结果为元组
'''
print('---第一种情况---')
def fun1():
print('hello')
# return #此处return可以省略不写,因为没有可返回的值(并且已经print输出,没必要再返回)
fun1()
print('---第二种情况---')
def fun2():
return 'hello'
'''函数调用'''
res=fun2()
print(res)
print('---第三种情况---')
def fun3():
return 'hello','world'
print(fun3()) #运行结果为('hello', 'world') -->将两个返回值放到了一个元组中(由此得出结论,在写函数的时候到底要不要return需要视情况而定)
#运行结果
---布尔复习---
False
True
([29, 23, 53, 55], [10, 34, 44])
---第一种情况---
hello
---第二种情况---
hello
---第三种情况---
('hello', 'world')
90.函数参数定义默认值参数
- 函数定义默认值参数
-
- 函数定义时,给形参设置默认值,只有与默认值不符的时候才需要传递实参
#实例
def fun(a,b=10): #b称为默认值参数
print(a,b)
'''函数调用'''
fun(100) #实参100会传参给a
fun(20,30) #实参20传参给b,实参30传参并替换b形参
print('---单击print跳到源码定义处,过去是\n换行,现在定义为\t制表符使其一行输出---')
print('hello',end='\t')
print('world')
#运行结果
100 10
20 30
---单击print跳到源码定义处,过去是\n换行,现在定义为\t制表符使其一行输出---
hello world
91.函数参数定义个数可变的位置形参_个数可变的关键字形参
- 函数的参数定义
-
- 个数可变的位置参数
- 定义函数时,可能无法事先确定传递的位置实参的个数时,使用可变的位置参数
- 使用*定义个数可变的位置形参
- 结果为一个元组
- 个数可变的关键字形参
-
- 定义函数时,无法事先确定传递的关键字实参的个数时,使用可变的关键字形参
- 使用**定义个数可变的关键字形参
- 结果为一个字典
#实例
print('---*个数可变的位置形参---')
'''函数定义'''
def fun(*args): #定义函数,函数名为fun
print(args)
# print(args[0])
'''函数调用'''
fun(10)
fun(10,30)
fun(30,130,50)
print('---**个数可变的关键字形参---')
'''函数定义'''
def fun1(**args):
print(args)
'''函数调用'''
fun1(a=10)
fun1(a=20,b=30,c=30)
print('hello','world','Python') #按住ctrl单击print进入函数定义查看,可以看到的是*args位置可变参数,所以写一个两个三个都没问题
'''测试:在定义个数可变的位置形参和关键字形参可以定义几个呢?'''
'''def fun1(*args,*a): #两个可变“位置形参”测试
pass
以上代码程序会报错,可变的位置参数,只能是一个
'''
'''def fun2(**args,**args): #两个可变“关键字形参”测试
pass
以上代码也报错,可变的关键字参数,也只能是一个
'''
def fun2(*args1,**args2):
pass
'''def fun3(**args1,*arg2):
pass
在一个函数的定义过程中,既有个数可变的关键字形参,也有个数可变的位置形参,要求个数可变的位置形参,放在个数可变的关键字形参之前
'''
#运行结果
---*个数可变的位置形参---
(10,)
(10, 30)
(30, 130, 50)
---**个数可变的关键字形参---
{'a': 10}
{'a': 20, 'b': 30, 'c': 30}
hello world Python
92.函数的参数总结
#实例
print('---使用**将字典中的每个键值对都转换为关键字实参---')
'''函数定义__形参'''
def fun(a,b,c): #a,b,c在函数的定义处,所以是形式参数
print('a=',a) #分别输出abc的值
print('b=',b)
print('c=',c)
'''函数调用__实参'''
fun(10,20,30) #函数调用时的参数传递,称为位置传参(因为它会把10赋给a,20赋给b,30赋给c)
print('---将列表中的元素作为实参,尔后加*位置传参---')
lst=[11,22,33]
'''函数调用'''
fun(*lst) #在函数调用时,将列表中的每个元素都转换为位置实参传入
print('---关键字实参的函数调用---')
fun(a=100,c=300,b=200) #使用关键字实参函数调用,它就不会像位置传参一样逐个传,而是通过实参关键字与形参占位名匹配继而完成赋值
print('---关键字实参的函数调用__字典---')
dic={'a':111,'b':222,'c':333}
'''函数调用'''
fun(**dic) #因为字典是一个参数,如果向进行关键字传参,想将字典中每个关键字都转为关键字实参传入加两个星**
print('-----------------------------------')
'''函数定义__复习案例'''
def fun(a,b=10): #b是在函数的定义处,所以b是形参,而且进行了赋值,所以b称为默认值形参
print('a=',a) #分别输出ab的值
print('b=',b)
def fun2(*args): #这是个数可变的”位置形参”
print(args)
def fun3(**args2): #这是个数可变的”关键字形参“
print(args2)
'''函数调用__复习案例'''
fun2(10,20,30,40) #它的结果是元组;反正是个数可变的,传多少都可以
fun3(a=11,b=22,c=33,d=44,e=55) #它的结果是字典(键值对的形式);
print('---关键字形参---')
'''函数定义'''
def fun4(a,b,*,c,d): #从*之后的参数,在函数调用时,只能采用关键字参数传递
print('a=',a) #分别输出abcd的值
print('b=',b)
print('c=',c)
print('d=',d)
'''函数调用'''
#fun4(10,20,30,40) #位置实参传递(此处注释掉,因为fun4定义了从*之后的cd只能采用关键字参数传递
fun4(a=10,b=20,c=30,d=40) #关键字实参传递
fun4(10,20,c=30,d=40) #前两个参数采用的是“位置实参传递”,而c,d采用的是“关键字实参传递“
print('---函数定义时的顺序形参问题---')
def fun5(a,b,*,c,d,**args): #此处定义*后的cd只能按照”关键字实参传递“(后面又加了**,这种加了个数可变”关键字形参“是可以的)
pass
def fun6(*args,**args2): #个数可变的关键字形参也是可以的
pass
def fun7(a,b=10,*args,**args2): #b”默认值形参“,个数可变的”位置形参“,个数可变的”关键字形参“,这几种组合都是可以的
pass
#运行结果
---使用**将字典中的每个键值对都转换为关键字实参---
a= 10
b= 20
c= 30
---将列表中的元素作为实参,尔后加*位置传参---
a= 11
b= 22
c= 33
---关键字实参的函数调用---
a= 100
b= 200
c= 300
---关键字实参的函数调用__字典---
a= 111
b= 222
c= 333
-----------------------------------
(10, 20, 30, 40)
{'a': 11, 'b': 22, 'c': 33, 'd': 44, 'e': 55}
---关键字形参---
a= 10
b= 20
c= 30
d= 40
a= 10
b= 20
c= 30
d= 40
---函数定义时的顺序形参问题---
93.变量的作用域
- 变量的作用域
-
- 程序代码能访问该变量的区域
- 根据变量的有效范围可分为
-
- 局部变量
-
- 在函数内定义并使用的变量,只在函数内部有效,局部变量使用global声明,这个变量就会就成全局变量
- 全局变量
-
- 函数体外定义的变量,可作用于函数内外
#实例
print('---局部变量---')
'''函数定义'''
def fun(a,b):
c=a+b #c就称为局部变量,因为c是函数体内进行定义的变量,a,b为函数的形参,作用范围也是函数内部,相当于局部变量
#print(c) #因为a,c超出了起作用的范围(超出了作用域)
#print(a)
print('----------------------------')
name='杨老师' #name的作用范围为函数内部和外部都可以使用,就称为全局变量
print(name)
'''函数定义'''
def fun2():
print(name)
'''函数调用'''
fun2()
print('---使用“global声明”,让局部变量变成全局变量-----')
'''函数定义'''
def fun3():
global age #函数内部定义的变量是局部变量,局部变量使用global声明,这个变量实际上就变成了全局变量
age=20
print(age)
'''函数调用'''
fun3()
print(age)
#运行结果
---局部变量---
----------------------------
杨老师
杨老师
---使用“global声明”,让局部变量变成全局变量-----
20
20
94.递归函数
- 什么是递归函数
-
- 如果在一个函数的函数体内调用了该函数本身,这个函数就称为递归函数
- 递归的组成部分
-
- 递归调用与递归终止条件
- 递归的调用过程
-
- 每递归调用一次函数,都会在栈内存分配一个栈帧,每执行完一次函数,都会释放相应的空间
- 递归的优缺点
-
- 缺点:占用内存多,效率低下
- 优点:思路和代码简单
什么叫阶乘:6的阶乘等于65432*1=720
#实例
'''函数定义'''
def fac(n): #定义函数,函数名为fac,n是要去计算阶乘的数
if n==1: #如果n等于1
return 1 #直接return结束(如果不等于1自己调自己)
else:
return n*fac(n-1) #6*fac 5
print(fac(6))
#运行结果
720
95.斐波那契数列_本章总结
斐波那契数列概念:指的是{1,1,2,3,5}这样的数列,后面数字是前两个数字的和。
#实例
def fib(n):
if n==1:
return 1
elif n==2:
return 1
else:
return fib(n-1)+fib(n-2)
#斐波那契数列第6位上的数字
print(fib(6))
print('------------------------------')
'''输出这个数列的前6位上的数字'''
for i in range(1,7):
print(fib(i))
#运行结果
8
------------------------------
1
1
2
3
5
8
96.Bug的由来
- 1.Bug的由来及分类
- 2.不同异常类型的处理方式
- 3.异常处理机制
- 4.PyCharm的调试模式
97.Bug的常见类型_粗心导致的错误
- Bug的常见类型
-
- 粗心导致的语法错误SyntaxError
粗心导致错误的自查宝典
- 1.漏了末尾的冒号,如if语句,循环语句,else子句等;
- 2.缩进错误,该缩进的没缩进,不该缩进的瞎缩进;
- 3.把英文符号写成中文符号,比如说:引号,冒号,括号;
- 4.字符串拼接的时候,把字符串和数字拼在一起;
- 5.没有定义变量,比如说while的循环条件的变量;
- 6.“=="比较运算符和”="赋值运算符的混用。
#实例
print('---案例1---')
age=input('请输入您的年龄:')
print(type(age))
if int(age)>=18: #18和input数据类型不一致,因此使用Int转换
print('成年人....')
print('---案例2---')
i=0 #给i一个初始值
while i <10:
print(i)
i+=1 #要写i+=1,否则程序是死循环状态
print('---案例3---')
for i in range(3):
uname=input('请输入用户名:')
pwd=input('请输入密码:')
if uname=='admin' and pwd=='admin':
print('登陆成功')
break
else:
print('输入错误')
else:
print('对不起,三次均输入错误')
98.Bug的常见类型_错误点不熟悉导致错误
#知识不熟练导致的错误
#(1)索引越界问题IndexError
1st=[11,22,33,44]
print()1st[4])
#(2)append()方法的使用掌握不熟练1st=[]
lst=append()'A','B','C')
print(lst)
#实例
print('---索引越界问题---')
lst=[11,22,33,44] #列表的正向索引从0开始
print(lst[3]) #输出第4个元素应输入索引号为3
print('---append()方法使用掌握不熟练---')
lst=[]
#lst=append('a','b','c')
lst.append('a')
lst.append('b')
lst.append('c')
print(lst)
#运行结果
---索引越界问题---
44
---append()方法使用掌握不熟练---
['a', 'b', 'c']
99.Bug的常见类型-思路不清导致的部题
- 思路不清导致的问题解决方案
-
- (1)使用print()函数
- (2)使用"#"暂时注释部分代码
题目要求
豆瓣电影Top250排行,使用列表存储电影信息,要求输入名字在屏幕上显示xxx出演了哪部电影。
#实例
lst=[{'rating':[9.7,50],'id':'1292052','type':['犯罪','剧情'],'title':'申克的救赎','actors':['蒂姆','罗宾斯','摩根.弗里曼']},
{'rating':[9.6,50],'id':'1291546','type':['剧情','爱情','同性'],'title':'霸王别姬','actors':['张国荣','张丰毅','巩俐','葛优']},
{'rating':[9.6,50],'id':'1296141','type':['剧情','犯罪','悬疑'],'title':'控方证人','actors':['泰隆.鲍华','玛琳.黛德丽']}]
name=input('请输入你要查询的演员:')
for item in lst: #遍历列表 --> item是一个又一个的字典
act_lst=item['actors']
for actor in act_lst:
if name in actor:
print(name,'出演了',item['title'])
''' 该部分语句是排错时注释掉
for movie in item: #遍历字典,得到movie是一个字典中的key
print(movie)
print('--------------------')
actors=movie['actors']
'''
100.Bug的常见类型-被动掉坑-try-except
- Bug的常见类型
-
- 被动掉坑:程序代码逻辑没有错,只是因为用户错误操作或者一些“例外情况”而导致的程序崩溃
#实例1
a=int(input('请输入第一个整数:')) #input输入函数为str字符串类型,进行计算需要转int类型
b=int(input('请输入第二个整数:'))
result=a/b
print('结果为:',result)
#实例2
'''程序异常处理机制 try except'''
try: #尝试(可能会出现问题)
a=int(input('请输入第一个整数:')) #input输入函数为str字符串类型,进行计算需要转int类型
b=int(input('请输入第二个整数:'))
result=a/b
print('结果为:',result)
except ZeroDivisionError: #释义:不包括ZeroDivisionError,(语法:except 要捕捉的异常:)
print('对不起,除数不允许为0')
print('程序结束')
#运行结果2
请输入第一个整数:20
请输入第二个整数:0
对不起,除数不允许为0
程序结束
#实例3
'''程序异常处理机制 try except多个except结构'''
#用于程序运行时常规except 要捕获的异常不存在 添加多个捕获的内容
try: #尝试(可能会出现问题)
a=int(input('请输入第一个整数:')) #input输入函数为str字符串类型,进行计算需要转int类型
b=int(input('请输入第二个整数:'))
result=a/b
print('结果为:',result)
except ZeroDivisionError: #释义:不包括ZeroDivisionError,(语法:except 要捕捉的异常:)
print('对不起,除数不允许为0')
except ValueError:
print('只能输入数字串')
print('程序结束')
#运行结果3
请输入第一个整数:10
请输入第二个整数:0
对不起,除数不允许为0
程序结束
------------------------------
请输入第一个整数:10w
只能输入数字串
程序结束
101.try-except-else5构与try-except-else-finally结构
#实例
try:
a = int(input('请输入第一个整数:'))
b = int(input('请输入第二个整数:'))
result = a/b
except BaseException as e:
print('出错了',e)
else:
print('计算结果为:',result)
#运行结果
请输入第一个整数:10
请输入第二个整数:a
出错了 invalid literal for int() with base 10: 'a'
#实例
try:
a = int(input('请输入第一个整数:'))
b = int(input('请输入第二个整数:'))
result = a/b
except BaseException as e:
print('出错了',e)
else:
print('计算结果为:',result)
finally:
print('谢谢您的使用')
#运行结果
请输入第一个整数:10
请输入第二个整数:2
计算结果为: 5.0
谢谢您的使用
102.Python中常见的异常类型
'''(1)数学运算异常'''
#print(10/0) #运行结果为ZeroDivisionError
'''(2)序列中没有此索引(index)'''
lst=[11,22,33,44]
#print(lst[4]) #运行结果为IndexError
'''(3)映射中没有这个键'''
dic={'name':'张三','age':20}
#print(dic['gender']) #运行结果为KeyError(字典中根本没有gender这个键)
'''(4)未声明/初始化对象(没有属性)'''
#print(num) #运行结果为NameError(没有定义过num)
'''(5)Python语法错误'''
#int a=20 #运行结果为SyntaxError(在python中,变量是没有数据类型的,而int a是在给变量设置数据类型)
'''(6)传入无效的参数'''
a=int('hello') #运行结果为ValueError(因为hello是字符串,这个字符串是不能转成十进制整数的)
103.8traceback模块的使用
- traceback模块
-
- 使用traceback模块打印异常信息
#实例
#print(10/0)
import traceback
try:
print('------------')
print(1/0)
except:
traceback.print_exc()
#异常信息有可能在后续被存入到文件当中,存放到日志文件里,所以会使用它将异常信息存到文件,称为log日志
#运行结果
------------
Traceback (most recent call last):
File "C:\file\pycharm\temp1\venv\demo103.py", line 10, in <module>
print(1/0)
ZeroDivisionError: division by zero
104.Pycharm的程序调试
- 断点
-
- 程序运行到此处,暂时挂起,停止执行。此时可以详细观察程序的运行情况,方便做出进一步的判断
- 进入调试视图
-
- 进入调试视图的三种方式
-
- (1)单击工具栏上的按钮并
- (2)右键单击编辑区:点击:debug'模块名”
- (3)快捷键:shift+F9
#实例
i=1
while i<=10:
print(i)
i+=1
105.编程的两大思想面向过程面向对象
本阶段内容导学:1.两大编程思想;2.类和对象的创建;3.类对象与类属性;4.类方法与静态方法
106.类与对象
- 类
-
- 类别,分门别类,物以类聚,人类,鸟类,动物类,植物类
- 类是多个类似事物组成的群体的统称。能够帮助我们快速理解和判断事物的性质
- 数据类型
-
- 不同的数据类型属于不同的类
- 使用内置函数查看数据类型
- 对象
-
- 100、99、520都是int类之下包含的相似的不同个例,这个个例专业数语称为实例或对象
Python中一切皆对象
107定义Python中的类
#实例
'''
class Student: #类定义,类名Student(类名规则:由一个或多个单词组成,每个单词首字母大写,其余小写;其实不遵循这个规则也可以,但显得不够专业,因为这个规则是程序员行业默认规则)
pass #类中具体写什么还没想好,可以pass进行占位以确保程序不报错
#Python中一切皆对象,上述创建的类Student是对象吗?对象由三部分组成:ID、类型、值
print(id(Student)) #运行结果2722640457600 -->证明有ID内存空间
print(type(Student)) #运行结果<class 'type'> -->证明有数据类型
print(Student) #<class '__main__.Student'> -->证明有value值
'''
class Student:
#类属性
native_pace='南京' #直接写在类李的变量,称为类属性
def __init__(self,name,age): #self也是缺省的,后面而且可以继续写其它的
self.name=name #self.name称为实体属性,进行了一个赋值的操作,将局部变量的name的值赋给实体属性 -->这是赋值操作
self.age=age
#实例方法
def eat(self): #这个类定义发现与函数定义def有几分相似,但是不一样的是它多了一个self,这个self是缺省的,它一定是存在的(当然这个self可以换成别的单词,但程序员行业人员习惯使用self)
print('学生在吃饭...')
#静态方法
@staticmethod
def method(): #静态方法什么都不写
print('使用了statticmethod进行修饰,所以是静态方法')
#类方法
@classmethod
def cm(cls): #这种类方法cm()内的cls也是缺省的,一定要有的会自动加,是class类的意思
print('这是“类方法”,因为使用了classmethod进行修饰')
#提示:在类之外定义的称为函数,在类之内定义的定义的称为方法
'''下面定义的drink定义的称为函数,因其是在类之外定义'''
def drink():
print('喝水')
#运行结果
Process finished with exit code 0
108.对象的创建
class Student: #类定义,类名Student(类名规则:由一个或多个单词组成,每个单词首字母大写,其余小写;(也就是说Student就是”类对象“)
#类属性
native_pace='南京' #直接写在类李的变量,称为类属性
def __init__(self,name,age): #self也是缺省的,后面而且可以继续写其它的
self.name=name #self.name称为实体属性,进行了一个赋值的操作,将局部变量的name的值赋给实体属性 -->这是赋值操作
self.age=age
#实例方法
def eat(self): #这个类定义发现与函数定义def有几分相似,但是不一样的是它多了一个self,这个self是缺省的,它一定是存在的(当然这个self可以换成别的单词,但程序员行业人员习惯使用self)
print('学生在吃饭...')
#静态方法
@staticmethod
def method(): #静态方法什么都不写
print('使用了statticmethod进行修饰,所以是静态方法')
#类方法
@classmethod
def cm(cls): #这种类方法cm()内的cls也是缺省的,一定要有的会自动加,是class类的意思
print('这是“类方法”,因为使用了classmethod进行修饰')
#提示:在类之外定义的称为函数,在类之内定义的定义的称为方法
'''下面定义的drink定义的称为函数,因其是在类之外定义'''
def drink():
print('喝水')
#实例(108.对象的创建)
#创建Student类的对象(Student就是类对象,根据”类对象“创建出来的就是”实例对象“)
stu1=Student('张三',20) #按住ctrl单击Student跳转到上面语句def __init__(self,name,age),init方法有两个参数那就写张三20;这就已经创建了Student类对象
print(id(stu1)) #验证下是id、类型、值;
print(type(stu1)) #注意:类对象“id内存地址2067915988752”其实是和类值"<__main__.Student object at 0x000001E17965DF10>"完全一致的
print(stu1) #注意:类对象id内存地址是十进制,而类对象值其实就是id的十六进制(可以打开计算器验证一下)
print('----上面语句是Student类型的对象的地址,下面语句是Student”类“的地址---------------')
print(id(Student))
print(type(Student))
print(Student)
#运行结果
2715757961072
<class '__main__.Student'>
<__main__.Student object at 0x000002784FC9DF70>
----上面语句是Student类型的对象的地址,下面语句是Student”类“的地址---------------
2715756586896
<class 'type'>
<class '__main__.Student'>
当创建完成这个对象之后就可以就可以使用这个类的实例属性以及这个类的相关方法
class Student: #类定义,类名Student(类名规则:由一个或多个单词组成,每个单词首字母大写,其余小写;(也就是说Student就是”类对象“)
#类属性
native_pace='南京' #直接写在类李的变量,称为类属性
def __init__(self,name,age): #self也是缺省的,后面而且可以继续写其它的
self.name=name #self.name称为实体属性,进行了一个赋值的操作,将局部变量的name的值赋给实体属性 -->这是赋值操作
self.age=age
#实例方法
def eat(self): #这个类定义发现与函数定义def有几分相似,但是不一样的是它多了一个self,这个self是缺省的,它一定是存在的(当然这个self可以换成别的单词,但程序员行业人员习惯使用self)
print('学生在吃饭...')
#静态方法
@staticmethod
def method(): #静态方法什么都不写
print('使用了statticmethod进行修饰,所以是静态方法')
#类方法
@classmethod
def cm(cls): #这种类方法cm()内的cls也是缺省的,一定要有的会自动加,是class类的意思
print('这是“类方法”,因为使用了classmethod进行修饰')
#提示:在类之外定义的称为函数,在类之内定义的定义的称为方法
'''下面定义的drink定义的称为函数,因其是在类之外定义'''
def drink():
print('喝水')
#实例(108.对象的创建)
#创建Student类的对象(Student就是类对象,根据”类对象“创建出来的就是”实例对象“)
stu1=Student('张三',20) #现在创建好Student类对象了,就可义使用它的eat实例方法
stu1.eat() #当执行输出eat()时,就会执行上面的def eat(self): print('学生在吃饭...')的方法体 -->对象名.方法名
print(stu1.name) #它的实例属性name和age都可以进行输出
print(stu1.age)
#提示:所以类的实例对象再去调用上面的”方法”和“属性”的时候,使用点"."就可以了,就可以进行这样的调用
print('-----------另一种调用方法--------------')
Student.eat(stu1) #传过来一个对象就可以了(Student.eat(stu1)和stu1.eat()代码功能相同,都是调用Student中的eat方法) -->类名.方法名(类的对象)
#解析:那为什么Student.eat(stu1) 有参数,而stu1.eat()没有参数呢?因为eat(self):方法中写了self,self意思就是自身,要求传入一个Student对象,所以Stu1不是Student对象吗?当然就可以传入
'''两种写法:(1)对象名.方法名
(2)类名.方法名(类的对象) -->实际上就是方法定义处的self
'''
#运行结果
学生在吃饭...
张三
20
-----------另一种调用方法--------------
学生在吃饭...
109.类属性_类方法_静态方法的使用方式
- 类属性:类中方法外的变量称为类属性,被该类的所有对象所共享
- 类方法:使用@classmethod修饰的方法,使用类名直接访问的方法
- 静态方法:使用@staticmethod修饰的主法,使用类名直接访问的方法