Python版本3.4.3
看清版本哦
官网链接
https://www.python.org/downloads/release/python-343/
下载之后会有这两个软件哦
好了进入正题
while循环
bingo = '天钧好帅'
name = input("请输入天钧最想听的一句话")
while True:
if name == bingo:
break
name = input("请重新输入天钧最想听的一句话")
print("卧槽,牛逼啊小伙子,猜对了")
笔记;因为Python不像C语言那样的强结构语言,所以我学完C就开始学Python,脑袋嗡嗡的,不过还好,它的赋值很不一般,像C语言第一条应该是先申请一个变量然后在接收赋值,但Python不一样,直接因为赋值是什么类型就变成什么类型的变量。
什么是while循环
大概是这个样子的[注意消失多年的灵魂画手上线了]
这不跟C语言一样的吗,没错就是一样的哈哈哈,指的是原理,别把C语言的格式写进Python代码,下场很惨的。
while结构如下
while 循环条件:
循环体
注意到一个现象没有,它没有大大小小的括号显得代码很干练,那它怎么识别条件语句与循环体的呢,答案是空格,这里的空格是严格要求的,建议同体代码使用4个空格,是一个tab建,千万不要滥用空格,不然报错了都不好排查
for循环
for 目标 in 表达式:
循环体
这个for循环跟C语言的不同,for是指向目标,in指向表达式后面以英文状态下的":"结尾然后才是循环体
注意变量与值之间应该有英文状态下的空格因为美观(这个是我书上记得笔记,现在一看有点绝望)
munber = [1,23,4]
for i in munber:
print(i,end=" ")
运行结果
输出了空格在每个数之间
range()
这个是 for 的好伙伴哦
for i in range(1,33,4):
print(i)
那么这个函数是什么意思呢,书上没过多解释,我的理解是就像枪一样,这个函数是枪的弹夹,去申请就多少发子弹,看一下简单的例子
for i in range(5)
print(i)
就这样像子弹一样发射出去,大家有没有发现一个有趣的事情,为什么我填的是5最后到4就停止发射了呢,这是因为range是从0开始数的一共5个数,所以到4就停止了。
那我不愿意怎么办,非要从1开始数,咱也有办法。
for i in range(1,33):
print(i)
熟悉吗,没错就是上面的代码。可是大家找到不同之处了吗
哇!好长的图啊,哈哈哈,看见了吗,range开始从1开始数了,因为咱们制定了“如何添加这个子弹,一共多少”
那文章第一个range的代码是什么呢
for i in range(1,33,4):
print(i)
这个啊,叫做步长(我这么叫的,不知道其他人怎么叫步幅吗)
看一下运行后的结果大家就明白了
每个结果等差为4哦
break语句
break语句执行到break时跳出
这里的break和C语言一样是跳出循环如下
i = 0
while i < 10:
if (i == 8):
print("运行到8就跳出了哦")
break
print(i)
i = i + 1
运行后
发现程序运行到if语句后就跳出循环了,明明还有两个没有参与循环呢
continue语句在循环开始之前要测试一次循环条件如果把上面的代码中的break替换成continue的话,那么会变成
列表
列表
创建列表
这一章我在学习时,感觉很像C语言的数组,感觉很奇妙啊进入笔记模式
>>> number = [1,2,3,4,5,6,7]
>>> number
[1, 2, 3, 4, 5, 6, 7]
append()
append()的作用是向列表的最后一位添加元素
如;
>>> number = [1,2,3,4,5,6,7]
>>> number
[1, 2, 3, 4, 5, 6, 7]
>>> number.append(0)
>>> number
[1, 2, 3, 4, 5, 6, 7, 0]
注;看见连接符了吗,就是那个“.”,我在第一章里提到过哦,这里详解一下,可以理解为{范围}append()这个方法是属于number的列表对象的。
细心地同学可能会想到如果我加入两个元素,append还可以使用吗,看程序给的回答。
>>> number.append(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: append() takes exactly one argument (2 given)
>>>
妈呀,报错了,这时候应该下一位选手上场了,咱没有那金刚钻,不揽瓷器活,就这样extend上场了
extend()
extend 的作用是向列表后添加多个元素
如下
>>> number.extend([1,2])
>>> number
[1, 2, 3, 4, 5, 6, 7, 0, 1, 2]
注;发现不同之处了吗,为什么append里没有中括号,而extend里面有呢? 解答;这里因为列表里添加多个元素,可以看做以原有的列表,去在申请一个列表进行拼接
如下
number = [1,2,3,4]
extend的列表 = [5,6,7,8]
拼接给number
number = [1,2,3,4,5,6,7,8]
那么想在任意位置插入元素怎么办。
insert上场
insert()
insert的作用是在指定的位置插入元素
如;
>>> number
[1, 2, 3, 4, 5, 6, 7, 0, 1, 2]
>>> number.insert(2,3)
>>> number
[1, 2, 3, 3, 4, 5, 6, 7, 0, 1, 2]
insert( ,)第一个参数代表着元素的位置,第二个参数代表着要插入的元素(突然有点害羞,我想我在开车),前面的文章说过Python的顺序索引是从0开始数的,这里不水啊。
那么我想查看列表里的某个元素怎么办
答;好问题,天钧不愧是玉树临风,风流倜傥........
咳咳,想查看列表里的某个元素,那好办直接索引
看例子
>>> name = ['天钧','老五','乌木','老三']
>>> name
['天钧', '老五', '乌木', '老三']
>>> name[0]
'天钧'
>>> name[2]
'乌木'
懂了吗(好想开大货车,带着一腔梦想去,喂牧羊犬)
问;如何从列表里删除元素呢
陷入沉思,从列表里删除元素,我的认知里有三种方法,分别为
pop()
remove()
del
来咱们先介绍第一位选手pop()。
pop()
pop作用是默认弹出列表里的最后一位元素
如下;
>>> name.pop()
'老三'
>>> name
['天钧', '老五', '乌木']
有趣的是,它在弹出最后一位 元素时,还会找你确认一下,但是只是让你了解它刚刚把谁弹出去了。[可怜了我们工作室的老三]
那想把老五也弹出去怎么办
>>> name
['天钧', '老五', '乌木']
>>> name.pop(1)
'老五'
>>> name
['天钧', '乌木']
pop的人生格言:pop里带索引,我不爽谁我踢谁
下一位选手是del大家对它很熟悉吧
del
del的作用,直接删除列表
这是我见过最狂的,那刚刚抛弃的number试试。
>>> del number
>>> number
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'number' is not defined
注意,它不是个列表方法,是个语句没有小点点。
好了,number滚蛋了[有点爽]
这时如果想用del删除指定元素,可不可以呢?
答案是完全可以
>>> del name[1]
>>> name
['天钧']
你能找出少了哪位同学吗。
下一位是谁呢,前面我已经剧透过了,remove()选手闪亮登场。
remove
作用:删除已知的元素,不能删除指定某个位置的元素
如,先向name里添加点元素,陪陪我。
>>> name.extend(['wocao',666,'好强'])
>>> name
['天钧', 'wocao', 666, '好强']
>>> name.remove(666)
>>> name
['天钧', 'wocao', '好强']
注意,数字可以不用加英文状态下的引号,刚刚犯了个小错误。
列表分片
开始与结束
怎么一次获得两个元素呢?
答;切它,那怎么切呢,如下
>>> name
['天钧', 'wocao', '好强']
>>> name[1:2]
['wocao']
>>> name[0:2]
['天钧', 'wocao']
找不同喽,细心的同学发现,第一次的为什么只返回了['wocao']呢,第二次为什么返回了两个值。
那就先要看看列表切片的方式了name[第一个参数:第二个参数]中间以英文状态下的冒号分割,以第一个参数为起点,以第二个元素为重点但是不包含第二个参数
如果没有开始位置怎么办
>>> name[0:2]
['天钧', 'wocao']
>>> name[:2]
['天钧', 'wocao']
答;没有的话,Python只能从0开始给你数了,看来Python为了你操碎了心。
不过,我还能玩。
>>> name[:2]
['天钧', 'wocao']
>>> name[1:]
['wocao', '好强']
>>> name[:]
['天钧', 'wocao', '好强']
>>> name
['天钧', 'wocao', '好强']
发现什么了,不妨笔记上记录自己的心得哦。
切片的进阶玩法
玩就要玩个痛快,进阶一下,玩斯它ψ(*`ー´)ψ
切片只能有两个参数吗,不不不[PS:第三个参数:“乃个孙子叫我”],他有第三个参数哦,阿秋~~(ps;你们谁看见谁骂我了),看例子
>>> number = [1,2,3,4,5,6,7,8,9] ps;我又回来了
>>> number
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> number[0:2:2]
[1]
>>> number[0:7:2]
[1, 3, 5, 7]
第三个参数有个名字叫做步长,前面提到,第一个参数是起步,第二个参数是结尾,第三个参数就是步长,步长是什么,就是等差的一个方法,从1开始的话,一共10个数,步长是2的话,那么是什么样子的呢?
>>> number
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> number.append(0)
>>> number[0:10:2]
[1, 3, 5, 7, 9]
这样的!!!!
你懂了吗
常用操作符在列表里的姿势
>>> list1 = [123]
>>> list2 = [456]
>>> list1 < list2
True
>>> list1 > list2
False
有人会疑问了,Python是怎么去比较两个列表的呢,答案是从第一个元素开始,比较,谁大谁赢,如下
>>> list1.append(456)
>>> list2.append(123)
>>> list1
[123, 456]
>>> list2
[456, 123]
>>> list1>list2
False
>>> list1 < list2
True
那数字这样玩那字符串怎么玩啊
马上继续
字符串玩法介绍
拼接玩法
>>> char1 = ['wocao']
>>> scring = ['666']
>>> char1 + scring
['wocao', '666']
那让它复读机呢,*它
>>> scring * 3
['666', '666', '666']
如何查看元素是否在列表里呢
答案是,看下面,in和not in上场了
>>> name
['天钧', 'wocao', '好强']
>>> 'wocao'in name
True
>>> 'wocao' not in name
False
index()
查询参数在列表的位置
看例子
>>> name.index('wocao')
1
count()
查询同一元素在列表里出现的次数
>>> number
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> number.extend([1,2,1,1,1,2])
>>> number
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1, 1, 1, 2]
>>> number.count(1)
5
reverse()
反向排列
>>> number
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1, 1, 1, 2]
>>> number.reverse()
>>> number
[2, 1, 1, 1, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
sort()
排序
题外话:说实话,有点累了,主要是饿了,快8点了,写完文章,还要自己去做饭,很烦,所以文章到这里未免有点枯燥,(对不起,超小声bb)
看例子!!!
>>> number
[2, 1, 1, 1, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> number.sort()
>>> number
[0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9]
>>> number.reverse()
>>> number
[9, 8, 7, 6, 5, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 0]
天钧在这里还给倒过来了,是不是很有意思呢?
切片的补充
看例子
>>> apple = [1,2,3,4,5,6]
>>> banana = apple[:]
>>> banana
[1, 2, 3, 4, 5, 6]
>>> monkey = apple
>>> monkey
[1, 2, 3, 4, 5, 6]
看似都一样的对吧,其实不一样。
>>> apple.reverse()
>>> apple
[6, 5, 4, 3, 2, 1]
>>> banana
[1, 2, 3, 4, 5, 6]
>>> monkey
[6, 5, 4, 3, 2, 1]
monkey居然随着apple的变化而变化,实力捕捉墙头草。其实这个解释起来就是,banana拿到的是apple的值,而monkey拿到的是apple,发现不同了吗?
《元组》
什么是元组,元组的理解成一个不可进行更改的列表,换个理解方式,如列表申请的元素,可以看见并进行修改等一定的高级操作,但是元组不一样它更像申请了一张可视的图片,可以观测元素,但不能对其更改。
元组的申请
>>> tuple = (1,2,3,4,5,6,7) #元组
>>> number = [1,2,3,4,5,6,7] #列表
>>> tuple
(1, 2, 3, 4, 5, 6, 7)
>>> number
[1, 2, 3, 4, 5, 6, 7]
发现不同的地方了吗,没错,就是元组的申请方式与列表的申请方式不一样,主要在包含元素的操作符上,在大部分的申请方式中区别元组与列表的方式,只要是看:创建元组用的是小括号,创建列表用的是中括号。
访问元组
访问元组的方式与列表是一样的
如
>>> tuple
(1, 2, 3, 4, 5, 6, 7)
>>> tuple[1]
2
也可以用切片的方式哦(切它!!!)
>>> tuple[:]
(1, 2, 3, 4, 5, 6, 7)
>>> tuple[1:5]
(2, 3, 4, 5)
>>> tuple[1:]
(2, 3, 4, 5, 6, 7)
现在天均开始自己打自己脸了,请问元组的标志性符号是什么(提示;列表是[中括号]哦)
一位长得挺帅的同学回答到;“小括号”,没错我刚开始也是这么理解的,但是这个是错误的,具体哪里错了,看例子。
type()方法
type方法返回参数类型
这里天均为什么又提到了type方法呢?
不要说话看例子
>>> apple = (1)
>>> apple
1
>>> type(apple)
<class 'int'>
>>> banana = (1,2,3,3)
>>> banana
(1, 2, 3, 3)
>>> type(banana)
<class 'tuple'>
不知道天均的土味英语大家感觉如何
有同学疑惑了,这元组的类型还是动态的,带动态变化的啊,这个问题看下面不带小括号会怎样
>>> apple = 1,2,3,4
>>> apple
(1, 2, 3, 4)
>>> type(apple)
<class 'tuple'>
>>> banana = (1,2,3,4,5)
>>> banana
(1, 2, 3, 4, 5)
>>> type(banana)
<class 'tuple'>
是不是很夸张,那元组的标志性符号是什么,不是小括号,难道是逗号吗,没错。(其实当时我也是惊讶的)举个例子,看一下逗号在元组里的关键性
>>> 8 * (2)
16
>>> 8 * (2,)
(2, 2, 2, 2, 2, 2, 2, 2)
更新与删除元组
前面提到元组就像一张图片,可视不可更改,怎么又开始说更新了呢?
看例子
>>> temp = temp[:3] + ('傻子',) + temp[3:]
>>> temp
('天钧', '老五', '老留', '傻子', '乌木')
注意重点来了,前面说逗号是元组的必需品,注意傻子后面还有个逗号,如果不加Python就把它当成字符串而不是元组,只有元组才能与元组进行拼接
看一下错误信息
>>> temp = temp[:3] + ('傻子') + temp[3:]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate tuple (not "str") to tuple
删除
拼接法
跟上面的同理,拼接然后再赋值,直接看例子
>>> temp
('天钧', '老五', '老留', '傻子', '乌木')
>>> temp = temp[:2] + temp[3:]
>>> temp
('天钧', '老五', '傻子', '乌木')
你能找到少了谁吗?不妨做一下笔记,在实验一下,毕竟实验才是巩固知识是的最好方式
在Python3中,所有的字符串都是Unicode字符串。
笔记如下;
字符串的创建如下
>>> char = ("contont")
>>> str1 = ('1234567')
>>> char
'contont'
>>> str1
'1234567
重点:创建字符可以使用单引号与双引号。
修改字符串
这里又要运用咱们熟悉的(切他)切片了,废话不多说,直接看例子
>>> str1
'1234567'
>>> str1[:3] + ("wo") + str1[3:]
'123wo4567'
>>> str1
'1234567'
发现没有变化,如果看过元组那一章的小伙伴们,或者有底子的,可能发现了问题所在,没错,少了从新赋予,在这里温习一下如下
>>> str1 = str1[:3] + ("wo") + str1[3:]
>>> str1
'123wo4567'
重点来了
格式化
format()方法
接受位置与关键词参数两者均传递replacement字段
replacement在字符串的有大括号表示
听不懂?没关系,看例子
>>> "{0} like {1}.{2}".format("I","variey","com")
'I like variey.com'
看见大括号了没,里面有数字呢,在我的理解里,数字相当于format里依次参数的坐标,可以指定的放进{0},{1},{2}里,所以format里的三个参数叫做位置参数,那什么是关键词参数呢?
关键词参数例子如下
>>> "{a} like {b}.{c}".format(a = "I",b = "variey",c = "com")
'I like variey.com'
>>> "{0} like {1}.{2}".format("I","variey","com")
'I like variey.com'
发现不同之处了吗,所谓的{}里的相当于位置参数的坐标,那样才会更好的找到属于自己的位置,不过注意哦,这两个也是有区别的,关键词参数更加准确的找到自己的,坐标了呢(就像每个房子上的编号一样,在format()它会将参数中等值的字符串替换进去)如果混合使用会怎么办。
>>> "{a} like {b}.{0}".format(a = "I",b = "variey","com")
File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
报错了,什么意思呢,拜托有道云了
翻译
回溯(最近一次调用last):
>>> "{a} like {b}.{0}"。格式(a = "I",b = "variey","com")
文件“<stdin>”,第1行
SyntaxError:关键字arg之后的非关键字arg
这是在说位置参数必须在关键词参数前面,如下
>>> "{0} like {a}.{b}".format("i",a = "I",b = "variey")
'i like I.variey'
格式化操作符
什么是格式化操作符呢?看一个符号 % 没错就是它,它在左右均为数字时为求余数,但它出现在字符中,表示的就是格式化操作符了,如下是格式化操作符的符号以及含义。
格式化操作符的符号以及含义。
符号 | 含义 |
---|---|
%c | 格式化字符及ASCII |
%s | 格式化字符串 |
%d | 格式化整数 |
%o | 格式化无符号八进制数 |
%x | 格式化无符号十六进制数 |
---|---|
%X | 格式化无符号十六进制数(大写) |
%f | 格式化浮点数字,可指定小数点后的精度 |
%e | 用科学计数法格式化浮点数 |
%E | 用科学计数法格式化浮点数(大写) |
%g | 根据值的大小决定使用%f或%E |
---|---|
%G | 根据值的大小决定使用%f或%E(大写) |
例子如下
>>> '%c' % 97
'a'
>>> '%c %c %c %c %c %c %c' % (118 ,97 ,114 ,105 ,101 ,116 ,121)
'v a r i e t y'
ASCII在线转换;https://www.mokuge.com/tool/asciito16/
格式化操作符的辅助命令
m.n | m是最小总宽度,n是小数点后的位数 |
---|---|
- | 结果左对齐 |
+ | 在证书面前显示加号(+) |
# | 在八进制面前显示‘0o’,在十六进制数面前显示‘0x’,'0X' |
0 | 显示的数字前面填充‘0’代替空格 |
Python的转义字符及含义
\' | 单引号 |
---|---|
\" | 双引号 |
\a | 发出系统响铃 |
\b | 退格符 |
\n | 换行符 |
\t | 横向制表符(TAB) |
---|---|
\v | 纵向制表符 |
\r | 回车符 |
\f | 换页符 |
\o | 八进制数代表字符 |
\x | 十六进制数代表字符 |
---|---|
\0 | 代表一个空字符 |
\\ | 反斜杠 |
整理的我脑袋嗡嗡的
序列
在讲序列之前,咱们先回顾一下知识点
元组,列表与字符串的共同点
list()方法用于把一个可迭代对象转换为列表(迭代是什么?所谓的迭代就是重复反馈过程的活动)看例子
>>> a = list((1,2,3,4,5,6))
>>> a
[1, 2, 3, 4, 5, 6]
>>> b = list('shazi')
>>> b
['s', 'h', 'a', 'z', 'i']
实现过程;
新建一个列表,然后循环通过索引迭代参数的每一个元素,并加入列表迭代完毕后,返回列表
那么列表有了,还需要什么,元组,如下
tuple()
用于把一个可迭代对象转换为元组
如下
>>> b = list('shazi')
>>> b
['s', 'h', 'a', 'z', 'i']
>>> c = tuple("wocao")
>>> c
('w', 'o', 'c', 'a', 'o')
str()
用于把一个obj对象转换为字符串
如下
>>> a = str(1)
>>> tuple(a)
('1',)
>>> type(a)
<class 'str'>
len(sub) len方法用于返回sub长度
>>> number = [1,2,3,4,5,6,7,8,9]
>>> len(number)
9
>>> list1 = "this is python"
>>> len(list1)
14
max
max方法用于返回序列或者参数中的最大值
>>> list2 = [1,2,3,4,45,6,756,22]
>>> max(list2)
756
>>> list3 = "wocao"
>>> max(list3)
'w'
不妨想一想,max怎么找到字符串里的最大值的
后台回复关键词,有惊喜
min
很熟悉吧,跟上面的max是不是有点像呢,那它是干什么的呢,找出最小的值,如下
>>> min(list3)
'a'
>>> min(list2)
1
>>> list2
[1, 2, 3, 4, 45, 6, 756, 22]
>>> list3
'wocao'
sum()
返回总和
>>> list2
[1, 2, 3, 4, 45, 6, 756, 22]
>>> sum(list2)
839
sorted排序
看到这个有没有想起天均在前面笔记提到过的sort呢
看看有什么区别吧
>>> list2 = [213,4,6,7,323,412,12]
>>> sorted(list2)
[4, 6, 7, 12, 213, 323, 412]
>>> list2
[213, 4, 6, 7, 323, 412, 12]
>>> list2.sort()
>>> list2
[4, 6, 7, 12, 213, 323, 412]
发现不同了吗,(天均小声bb,ascii,ASCII,知道我在说什么吗)
reversed
这个跟谁很像呢,不放在天均前面的文章找一找哦
作用是返回逆向迭代的序列值,看不懂没关系看例子
>>> for each in reversed(list1):
print(each,end = ',')
434,22,-22,332,5,4,4,23,1,
没有看错,他返回的是不是个列表而是个迭代器对象
enumerate
enumerate用于生成二元组(二元组就是元素为2的元组)构成一个迭代对象,每个二元组是由可迭代参数的索引号及其对应的元素组成的,看例子
>>> str1 = "variety"
>>> for i in enumerate(str1):
... print(i)
...
(0, 'v')
(1, 'a')
(2, 'r')
(3, 'i')
(4, 'e')
(5, 't')
(6, 'y')
zip
用于返回有个个可迭代的参数共同组成的元组
>>> list2 = [1,2,33,4,5,65]
>>> for i in zip(str1,list2):
... print(i)
...
('v', 1)
('a', 2)
('r', 33)
('i', 4)
('e', 5)
('t', 65)
>>> tuple1 = [1,2,3,4,5,6]
>>> for i in zip(str1,list2,tuple1):
... print(i)
...
('v', 1, 1)
('a', 2, 2)
('r', 33, 3)
('i', 4, 4)
('e', 5, 5)
('t', 65, 6)
函数
函数是什么,随着学习的深入,编写的代码越来越复杂,所以要找到一个方法去吧,重复性的操作变得更加简单高效起来,把一些重复性的的代码块封装成BIF,方便反复调用,减少人力的资源浪费,更加的节约了时间。
函数的创建和调用函数
上面说到函数就是把一次次重复的代码封装成一个BIF这样会更好的利用,那怎么去封装的呢?
看例子
>>> def myfirstfuncion():
... print("第一个函数")
... print("天钧成年了")
... print("可以负法律责任了")
>>> myfirstfuncion()
第一个函数
天钧成年了
可以负法律责任了
函数的调用和运行机制,当函数myfistfuncion()发生调用操作时,Python会自动找到>>> def myfirstfuncion():然后依次执行该函数所包含的代码块部分(冒号后面的部分内容)一句调用就实现了函数的所有内容,是不是很方便呢?不用一行行去重复性的劳动了。
打印三次怎么办呢,看见调用函数时后面跟的小括号了吗。
看例子
>>> for i in range(3):
... myfirstfuncion()
...
第一个函数
天钧成年了
可以负法律责任了
第一个函数
天钧成年了
可以负法律责任了
第一个函数
天钧成年了
可以负法律责任了
还记得range()吗?前面文章说的for的弹夹哦,想有多少子弹,就有多少子弹。
[小声bb,天钧把公众号底下的菜单给优化了,可以找到专门的Python笔记了不用再去历史文章一章章找去了,后面的owasp tap 10 也方便大家查阅笔记,也请大家多多转发文章,您一直以来的支持,才是我们坚持下去的动力]
函数的参数
函数的参数,关于上面函数大家注意到了,函数后面跟着一个空的小括号,这是为什么呢?
聪明的小伙伴们,可能在上面我使用for循环,反应过来函数不过是对相同的代码进行,打包这样和循环的本质没有什么不同的,所以为了函数能够在每次调用实现不同的风格,才加入了函数的概念。
>>> def myfistfunction(name):
... print(name + "真的很帅")
...
>>> myfistfunction("variety")
variety真的很帅
>>> myfistfunction("天钧")
天钧真的很帅
>>> myfistfunction("老五")
老五真的很帅
>>> myfistfunction("奥巴马")
奥巴马真的很帅
一个参数怎么够咱们玩的,不不不这远远不够,为此还能有两个参数去玩。如下
>>> def add(num1,num2):
... print(num1 + num2)
...
>>> add(1,45)
46
这里咱观察细致一些,如有了两个参数,我要做的是加法运算,那么输出是不用加入双引号的,在调用时add后面应跟两个数,用逗号隔开,下面是错误的例子。
>>> def add(num1,num2):
... print("num1 + num2")
...
>>> add(12,34)
num1 + num2
没有输出应有的效果,因为print里面的是字符串类型了,应该输出字符串。
函数的返回值
返回值是什么,学过C语言的同学立马想到了RETURN这个函数了吧,它在两种语言里代表的含义是一样的,来看看Python里的return同学吧!
>>> def cdd(num1,num2):
... return num1 + num2
...
>>> cdd(12,34)
46
注;因为公众号文章面对的是小白,我尽量用大白话出文章,来照顾小白的学习,更好的去入门Python,才是我们要做的,安全圈很小,天钧应该尽自己所能,去帮助其他人。来了解这个行业,入门这个行业,所以一些学习过的大佬们,可以在后台指出天钧文章里的错误,为了安全圈的繁荣,天钧愿与诸君共同进步。
灵活强大的参数
形参与实参
参数从调用的角度来看是分为形参与实参的
例子
>>> def myfistfunction(name):
... print(name + "wocao")
...
>>> myfirstfunction("天钧")
>>> myfistfunction("天钧")
天钧wocao
def myfistfunction(name):里的name就是形参,代表着一个位置一个变量名,而调用的myfirstfunction("天钧")就是实参了,很容易理解对不对,因为它是个具体的内容,是赋值到变量名中的值。
函数文档与关键词参数
函数文档
函数文档是什么,就是给函数写文档,一个团队去写代码时,一般都是很多人一起来的,不知道大家听过一个笑话没有,老板对程序员说,给你6个人,这个项目多久能完成,程序员说10天,那给你10个人呢?程序员说要20天,为什么人越多时间越长呢?,因为人与人写代码的规范是不同的,写函数文档的理由就是,不管是谁阅读你的代码都能看得懂,这是个好习惯。
>>> def myfistfunction(name):
... """输入名字打出很帅"""
... print(name + "真的很帅")
...
>>> myfistfunction("老五")
老五真的很帅
我们看到写在代码开头的三引号里不会打印出来,但会被储存起来,它的功能和注释是一样的。怎么去获取呢?
__doc__
获取函数上场(doc两边的是两个英文状态下的下划线)
>>> myfistfunction.__doc__
'输入名字打出很帅'
>>>
关键词参数
还记得format()函数吗?
关键词函数跟它原理很像如下
>>> def add(num1,num2):
... print(num1 + num2)
...
>>> add(1,45)
46
这样的是不是很容易搞混,num1与num2呢?
但是关键词函数很直接,如下
>>> def add(num1,num2):
... print(num1 + num2)
...
>>> add(num1 = 45 ,num2 = 23)
68
>>>
后台回复cxk,查看小彩蛋
默认参数
什么是默认参数,默认参数是在定义时赋予了默认值得的参数
如下
>>> def add(num1 = "天钧",num2 = "love 老五"):
... print(num1 + num2)
... print("py交易")
...
>>> add()
天钧love 老五
py交易
>>>
收集参数
可变形参
>>> def tese(* params):
... print("里面有%d个参数" % len(params))
... print("第二个参数是:",params[1])
...
>>> tese('C','C','S','D','E','W')
里面有6个参数
第二个参数是: C
其实也不难理解,可以当做参数里的元组,星号(*)既可以把和参数打包也可以解包,怎么操作如下。
>>> def tese(* params):
... print("里面有%d个参数" % len(params))
... print("第二个参数是:",params[1])
...
>>> tese('C','C','S','D','E','W')
里面有6个参数
第二个参数是: C
>>> a = [1,2,3,4,4,5]
>>> tese(a)
里面有1个参数
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in tese
IndexError: tuple index out of range
这样为什么出错呢,大家不妨思考一下。
正确的如下
>>> def tese(* params):
... print("里面有%d个参数" % len(params))
... print("第二个参数是:",params[1])
...
>>> tese('C','C','S','D','E','W')
里面有6个参数
第二个参数是: C
>>> a = [1,2,3,4,4,5]
>>> tese(*a)
里面有6个参数
第二个参数是: 2
字典和集合
字典是python中唯一,一个映射类型
如何创建一个字典,如下
>>> dict = {"渗透":"网络安全","笔记":"为了共享","我们":"追逐梦想"}
>>> dict["渗透"]
'网络安全'
怎么理解字典呢?现实生活中的字典可以通过首字母进行查询要查找的汉子,python也可以这样理解,通过”:”前的元素查找到冒号后的元素。
为什么说字典是唯一一个映射类型呢?看图。
映射类型区别与序列类型,序列类型以数组的形式储存,通过索引的方式来获取相应位置的值,一般索引值与对应位置数据无关系。
简单来说就是你可以通过a找到n,但是a和n无关系。
字典的标志性符号“{}”,用大括号来定义,字典由多个键及其对应的值所构成,每一对键值成为项,很绕口吧。不急。
>>> dict = {"渗透":"网络安全","笔记":"为了共享","我们":"追逐梦想"}
>>> dict["渗透"]
'网络安全'
例子里的渗透,笔记,我们就是键,而后面的宣传标语就是值了。是不是好理解多了。
注意;字典的键必须是独一无二的,里面的值可以是多个类型,但必须是不可变的(如字符串,数,元组)
如何声明个空字典
>>> a = {}
>>> a
{}
>>> type(a)
<class 'dict'>
如例子中直接用一个空的大括号声明即可。
声明字典的多种方式
dict()方法如下
>>> dict1 = dict((('I',23),('V',83),('I',65),('U',3),('Y',343)))
>>> dict1
{'U': 3, 'I': 65, 'V': 83, 'Y': 343}
这里天钧遇到了故障,进行排查发现我定义过dict
TypeError:'dict' object is not callable 出现这种错误有两种可能:1. 代码里重新定义了dict,比如 dict= {...},这时调用的是代码里定义的dict而不是python内置类型 2. 取字典内容时用了()而不是[]。比如sdict("content_id"),应该是sdict["content_id"]
我的解决方法是
>>> del dict
>>>
>>> dict
<class 'dict'>
>>> del dict
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'dict' is not defined
>>> dict1 = dict((('I',23),('V',83),('I',65),('U',3),('Y',343)))
>>> dict1
{'U': 3, 'I': 65, 'V': 83, 'Y': 343}
第二种方法
>>> dict2 = dict(Y = 23,A = 21,W = 56,U=353)
>>> dict2
{'U': 353, 'W': 56, 'A': 21, 'Y': 23}
对比第一种方法,第二种是比较简洁的。这时注意键的位置上不能加上双引号。否则会报错
>>> dict4 = dict('Y' = 23,'A' = 21,'W' = 56,'U'=353)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression
直接给字典赋予新的值
>>> dict1['H'] = 12
>>> dict1
{'U': 3, 'I': 65, 'H': 12, 'V': 83, 'Y': 343}
>>>
这时咱们发现字典中的项里的 顺序跟序列是不同的,是因为字典讲究映射不讲顺序,所以很随意。
内置方法
formkeys()
用于创建返回一个新的字典,他有两个参数,第一个参数就是字典的键,第二个参数是可选的,是传入键对应的值。默认为None.
>>> dict1.fromkeys((1,2,3))
{1: None, 2: None, 3: None}
>>> dict2 = {('wocao'),"你大爷"}
>>> dict2
{'wocao', '你大爷'}
>>> dict2 = {('wocao',"卧槽","你大爷的"),"你大爷"}
>>> dict2
{('wocao', '卧槽', '你大爷的'), '你大爷'}
>>>
为什么和我们预想的不一样呢?如结果“wocao”你大爷,所示
解释为,他把('wocao',"卧槽","你大爷的")当成一个值了。
key() values() itsms()
key方法用于返回字典中的键如下
>>> dict3 = {}
>>> dict3.fromkeys(range(31),'wocao')
{0: 'wocao', 1: 'wocao', 2: 'wocao', 3: 'wocao', 4: 'wocao', 5: 'wocao', 6: 'wocao', 7: 'wocao', 8: 'wocao', 9: 'wocao', 10: 'wocao', 11: 'wocao', 12: 'wocao', 13: 'wocao', 14: 'wocao', 15: 'wocao', 16: 'wocao', 17: 'wocao', 18: 'wocao', 19: 'wocao', 20: 'wocao', 21: 'wocao', 22: 'wocao', 23: 'wocao', 24: 'wocao', 25: 'wocao', 26: 'wocao', 27: 'wocao', 28: 'wocao', 29: 'wocao', 30: 'wocao'}
>>> dict3.keys()
dict_keys([])
咦,为什么没有返回键呢?
看
>>> dict3
{}
因为fromkeys根本没有赋予值。如何解决
>>> dict3 = dict3.fromkeys(range(31),'wocao')
>>> dict3
{0: 'wocao', 1: 'wocao', 2: 'wocao', 3: 'wocao', 4: 'wocao', 5: 'wocao', 6: 'wocao', 7: 'wocao', 8: 'wocao', 9: 'wocao', 10: 'wocao', 11: 'wocao', 12: 'wocao', 13: 'wocao', 14: 'wocao', 15: 'wocao', 16: 'wocao', 17: 'wocao', 18: 'wocao', 19: 'wocao', 20: 'wocao', 21: 'wocao', 22: 'wocao', 23: 'wocao', 24: 'wocao', 25: 'wocao', 26: 'wocao', 27: 'wocao', 28: 'wocao', 29: 'wocao', 30: 'wocao'}
>>>
在进行操作
>>> dict3.keys()
dict_keys([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30])
>>>
完美
values
用于返回字典里的所有值
>>> dict3.values()
dict_values(['wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao', 'wocao'])
>>>
items
返回字典里的所有项
>>> dict3.items()
dict_items([(0, 'wocao'), (1, 'wocao'), (2, 'wocao'), (3, 'wocao'), (4, 'wocao'), (5, 'wocao'), (6, 'wocao'), (7, 'wocao'), (8, 'wocao'), (9, 'wocao'), (10, 'wocao'), (11, 'wocao'), (12, 'wocao'), (13, 'wocao'), (14, 'wocao'), (15, 'wocao'), (16, 'wocao'), (17, 'wocao'), (18, 'wocao'), (19, 'wocao'), (20, 'wocao'), (21, 'wocao'), (22, 'wocao'), (23, 'wocao'), (24, 'wocao'), (25, 'wocao'), (26, 'wocao'), (27, 'wocao'), (28, 'wocao'), (29, 'wocao'), (30, 'wocao')])
>>>
字典很大,有的参数我们不知道在不在子弹里,如果不存在就会报错
>>> dict3[32]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 32
get()
当查询一个项
>>> dict3.get(32)
>>>
在不在字典里,如果不在get会返回一个None,不会报错
也可以用in 与not in 来判断
清空一个字典
clear()
前面因为帮助理解,天钧用了一个最简单的方法就是把字典del了,其实还有更好的如下
>>> dict2
{('wocao', '卧槽', '你大爷的'), '你大爷'}
>>> dict2.clear()
>>> dict2
set()
>>>
copy()
复制字典
如下
>>> a = {1,23,4,5,67,87,23}
>>> a
{1, 67, 4, 5, 87, 23}
>>> type(a)
<class 'set'>
>>> b = a.copy()
>>> b
{1, 67, 4, 5, 87, 23}
>>>
pop与popitem
pop是弹出值,则popitem是弹出对应的项如下
>>> dict4 = {1:"wpcap",2:"342"}
>>> dict4.pop(1)
'wpcap'
>>> dict4.popitem()
(2, '342')
update
更新字典
如下
>>> name = {"米老鼠":"老鼠","天钧":"男人","小白":"狗"}
>>> name
{'米老鼠': '老鼠', '小白': '狗', '天钧': '男人'}
>>> name.update(小黑= "猫")
>>> name
{'米老鼠': '老鼠', '小黑': '猫', '小白': '狗', '天钧': '男人'}
>>>
集合
set大家看见如果认真看了有事type返回的是set,这个就是集合,看对比
>>> dict1 = {}
>>> dict2 = {1,23,4,5,5}
>>> type(dict1)
<class 'dict'>
>>> type(dict2)
<class 'set'>
>>>
好奇怪啊,在大括号里如果只是一群数字话没有体现到映射关系的,那么就认为他是个集合。
看个有趣的例子
>>> dict1 = {1,23,4,34,5,5,5,5,5,5,6,32,1,11,32}
>>> dict1
{32, 1, 34, 4, 5, 6, 11, 23}
>>>
你能找到谁失踪了吗?
创建集合
>>> set1 = {1,2,3,4,5,6,7,8}
>>> set2 = set([1,2,3,4,5,6,7,8])
>>> set1 == set2
True
>>>
这两种方法是一样的
访问集合
>>> set1
{1, 2, 3, 4, 5, 6, 7, 8}
>>> for each in set1:
... print(each,end = "_")
...
>>>1_2_3_4_5_6_7_8
将集合变成图片
让集合很稳,嘿嘿嘿 frozenset
>>> set1 = frozenset({1,2,3,4,5,6})
>>> set1.add(22)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'frozenset' object has no attribute 'add'
>>>
递归
大家有没有想我的Python呢?这几天挖粽子,挖到自闭,还好挖到一个,大家快去补天挖粽子吧!我知道这是废话。连Python都不会挖什么粽子。那不还赶快学起。这是函数的最后一章,下一章《字典》快点学习吧,开始我们的笔记
等等,差点忘记了,为了赶时间,我只能舍弃无关的图片,但又要保障大家的质量。
一边看视频一边看笔记吧,后台回复8523获取教程视频让你们零消费,学会Python。
递归是神马
从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?“从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?‘从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……’”。这个故事永远也讲不完,因为没有递归结束条件。老师讲递归时总是说,递归很简单,一个递归结束条件,一个自己调用自己。如果递归没有结束条件,那么就会无限递归下去。在编程的时候,没有递归结束条件或者递归过深,一般会造成栈溢出。 网络
怎么样理解了吗?有的同学对迭代也不了解,这里也提一下
迭代算法是用计算机解决问题的一种基本方法。 它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。为什么使用迭代而不用递归呢?很明显,使用递归时每调用一次,就需要在栈上开辟一块空间,而使用迭代就不需要了,因此,很多时候设计出了递归算法,还要想法设法修改成迭代算法。 网络
这样的解释懂了吧。
递归从原理上来讲就是不断地调用自身的一个行为,迭代就是重复同一个操作的,并从原有的值变成新值
例子
>>> def number():
... number()
...
>>> number()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in number
File "<stdin>", line 2, in number
File "<stdin>", line 2, in number
File "<stdin>", line 2, in number
它会不断地重复,直到耗尽所有资源。Python出于保护防止把它玩坏,最高叠加是100层。
实例
写一个求阶乘的函数
首先你要知道什么是阶乘,如果输入一个数如5,1x2x3x4x5=120,120就是5的阶乘。
普通版本
>>> def recursion(n):
... result = n
... for i in range(1,n):
... result *= i
... return result
...
>>> recursion(5)
120
递归版本
>>> def factorial(n):
... if n == 1:
... return 1
... else:
... return n * factorial(n - 1)
...
>>> factorial(5)
120
>>>
解释一下,期初我也是有些不懂,但是看着看着就明白了。灵魂画手天钧上线
习惯;记住要多使用Ctrl+S来保存文件,养成良好习惯
文件打开模式
‘r’ | 以只读方式打开文件 |
---|---|
'w' | 已写入的方式打开文件,会覆盖原有文件 |
'x' | 如果文件已经存在,会抛出异常 |
'a' | 以写入模式打开,如果已有文件会在后面追加写入 |
'b' | 以二进制打开文件 |
't' | 以文本模式打开 |
---|---|
'+' | 可读写模式 |
'U' | 通用换行符支持 |
打开文件
open有很多参数,这里先讲两个,第一个参数是导入文件名,只要有文件名,不带路径的话,Python会在当前的文件中找到它,并打开,第二个参数就是上面的表格,代表着打开方式。
打开演示
双斜杠表示转义。
打开这个文件。
close() | 关闭文件 |
---|---|
read(size = -1) | 从文件中读取size这个字符,当未给定size或给定负值的时候,读取剩余的所有字符,然后作为字符串返回。 |
readline() | 从文件中读取一整行字符串 |
write(str) | 将字符串str写入文件 |
writelines(seq) | 向文件写入字符串序列seq,seq应该是一个返回字符串可迭代的对象。 |
seek(offset,from) | 在文件中移动文件指针,从from(0代表文件起始,1代表着位置,2代表着文件末尾)偏移offset个字节 |
---|---|
tell() | 返回当前在文件的位置 |
read打开文件同'r'只能只读
>>> a.read()
' 一、 情景对话指的是任何人运用语言进行交流的时候,必须同时考虑语言的社会文化特点和语言的交流功能。他所说的每句话,都离不开他当时所处的具体环境。从使用什么句型到字词选择,都要和讲话人的身份和他所处的特定场合相符合。换言之,他应该知道在什么时候,什么地方对谁该用什么方式讲什么话,该说什么,不该说什么。\n\n 二、情景会话主要考查考生对日常生活中经常运用的交流语言及其应答的掌握情况,内容包括问候、介绍、打电话,感谢、问路、祝贺、道歉、应允、赞成、谈论天气、购物等等。'
>>> a.read()
''
>>> 读到文章末尾
读取前5个字符文,件指针
>>> a.read(5)
' 一、 情'
tell返回当前在文件中的位置
>>> a.tell()
9
>>>
读取一行,从45字符开始,
转换列表
高效率形式,利用for循环
写入
写入了7个字符
关闭
模块
模块是什么?模块其实是对你包含所定义函数的文件,可以进行引入
OS模块
什么是OS模块,OS模块就是operating system的缩写,意思是操作系统。
具体点就是市面上的系统很多如Linux,Windows,Unix,macOS,这些操作系统,如果把代码移到不同的平台可能会产生一些错误,但是有了OS模块后,就不怕啦。
getcwd()用于查看应用程序当前的工作目录。
chdir(path)用于切换目录
我估计你们是理解不了,迷糊。看图
这里提一下,这个括号里斜杠的问题。‘’\\‘’这个是转义然后可以运行,嫌麻烦直接‘’/‘’ 这个,记住自己系统里有乃个盘,不要照着我这个输入,结果报差错,没有I这个盘。
小爬虫“listdir(path='.')”
查看当前目录下有哪些文件与子目录,它可以帮助咱们列举出来。path的参数用于指定列举的目录,默认参数是'.',代表当前的目录也可以使用'..'代表上一层目录,迷糊吧,看例子就明白了
没有暴露什么吧。嘿嘿嘿
也就是说,listdir()可以查看任意的目录。那么我们创建一个文件夹,怎么做
mkdir(path)
当然要是重复了,会抛出异常
会受到,鄙夷的。
makedirs()与上面的mkdir很相似,看看这个makedirs()像不像make dir是不是有点好记了,但是不要搞混哦,makedirs用于创建多层目录。
这样
remove(path) rmdir(path) removedirs(path)三位大佬登场。
他们是干啥的,他们是拆迁队,还不给钱的那种,管删除的
remove(path)函数用于删除指定文件,然后我报错了
给你们看一下我的表情,
这种原因,拒绝访问,肯定是权限没到位,那么右击文件属性,把所有的用户权限开到完全控制
但是很快我就反应过来,他妈的
remove是删除文件的,不是删除文件夹
人生如戏啊
radir(path)这个可以完成上面那个操作,删除new make,哭
removedirs用于删除多层目录
removedirs
rename重命名文件或文件夹
看着两个文件,现在重命名
方法;rename(‘以前文件名’,‘改后文件名’)
调用工具,system()
walk(top)
遍历子目录返回一个三元组(路径。【包含目录】。【包含文件】)
basename(path)和dirname(path)
用于获得文件名和路径名
>>> os.path.basename(r"sqlmap\sqlmap.py")
'sqlmap.py'
>>> os.path.dirname(r"sqlmap\sqlmap.py")
'sqlmap'
完整路径join()
>>> os.path.join(r"sqlmap\sqlmap.py","new make.txt")
'sqlmap\\sqlmap.py\\new make.txt'
split()和splitext()
分割路径,
split用于分割路径与文件名
splitext用于分割文件名和扩展名
>>> os.path.split(r"sqlmap\sqlmap.py")
('sqlmap', 'sqlmap.py')
>>> os.path.splitext(r"sqlmap\sqlmap.py")
('sqlmap\\sqlmap', '.py')
>>>
获取文件尺寸
返回值以字节为单位
>>> os.path.getsize(r"sqlmap\sqlmap.py")
14737
时间函数
getatime(file)与getctime(file)和getmtime(file)
getatime()最近访问时间
getctime()创建时间
getmtime()修改时间
>>> os.path.getatime(r"sqlmap\sqlmap.py")
1559199951.9334888
>>> os.path.getctime(r"sqlmap\sqlmap.py")
1550079748.4742687
>>> os.path.getmtime(r"sqlmap\sqlmap.py")
1549964987.0
prckle()
pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。
pickle模块只能在Python中使用,python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化,
pickle序列化后的数据,可读性差,人一般无法识别。
>>> import pickle
>>> my_list = [122,333,44,'tian',['sssj']]
>>> pickle_file = open('I:\\my_list.pkl','wb')
>>> pickle.dump(my_list,pickle_file)
>>> pickle_file.close()
>>>
把my_list永远保存起来,建立文件夹my_list.pkl,dump来保存数据。
使用二进制打开
>>> pickle_file = open('I:\\my_list.pkl','wb')
>>> pickle.dump(my_list,pickle_file)
>>> pickle_file.close()
>>> pick_file = open("I:\\my_list.pkl","rb")
>>> my_list = pickle.load(pickle_file)
>>> print(my_list)
[122, 333, 44, 'tian', ['sssj']]
>>>
异常处理
常见的异常处理
AssertionError;断言语句失败
assert在测试程序的时候 在代码植入检查点
>>> my_list = ["tianjun"]
>>> assert len(my_list) > 0
>>> my_list.pop()
'tianjun'
>>>
>>> assert len(my_list) > 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
就是说assert len(my_list)>0这个语句判断为假时会报错
因为my_list只有“tianjun”这个字符串,pop()弹出后my_list为空,下面assert等式不成立,所以抛出异常
attributeerror尝试访问未知的对象属性
>>> my_list = []
>>> my_list.fisa
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'fisa'
indexerror索引超出序列范围
>>> my_list = [1,2,3,4,5]
>>> my_list[5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
keyerror字典中查找一个不存在的关键词
>>> dict1 = {"one":"1","two":"2","three":"3"}
>>> dict1['one']
'1'
>>> dict1['six']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'six'
>>>
nameerror尝试访问一个不存在的变量
>>> name = {}
>>> name
{}
>>> not name
True
>>> mett
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'mett' is not defined
OSerror操作系统异常
syntaxerror语法错误
>> print"wocao,meiyou xioakuohao"
File "<stdin>", line 1
print"wocao,meiyou xioakuohao"
^
SyntaxError: invalid syntax
typeerror不同类型的无效操作
>>> 1 + '1'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
zerodivisionerror除数为零
>>> 5/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
try-except语句
try-except语法
try:
检测范围
except exception[as reason]:
出现异常(esception)后处理代码
用于检测和处理异常
>>> try:
... f = open("一个文档.txt")
... print(f.read())
... f.close()
... except OSError:
... print("领绕我错了,报错了")
...
领绕我错了,报错了
>>>
根据不同的异常设置多个except
>>> try:
... sum = 1 + "1"
... f = open("wocao.txt")
... print(f.read())
... f.close()
... except OSError as reason:
... print("文件出错了,原因是"+str(reason))
... except TypeError as reason:
... print("文件出错了,原因是"+str(reason))
...
文件出错了,原因是unsupported operand type(s) for +: 'int' and 'str'
>>>
else语句(补充)
与if搭配的条件判断(要么怎样,要么不怎样)
if:
条件为真执行
else:
条件为假时执行
还能和for与while搭配如
>>> def showmaxdactor(num):
... count = num//2
... while count > 1:
... if num % count == 0:
... print('%d最大的数是%d' % (num,count))
... break
... count -=1
... else:
... print("%d是个素数"% num)
... num = int(input("请输入一个数"))
... showmaxdactor(num)
...
>>> showmaxdactor(2)
2是个素数
请输入一个数2
这个很好理解,要求用户输入的数的最大的约数。
也可以和异常处理进行搭配
>>> try:
... int('abx')
... except ValueError as reason:
... print("出错了"+ str(reason))
... else:
... print('没有异常')
...
出错了invalid literal for int() with base 10: 'abx'
>>>
with简洁你的异常处理
普通版
>>> try:
... f = open("date.txt",'w')
... for each_line in f:
... print(each_line)
... except OSError as reason:
... print("出错了:" + str(reason))
... finally:#这里的finally确保无论如和都是要被执行的
... f.close()
...
出错了:not readable
with版
>>> try:
... with open('date.txt','w')as f:
... for each_line in f:
... print(each_line)
... except OSError as reason:
... print("出错了"+str(reason))
...
出错了not readable
知识回顾 常见的异常: Exception 所有异常的基类(当不知道具体的异常可用这个处理)
AssertionError assert语句失败
AttributeError 特性应用或赋值时引发(试图访问一个对象没有的属性)
IOError 试图打开不存在的文件或者无全新的文件等操作时,就会引发(输入输入异常,基本是无法打开文件)
ImportError 无法引入模块或包,基本是路径问题
IndexError 在使用系列中不存在的索引时引发(下标索引超出序列边界)
KeyError 试图访问你字典里不存在的键key
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个未被赋予对象的变量
SyntaxError Python代码逻辑语法出错不能执行
TypeError 传入的对象类型与要求不符
UnboundLocalError 试图访问一个还未被设置的全局变量,基本上是由于另有一个同名的全局变量
ValueError 传入一个不被期望的值,即使类型正确
ZeroDivisonError 在除数为零发生的一个异常
对象
对象是什么?对象就是可以抱在怀里使劲揉,然后吃钱的小祖宗,她是怎么构成的,爱钱+任性 = 对象。在Python里也一样 对象=属性+方法。
是不是有种异曲同工之妙呢?答案是有个屁!
属性其实就是变量,方法就是咱们学过的函数,这样一想还是有联系的
如一个对象的特征叫做属性并且一个对象的行为叫做方法
看代码
小乌龟源代码
class Turtle:
#python 中的类名约定以大写字母开头
#特征的描述称为属性,在代码层次来看其实就是变量
color = "green"
weigth = 10
legs = 4
shell = True
mouth = '大嘴'
#方法实际就是函数,通过调用这些函数来完成某些工作
def climb(self):
print("我正在努力地往前爬")
def run(self):
print("我正在飞快的像前爬")
def bite(self):
print("咬死你咬死你")
def eat(self):
print("有吃的了")
def sleep(self):
print("困了,睡觉了,告辞")
调用
>>> tt = Turtle()
>>> tt.climb()
我正在努力地往前爬
>>>
笔记;
在源代码的层次上,还不叫一个对象,而是称源代码为一个class类,大家可能会注意到定义一个函数后跟了个陌生的参数(self)这个是什么呢?
在同一个class类里会生成无数个对象,也就是咱们常听到的面对修修爱那个编程,调用对象里的方法与函数也一样,先举个例子,理解下self的重要性
>>> aa = Buall()
>>> aa.setName("woshi")
>>> bb = Buall()
>>> bb.setName("天钧")
>>> aa.kick()
我叫woshi,奥 我是谁?!
>>> bb.kick()
我叫天钧,奥 我是谁?!
>>>
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称,但是在调用这个方法的时候你不为这个参数赋值,python会提供这个值。这个特别的变量指对象本身,按照惯例它的名称是self。 虽然你可以给这个参数任何名称,但是 强烈建议 你使用self这个名称——其他名称都是不赞成你使用的。使用一个标准的名称有很多优点——你的程序读者可以迅速识别它,如果使用self的话,还有些ide(集成开发环境)也可以帮助你。
现在我们先记住一个class类必须有一个好基友self
初探Python魔法方法
从前有个魔仙堡,里面有着许多的Python对象,他们天生就会魔法,所以他们把握着面对对象,他们会给你的类增加魔力,是不是很神奇呢?
Python的魔法方法都是用两个下划线封印起来的,还是很好辨认
法术__init__()构造方法。
__init__方法的魔力体,现在只要实例化一个对象,这个方法就会在对象被创建时自动调用,其实实例化对象时是可以传入参数的,这些参数会自动传入__init__()方法中,可以通过重写这个方法来自定义独享的初始化操作。
class Potato:
def __init__(self,name):
self.name = name
def kick(self):
print("我叫%s,奥我擦" % self.name)
运行为
>>> ss = Potato("卧槽卧槽")
>>> ss.kick()
我叫卧槽卧槽,奥我擦
实例化对象,你懂了多少,就是class带参数嘛,先存疑,魔法方法讲
公有与私有
一般的面对对象编程语言都会区分公有与私有的数据类型,像C++和Java他们的public和private关键字,用于声明数据是公有还是私有,但在Python中并没有用类似的关键词来修饰,所以本章到这里就结束了,告辞
默认上的对象属性和方法都是公开的,就像衣不隐体的美少女那样,可以通过(.)来访问。万恶之源
源代码
class Potato:
name = "卧槽,臭流氓"
运行后
>>> cc = Potato()
>>> cc.name
'卧槽,臭流氓'
为了实现私有变量,Python有个name mangling的技术(不是我说的,小甲鱼说得,我也没听过在变量名或者函数名前添加__两个英文的下划线,那么这个函数或者变量就是私有的了,不就是“半封印”嘛,魔法方法是全封印,秒懂,我真是机智的一比
源代码
class Potato:
__name = "卧槽,臭流氓"
运行后
>>> cc = Potato()
>>> cc.__name
Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
cc.__name
AttributeError: 'Potato' object has no attribute '__name'
那没法访问了丫,咋办,从内部访问
源代码
class Potato:
def __init__(self,name):
self.__name = name
def getName(self):
return self.__name
运行
>>> o = Potato("天钧")
>>> o.__name
Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
o.__name
AttributeError: 'Potato' object has no attribute '__name'
>>> o.getName()
'天钧'
>>>
还可以这样哦
>>> o._Potato__name
'天钧'
继承,这个词熟悉吗?如果你才20岁,可能要等上100年才会接触到继承这个词,努努力没准长生了呢
语法
class 类名(被继承的类):
.....
看代码,其实很好理解
>>> class Parent:
... def hello(self):
... print("正在调用父类方法")
...
>>> class Child(hello):
... pass
...
>>> p = Parent()
>>> p.hello()
正在调用父类方法
>>> c = Child()
>>> c.hello()
正在调用父类方法
>>>
嗯哼哼?其实就相当于就用,继承者相当于子类,pass是什么,空的意思方便大家理解,官方点就是占位符
看一个吃鱼的小游戏(源代码)
import random as r#调用
class Fish:#一个类
def __init__(self):#还记得上一章的魔法方法吗__init__可以实实例化对像来代入参数
self.x = r.randint(0,10)
self.y = r.randint(0,10)
def move(self):
self.x -=1
print("我的位置是",self.x,self.y)
def goldfish(Fish):
pass
def carp(Fish):
pass
def Salmon(Fish):
pass
class Shark(Fish):#定义鲨鱼,一个傻鲨鱼
def __init__(self):#这里会讲到调用未绑定的父类方法
self.hungry = True
def eat(self):
if self.hungry:
print("我是个大吃货")
self.hungry = False
else:
print("饱了,不吃了")
运行后,发现鲨鱼报错了
>>> fish = Fish()
>>> fish.move()
我的位置是 2 7
>>> shark = Shark()
>>> shark.move()
Traceback (most recent call last):
File "<pyshell#94>", line 1, in <module>
shark.move()
File "C:/Users/Administrator/Desktop/魔法方法.py", line 10, in move
self.x -=1
AttributeError: 'Shark' object has no attribute 'x'
>>>
原因是,调用__init__时重新定义,无法实现移动 改下代码
完美
这里的self是子类的self而不是父类的self替代
代码
class Shark(Fish):
def __init__(self):
Fish.__init__(self)
self.hungry = True
def eat(self):
if self.hungry:
print("我是个大吃货")
self.hungry = False
else:
print("饱了,不吃了")
有没有更好的方法呢?
有的super函数
class Shark(Fish):
def __init__(self):
super().__init__()
self.hungry = True
def eat(self):
if self.hungry:
print("我是个大吃货")
self.hungry = False
else:
print("饱了,不吃了")
运行如下
>>> shark = Shark()
>>> shark.move()
我的位置是 4 9
直接原话开始解释
super的超级之处在于你不许要明确的给出任何基类的名字,他会自动的帮你找出所有基类以及对应的方法。意味着如果需要改变类的继承关系,只需要改变class语句里的父类即可。
多重继承
语法
class 类名(父类1,父类2,父类3......)
.......
看代码,秒懂
class Base1:
def fool(self):
print("我是fool,我在Basel中")
class Base2:
def foo2(self):
print("我是foo2,我在Basel中")
class Cat(Base1,Base2):
pass
运行后
>>> cat = Cat()
>>> cat.fool()
我是fool,我在Basel中
>>> cat.foo2()
我是foo2,我在Basel中
>>>
当然不建议使用的,会造成bug的
>>> class C:
... count = 0
...
>>> a = C()
>>> b = C()
>>> c = C()
>>> print(a.count,b.count,c.count)
0 0 0
>>> c.count +=100
>>> print(a.count,b.count,c.count)
0 0 100
>>> C.count +=100
>>> print(a.count,b.count,c.count)
100 100 100
上面可以看出,对实例对象c的count的属性进行赋值后,就相当于覆盖了类对象C的count属性。如果没有赋值覆盖,那么引用的是类对象的count属性。
有点绕对吧
看一下图就很好理解了
注意;类中定义的属性是静态变量,也就是相当于C语言中加上static声明的变量,类的属性食欲类对象进行绑定,并不会以来任何他的实例对象。
如果属性跟方法名相同,属性会覆盖方法
>>> class C:
... def x(self):
... print("xman")#如果属性跟方法名相同,属性会覆盖方法
...
>>> c = C()
>>> c.x()
xman
>>> c.x = 1#覆盖
>>> c.x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>> c.x#覆盖后属性为1 ,也即是变量会覆盖函数
1
>>>
规则
骆驼命名法
printEmployeePaychecks();
print_employee_paychecks();
第一个函数名使用了骆驼式命名法——函数名中的每一个逻辑断点都有一个大写字母来标记;
第二个函数名使用了下划线法----函数名中的每一个逻辑断点都有一个下划线来标记。
什么是绑定
>>> class CC:
... def setXY(self,x,y):
... self.x = x
... self.y = y
... def printXY(self):
... print(self.x,self.y)
...
>>> dd = CC()
>>> dd.setXY(2,4)
>>> dd.printXY()
2 4
>>>
可以使用__dict__查看对象的的所有属性
>>> class CC:
... def setXY(self,x,y):
... self.x = x
... self.y = y
... def printXY(self):
... print(self.x,self.y)
...
>>> dd = CC()
>>> dd.setXY(2,4)
>>> dd.printXY
<bound method CC.printXY of <__main__.CC object at 0x02AA1D30>>
>>> dd.printXY()
2 4
>>> dd.__dict__
{'y': 4, 'x': 2}
>>> CC.__dict__
mappingproxy({'printXY': <function CC.printXY at 0x02AA4228>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None, 'setXY': <function CC.setXY at 0x02AA4270>, '__module__': '__main__'})
>>>
__dict__属性是由一个字典组成,字典中仅有得实例对象的属性,不显示类属性和特殊属性,键表示属性名,值表示对键对应的
>>> dd.printXY()
2 4
>>> dd.__dict__
{'y': 4, 'x': 2}
兑现实例对象dd有了两个新属性,而是这两个属性是仅属于实例对象的
>>> CC.__dict__
mappingproxy({'printXY': <function CC.printXY at 0x02AA4228>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None, 'setXY': <function CC.setXY at 0x02AA4270>, '__module__': '__main__'})
这完全归功于self参数,当时离对象dd去调用setXY方法的时候,他传入的第一个参数就是dd,那么self.x=2,self.y=4.也就相当于dd.x=2,dd.y=4所以你在实例对象,甚至类对象中都看不到xy因为这两个属性只属于实例对象dd的
如果删除类对象,还是可以使用dd来调用printXY方法
构造和析构
魔法方法总是被"__init__"两个下划线所包围
魔法方法是面对对象Python的一切
魔法方法的魔力总是能够在适当的时候被调用
例子
class Rectangle:
'''定义一个矩形类,需要长宽两个参数,拥有计算周长和面积
的两个方法,需要对象在初始化的时候,拥有长和宽两个参数
因此需要重写__init__方法'''
def __init__(self,x,y):
self.x = x
self.y = y
def Zc(self):
return self.x + self.y
def Cc(self):
return self.x * self.y
运行后
>>> dd = Rectangle(2,4)
>>> dd.Zc()
6
>>> dd.Cc()
8
很容易理解吧。
注意的是,__init__()方法的返回值一定是None,不能是其他,例子
>>> class A:
... def ___init__(self):
... return "A for A-Cup"
...
>>> cup = A()
Traceback (most recent call last):
File "<pyshell#26>", line 1, in <module>
cup = A()
TypeError: __init__() should return None, not 'str'
这里有个误差,有的同学,是没有报错的。
可能是版本不同,而且上面的程序也没达到咱们要的效果
>>> cup = A()
>>>A for A-Cup
这是咱们想得到的,根据魔法方法__init__的要求,返回值一定要是None大家记住就好。
在魔法方法中,也是讲究谁是老大的,也就是,谁是第一个被调用的,这里有的同学会说那肯定是(__init__())其实并不是,新知识点
__new__(cls[,....])才是一个对象实例化的时候所调用的第一个方法
看例子
class Capstr(str):
def __new__(cls,string):
string = string.upper()
return str.__new__(cls,string)
运行后
>>> a = Capstr("tianjun")
>>> a
'TIANJUN'
>>>
如果说__init__()和__new__()方法是对象的构造器的话,那么python也析构了一个构造器,__del__()方法,当对象被销毁时,这个方法就一定会被调用,但要注意的是,并非del x就等同于自动调用了x.__del__(),__del__()方法是当垃圾回收机制回收这个对象的时候调用的
看例子
>>> class C():
def __init__(self):
print('我是__init__()方法')
def __del__(self): \
print('我是__del__()方法')
>>> c1 = C()
我是__init__()方法
>>> c2 = c1
>>> c3 = c2
>>> del c1
>>> del c2
>>> del c3
我是__del__()方法
自Python2.2以后,对类和类型进行了同一,做法就是将int(),float(),str(),list()tuple()这些BIF转换为工厂函数
工厂函数
>>> type(len)
<class 'builtin_function_or_method'>
#len方法用于返回参数的长度
他返回了一句<class 'builtin_function_or_method'>这是个普通的BIF返回的,看一下Int的返回格式
>>> type(int)
<class 'type'>
>>> type(str)
<class 'type'>
>>>
你会发现,它和class(类,撞了衫)如下
>>> class A:
... pass
...
>>> type(A)
<class 'type'>
>>>
所谓的工厂函数,其实就是个class(类),调用时,其实就是实例化一个对象,如下
>>> a = int("123")
>>> b = int("456")
>>> a + b
579
>>>
算数操作符
列举一些常用的算数运算的魔法方法
魔法方法 | 含义 |
---|---|
__add__(self,other) | 定义加法的行为:+ |
__sub__(self,other) | 定义减法行为:- |
__mul__(self,other) | 定义乘法行为;* |
__truediv__(self.other) | 定义除法行为:// |
__mod__(self,other) | 定义取模算法行为;% |
---|---|
__divmod__(self,other) | 定义当做调用__divmod__时的行为 |
__pow__(self,other[,,odulo]) | 定义被当做__pow_-调用或**运算时行为 |
__lshift__(self,other) | 定义按位左移的行为;<< |
__rshift__(self,other) | 定义按位右移的行为;>> |
__and__(self,other) | 定义与操作的行为;‘&’ |
---|---|
__xor__(self,other) | 定义按位异或的行为‘^’ |
__or__(self,other) | 定义按位或的行为‘|’ |
举个例子
class New_int(int):
def __add__(self,other):
return int.__sub__(self,other)
def __sub__(self,other):
return int.__add__(self,other)
源码
运行后
>>> a = New_int(4)
>>> b = New_int(5)
>>> a + b
-1
>>> a - b
9
如果自己写代码,不想调用Python的默认方案行吗?
肯定行啊,但是我们可能会疏忽
看下列代码
class Try_int(int):
def __add__(self,other):
return selt + other
def __sub__(self,other):
return self - other
大家不妨找找错
运行后
>>> a = Try_int(4)
>>> b = Try_int(6)
>>> a +b
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
a +b
File "C:/Users/Administrator/Desktop/__add甲方.py", line 3, in __add__
return selt + other
NameError: name 'selt' is not defined
程序出现了无限递归的情况,为什么
return selt + other
因为这串代码,当对象涉及到,加法时会调用__add__然后,又加法又调用,形成无限的递归。
怎么改
class Try_int(int):
def __add__(self,other):
return int(self) + int(other)
def __sub__(self,other):
return int(self) - int(other)
运行后
>>> a = Try_int(4)
>>> b = Try_int(6)
>>> a + b
10
(反运算相关的魔法方法)
与之前的笔记对比,不难发现反运算只是多了一个‘r’
看例子
class Nint(int):
def __radd__(self,other):
return int.__sub__(self,other)
#加数是a,被加数是b。请问谁主动。
运行后
>>> a = Nint(5)
>>> b = Nint(3)
>>> a + b#肯定是a主动啦!
8
关于反运算,这里要注意一点;对于a + b,b的__radd__(self,other),中other是a的对象,self才是b的对象
增量赋值运算符
(来源于网络)
Python里有大量的魔术方法可以定制增量赋值语句,增量赋值其实就是一种偷懒的形式,就像上面
>>> a = 1
>>> b =3
>>> a += b#注意+=之间无空格
>>> a
4
>>> a = a + b
一元操作符概念
一元操作符是指一个操作数,如上面的a +=b是二元操作符,只有一个操作数的,如把一个减号放在操作数前面,取这个数相反数的意思,管他叫负号
简单的定制
#基本要求
定制一个计时器额类
start和stop方法代表启动计时和停止计时
假设计时器对象t1,print(t1)和直接调用t1均显示结果
当计时器未启动或已经停止计时,调用stop方法会给温馨提示
两个计时器对象可以相加
只能使用有限的资源完成
演示代码
>>>t1 = MYtime()
>>>t1
未开始计时
>>>t1.stop()
提示:请先调用start()开始计时
>>>t1.start()
计时开始
>>>t1
提示;请输入stop()结束计时
>>>t1
总共运行5秒
>>>t2 = MYtime()
>>>t2.start()
计时开始
>>>t2.stop()
计时结束
>>>t2
一共运行6秒
>>>t1 + t2
总共运行11秒
你需要使用time模块里的localtime方法获取时间
time.localtime返回struct_time的时间格式
表现你的类__str__()和__repr__()魔法方法
>>> import time
>>> time.time
<built-in function time>
>>> time.time()
1560518311.610051
>>>
localtime方法获取时间
time.localtime
>>> import time
>>> time.localtime()
time.struct_time(tm_year=2019, tm_mon=6, tm_mday=14, tm_hour=21, tm_min=38, tm_sec=35, tm_wday=4, tm_yday=165, tm_isdst=0)
>>>
源代码
def stop(self):
self.stop = t.localtime()
print("计时结束")
#考虑怎么进行计算localtime()返回一个时间元组的结构,只取前面6个元素,然后将stop的元素
#依次减去start对应的元素,将差值存放在一个新的列表里
import time as t
class Mytime:
def start(self):
self.start = t.localtime()
print("开始计时")
def stop(self):
self.stop = t.localtime()
self._calc()
print("计时结束")
#内部方法用于计算时间
def _calc(self):
self.lasted = []
self.prompt = "总共运行了"
for index in range(6):
self.lasted.append(self.stop[index] - self.start[index])
self.prompt += str(self.lasted[index])
print(self.prompt)
运行结果
>>> t1 = Mytime()
>>> t1.start()
开始计时
>>> t1.stop()
总共运行了000005
计时结束
>>>
基本实现了计时功能,接下下来需要完成print(t1)与t1均显示结果,那就要重写,str__()与__repr__()魔法方法来实现。
import time as t
class Mytime:
def start(self):
self.start = t.localtime()
print("开始计时")
def stop(self):
self.stop = t.localtime()
self._calc()
print("计时结束")
#内部方法用于计算时间
def _calc(self):
self.lasted = []
self.prompt = "总共运行了"
for index in range(6):
self.lasted.append(self.stop[index] - self.start[index])
self.prompt += str(self.lasted[index])
print(self.prompt)
def __str__(self):
return self.prompt
__repr__ = __str__
运行后
>>> t1 = Mytime()
>>> t1.start()
开始计时
>>> t1.stop()
总共运行了000008
计时结束
>>> t1
总共运行了000008
>>>
似乎很不错,但是一位安全工作者,怎么能把自己的用户当成“朋友”呢?
>>> t1 = Mytime()
>>> t1
Traceback (most recent call last):
File "<pyshell#43>", line 1, in <module>
t1
File "C:\Python34\lib\idlelib\rpc.py", line 614, in displayhook
text = repr(value)
File "C:/Users/Administrator/Desktop/fugai.py", line 19, in __str__
return self.prompt
AttributeError: 'Mytime' object has no attribute 'prompt'
>>>
没有执行stop()那么_calc就是个摆设,要是先定义,不让在调用某个函数在进行其变量,就不会出错
import time as t
class Mytime:
def __init__(self):
self.prompt = "未开始计时"
self.lasted = []
self.start = 0
self.stop = 0
def start(self):
self.start = t.localtime()
print("开始计时")
def stop(self):
self.stop = t.localtime()
self._calc()
print("计时结束")
#内部方法用于计算时间
def _calc(self):
self.lasted = []
self.prompt = "总共运行了"
for index in range(6):
self.lasted.append(self.stop[index] - self.start[index])
self.prompt += str(self.lasted[index])
print(self.prompt)
def __str__(self):
return self.prompt
__repr__ = __str__
运行后
>>> t1 = Mytime()
>>> t1
未开始计时
>>> t1.start()
Traceback (most recent call last):
File "<pyshell#46>", line 1, in <module>
t1.start()
TypeError: 'int' object is not callable
>>>
怎么又报错了,书上是故意的,但是我是很不愿意报错,因为会浪费时间
这里简要说明
TypeError: 'int' object is not callable
大家要学会看异常,在调用t1.start()
Python认为他是个整型,这是因为如果类中的方法名(函数)和属性(变量)重名方法会覆盖属性
更改其所有self.start和self.end成self.begin和relf.start即可
但是不人性化
稍微加工一下
#记载时间模块
import time as t
class Mytimer :
def __init__ (self) :
self.unit = ['年','月','天','时','分','秒']
self.prompt = '未开始计时'
self.lasted = []
self.begin = 0
self.end = 0
#输入对象直接输出
def __str__ (self) :
return self.prompt
def __repr__ (self) :
return self.prompt
#开始计时模块
def start (self) :
self.begin = t.localtime()
self.prompt = '请先调用stop()停止计时!'
print ('计时开始...')
#停止计时模块
def stop (self) :
if not self.begin :
print ('请先调用start()开始计时!')
else :
self.end = t.localtime()
self._cacul()
print ('计时结束!')
#内部计算运行时间
def _cacul(self) :
self.prompt = '总共运行了'
self.lasted = []
for index in range (6) :
self.lasted.append(self.end[index] - self.begin[index])
self._judge1()
for index in range (6) :
if self.lasted[index] :
self.prompt += (str(self.lasted[index]) + str(self.unit[index]))
#为下一轮计数初始化变量
self.begin = 0
self.end = 0
#计算两个时间累计和
def __add__ (self,other) :
self.prompt = '两次总共运行了'
self.result = []
for index in range (6) :
self.result.append(self.lasted[index] + other.lasted[index])
self._judge2()
for index in range (6) :
if self.result [index] :
self.prompt += str( self.result[index] ) + self.unit[index]
return self.prompt
#判断两个数据是否出现负数
def _judge1(self) :
for index in range (6) :
if self.lasted[ index ] < 0 :
#当负数出现时,前一位-1
self.lasted [ index-1 ] -= 1
#当负数出现在分秒时,+60
if index == 5 or index == 4:
"""self.lasted [ index -1 ] -= 1"""
self.lasted [ index ] += 60
#当负数出现在时时,+24
elif index == 3 :
"""self.lasted [ index-1 ] -= 1"""
self.lasted [ index ] += 24
#当负数出现在天时,+31
elif index == 2 :
"""self.lasted [ index-1 ] -= 1"""
self.lasted [ index ] +=31
#当负数出现在月时,+12
elif index == 1 :
"""self.lasted [ index-1 ] -= 1"""
self.lasted [ index ] += 12
#判断两个数据是或否可以进位
def _judge2 (self) :
for index in range (5 , -1 , -1) :
if index == 5 or index == 4 :
if self.result [ index ] >= 60 :
self.result [ index - 1 ] += 1
self.result [ index ] -= 60
elif index == 3 :
if self.result [ index ] >= 24 :
self.result [ index - 1 ] += 1
self.result [ index ] -= 24
elif index == 2 :
if self.result [ index ] >= 31 :
self.result [ index - 1 ] += 1
self.result [ index ] -= 31
elif index == 1 :
if self.result [ index ] >= 12 :
self.result [ index - 1 ] += 1
self.result [ index ] -= 12
else :
pass
运行后
>>> t1 = Mytimer()
>>> print(t1)
未开始计时
>>> t1.start()
计时开始...
>>> t1.stop
<bound method Mytimer.stop of 请先调用stop()停止计时!>
>>> t1.stop()
计时结束!
>>> t1
总共运行了20秒
>>>
属性访问
通常可以通过点(.)操作符的形式去访问对象的属性,关于属性的访问,也有相应的魔法方法来管理,
属性相关的魔法方法
魔法方法 | 含义 |
---|---|
__getattr__(self,name) | 定义当用户试图获取一个不存在的属性的行为 |
__getattribute__(self,name) | 定义当该类的属性被访问时的行为 |
__setattr__(self,name,value) | 定义当一个属性被设置时 |
__delattr__(self,name) | 定义一个属性被删除时 |
例子
class C:
def __getattribute__(self,name):#当该类的属性被访问的行为
print('getattribute')
return super().__getattribute__(name)
def __setattr__(self,name,value):#当一个属性被设置时
print('setattr')
super().__setattr__(name,value)
def __delattr__(self,value):#当一个属性被删除
print('delattr')
super().__delattr__(name)
def __getattr__(self,name):#当用户获取一个不存在的上述属性
print('getattr')
运行后
>>> c = C()
>>> c.x
getattribute
getattr
>>> c.x = 1
setattr
>>> c.x
getattribute
1
>>> del c.x
delattr
上面的几个魔法方法可能会造成死循环
看例子
要求;写一个矩形类(Rectangle),默认有宽和高两个属性,如果为一个叫做square的属性赋值,那么说明是个正方形,值就是正方形的边长,此时宽高都应等于边长
class Rectangle:
def __init__(self,width = 0,height = 0):
self.width = width
self.height = height
def __setattr__(self,name,value):
if name == 'square':
self.width = value
self.height = height
else:
self.name = value
def getArea(self):
return self.width * self.height
不妨粘在电脑里运行一下
分析原因,其实就是调用__init__时,不断地去触发__setattr__方法,造成了死循环
更改
class Rectangle:
def __init__(self,width = 0,height = 0):
self.width = width
self.height = height
def __setattr__(self,name,value):
if name == 'square':
self.width = value
self.height = height
else:
self.__dict__[name] = value
def getArea(self):
return self.width * self.height
运行
>>> r1 = Rectangle(4,5)
>>> r1.getArea()
20
迭代器
还记得迭代吗?
这篇介绍下
迭代类似于循环,每一次充分的过程被称为一次迭代
如序列(列表,元组,字符串),还有字典,都支持迭代操作
复习一下
>>> for i in 'tianjun':
... print(i)
...
t
i
a
n
j
u
n
>>>
字符串相当一个容器,也同时是个迭代器,for语句的作用介绍触发这个迭代器的迭代功能,每次拿出一个数据,就是迭代操作
关于迭代
Python有两个BIF
重点
iter()
next()
对一个容器对象调用iter就是得到他的接待器,调用next迭代器觉慧返回下一个值
如果一个容器是迭代器,那就必须调用iter方法,这个方法实际是就是返回迭代器本身,然后是实现的是next()魔法方法,因为它决定了迭代的规则,如下
用迭代器写的裴波那切数列:
class Fibs:
def __init__(self,n = 10):
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self
def __next__(self):
self.a,self.b = self.b,self.a+self.b
if self.a > self.n:
raise StopIteration
return self.a
生成器、什么是生成器
通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator
继续使用import sys斐波那契
def fibonacci(n):
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
输出
0 1 1 2 3 5 8 13 21 34 55
模块
把定义存放在文件中,为一些脚本或者交互式的解释器实力使用,这个文件被称为模块
模块是一个包含所有你定义的函数和变量的文件,其后缀名是py模块可以被背的程序引用,以使用该模块中的函数等功能,这就是使用Python标准库的方法
可以说模块实际上就是程序
在前面咱们尝试过,如import OS
如下
>>> import os
>>> type(os)
<class 'module'>
import os 引用了os模块
同理,使用Python标准库的例子
>>> import sys
>>> import using_sys.py
命令行参数如下:
Python 路径为: ['', 'C:\\WINDOWS\\SYSTEM32\\python34.zip', 'C:\\Python34\\DLLs', 'C:\\Python34\\lib', 'C:\\Python34', 'C:\\Python34\\lib\\site-packages']
自定一个模块,代码内容如下
def name():
print("hello")
编辑好后。命名为modle.py,运行后
>>> import modle
>>> modle.name()
hello
想使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下:
import module1[, module2[,... moduleN]
当解释器遇到import语句时,如果模块在当前的搜索路径就会被导入
搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块需讲命令放在脚本顶端
例子计算摄氏度与华氏度的相互转换
#pan.py
def c2f(cel):
fan = cel *1.8 + 32
return fan
def f2c(fah):
cel = (fah - 32)/1.8
return cel
在写个文件
import pan
print("32摄氏度 = %.2f" % pan.c2f(32))
print("99华氏度 = %.2f" % pan.f2c(99))
这样显得有些麻烦
from 模块名 import 函数名如下
from modname import name1[, name2[, ... nameN]]
例如,要导入模块 sa 的 name 函数,使用如下语句:
from sa import name
它不会把整个sa模块导入当前的命名空间里,只会把其对应的函数引入
from 模块名 as 新名字
from modname import *
把一个模块的所有内容全都导入到当前的命名空间也是可行的
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
所以并不推荐使用
推荐使用方法
import 模块名 as 新名字【指模块的新名字,方便】
用这种方法给导入的命名空间替换一个新名字
命名空间解释;如同在一个文件里声明一个name函数,再另一个文件里再声明一个name函数,这两个函数虽然名字相同,但是却不相干,如何识别,在name函数前面加上文件名,而这个文件名加上命名空间
一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行。
>>> __name__
'__main__'
简单的理解,就是说__name__属性的值是__main__ 每个模块都有一个__name__属性,当其值是'__main__'时,表明该模块自身在运行,否则是被引入。
测试下面的代码
if __name__ == '__main__':
print('程序自身在运行')
else:
print('我来自另一模块')
dir()内置函数dir()可以找到模块内定义的所有名称
>>> import pan
>>> pan.__name__
'pan'
>>> dir(pan)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'c2f', 'f2c']
path搜索路径
>>> import sys
>>> sys.path
['', 'C:\\WINDOWS\\SYSTEM32\\python34.zip', 'C:\\Python34\\DLLs', 'C:\\Python34\\lib', 'C:\\Python34', 'C:\\Python34\\lib\\site-packages']
>>>
包
简单理解就是,上面咱们把建立一个文件叫做模块,其实包就是建立一个文件夹
但是文件夹是有前提条件的,Python怎么识别这个文件夹是一个包呢?