Python语法--Mooc七月
参考资料备用:
python ABC
3.8.2Documentation
python cookbook 3rd
pip安装超时解决办法
vscode小技巧
- 打开命令窗口:Ctrl+`
- 注释:单行 – Ctrl+/,多行 – Shift+Alt+A
- cmd:
cls
清屏 - Ctrl + Shift + O:快速定位函数
目录速查
Python入门导学
Python基本类型:数字,字符串
组:列表,元组,集合,字典
变量与运算符
分支、循环、条件和枚举
包、模块、类
函数
面向对象:类,实例,方法,继承
正则表达式和JSON
枚举类型,闭包
匿名函数、高阶函数、装饰器
爬虫实战
Python杂记
Python入门导学
返回
特点
- 简洁;丰富的标准库和第三方库(电子邮件、GUI);面向对象+函数式编程;易于上手,难于精通;既有动态脚本的特性,又有面向对象的特性。
- 豆瓣、知乎
- Simple is better than complex.
Now is better than never. Although never is often better than an right now. - 缺点:慢
编译型语言(C、C++)–运行效率
解释型语言(Javascript,Python)–开发效率
一个经典误区:编程 = web编程?
- 世界上不是只有网站,还有很多问题需要编程来解决。
- web是基础–爬虫、数据服务提供、数据分析。
- 互联网时代,有网络的地方就需要web。
- web编程确实是最好的语言实践–业务逻辑思考能力、宽广的知识面。
Python能做什么
- 爬虫
- 大数据与数据分析(Spark)
- 自动化运维与自动化测试
- web开发:Flask,Django
- 机器学习:Tensor Flow(谷歌)
- 胶水语言:能够把其他语言制作的各种模块(尤其是C/C++)轻松地联结在一起
正确打开方式:遇到问题时,随手拿起Python写个工具
什么是写代码&Python的基本类型
返回
什么是代码,什么是写代码
- 代码: 现实世界事物在计算机世界中的映射
- 写代码: 将现实世界中的事物用计算机语言来描述
数字
整型与浮点型
- 整数:
int
其他语言有short
,int
,long
- 浮点数:
float
其他语言有单双精度之分,Python没有
type(2/2)
是float
(1.0),type(2//2)
是int
(1)
*双斜杠是“整除”
10、2、8、16进制&表示&转换
- 其他进制:60s = 1min
- 2进制:0b10,直接在IDLE回车就会返回2
8进制:0o10 = 8
16进制:0x10 = 16 bin()
:将其他进制转换成2进制
oct()
:将其他进制转换成8进制
hex()
:将其他进制转换成16进制
int()
:将其他进制转换成10进制
布尔类型和复数(属于数字分类)
bool
:表示真、假
True/False
,要大写
只要非 0/空串/空列表/None
,就都是True
complex
:复数(36j
)
抓大放小,抓住重点深入
字符串str
单双引号
- 单引号和双引号–成对出现
"let's go"
,'let\'s go'
多行字符串
- 一行79,回车字符\n会读进字符串中
'''
hello world
hello world
'''
"""
hello world
hello world
"""
- IDLE写
'\n'
输出还是'\n'
,不换行
print("""hello world\nhello world\n""")
会输出换行 - 单引号换行:
'hello\
world'
输出'helloworld'
转义字符–特殊的字符
- 表示无法“看见”的字符
- 与本身语法有冲突的字符
\n
换行
\r
回车:光标回到本行首位置,不会换行
\t
横向制表符:TAB
\'
单引号
原始字符串
- 字符串前加
r
/R
,原始字符串–所看即所得。 'let's go'
无法通过加r解决–引号要成对出现
字符串运算
- +:拼接
*数字:重复数字倍 - 获取单个字符:“字符串”[i],负数从后往前数
获取一段字符:步长
'hello world'[0:4]
输出'hell'
,要读到字符下一位
'hello world'[0:-1]
输出'hello worl'
- 怎么输出world?
"hello world"[6:]
,默认取字符串最后一位
"hello world"[-5:]
,后往前数第5位,到末尾
“组”的概念与定义
返回
列表list
定义
列表内部可以存放不同类型元素
列表内部可以嵌套列表
基本操作
- 取元素
["新月打击","苍白之瀑","月之降临","月神冲刺"][0]
'新月打击' #返回的是元素
["新月打击","苍白之瀑","月之降临","月神冲刺"][-1:]
['月神冲刺'] #返回的是列表
- 合并列表:
+
*3
:把列表内元素重复三次
元组tuple
- 同列表
type(('hello'))
返回值str
:为什么只有一个元素的元组是元素的类型?
答:()内只有一个元素,python优先认为()是数学运算符,返回数学运(比如(1))。
表示只有一个元素的元组:(1,)
表示一个元素都没有的空元组:()
type([1])
返回值是list
序列总结
- 序号
- 切片
"hello world"[0:8:2]
返回'hlow
–在0-7的切片内隔1取元素? +
,*
- 元素是否在序列中:
in
,not in
,返回bool值
3 in [1,2,3,4,5]
返回True
len()
,max()
,min()
:返回序列长度、最大值、最小值
max、min不支持不同类型元素比较ord()
返回单个字符的ASC码(字符串不行)
集合set
- 最大的特点——无序
{1,2,3,4,5}
不支持序号、切片 - 不重复
{1,1,1,2,2,3,4,5}
返回{1,2,3,4,5}
len()
in
、not in
{1,2,3,4,5,6} - {3,4}
:两个集合取差集
{1,2,3,4,5,6} & {3,4}
:两个集合取交集
{1,2,3,4,5,6} | {3,4,7}
:两个集合取并集- 怎么定义空的集合?
type({})
返回dict
类型 – 不可用
type(set())
返回set
类型 – 正确操作
字典dict
- 很多的
key
和value
,set
的延生而不是序列的
{key1:value, key2:value, ……}
- 最常用操作:通过key得到/访问value
- key值不可重复
{'Q':"新月打击",'W':"苍白之瀑",'E':"月之降临",'R':"月神冲刺"}['Q']
'新月打击'
{'Q':"新月打击",'Q':"苍白之瀑",'E':"月之降临",'R':"月神冲刺"}['Q']
'苍白之瀑'
{'Q':"新月打击",'Q':"苍白之瀑",'E':"月之降临",'R':"月神冲刺"}
{'Q':"苍白之瀑",'E':"月之降临",'R':"月神冲刺"}
value
类型无限制,可以也是一个字典
key
必须是不可变的类型 – 字符串和元组不可变,列表可变
变量与运算符
返回
变量
什么是变量
- 名字:起名字要有意义 – 命名可读性要强,多查单词
=
:赋值符号
命名规则
- 字母、数字、下划线
- 首位不能是数字
- 系统关键字(保留关键字)不能用在变量名中
非保留的也尽量不要用,血和泪的教训。
type = 1
type(1) #报错,此时等价于1(1)
值类型与引用类型
a = 1
b = a
a = 3 #a指向了新的int(3)
print(b) #1a = [1,2,3,4,5]
b = a
a[0] = '1' #a没有指向新的list,而是改变原来的list
print(b) #['1',2,3,4,5]
- 值类型:不可改变
int
、str
、tuple
引用类型:可改变
list
、set
、dict
#str不可变,id()得到地址,发现前后地址变了,说明不是在原地址上修改
b = 'hello'
b = b + 'python' #生成新的字符串,再赋值给b
print(b) #hellopython
list
和tuple
:
元组不可修改,能用元组就用元组 – 代码稳定性考虑
a = (1,2,3,[1,2,['a','b','c']])
a[2] = '3' #不可改变,报错
a[3][2][1] = '4' #可以改变,变为(1,2,3,[1,2,['a','4','c']])
运算符
算术运算符
+
,-
,*
,/
,//
整除,%
,**
指数(2**5 = 32
)
赋值运算符
- 先做运算再赋值
- python中没有自增自减运算
比较运算符
- 返回一个
bool
值
逻辑运算符
- 与、或、非
int
,float
中0
被认为是False
字符串中空字符串""
是False
列表中空的列表[]
被认为是Falseand
和or
的返回值 – 最后一个读到的内容
1 and 2
返回2,2 and 1
返回1 – 读到第二个数字才能判断
1 or 2
返回1 – 读到第一个1的时候就能判断了
成员运算符
in
,not in
- 字典类型判断的是
key
身份运算符
is
,is not
– 两个变量的身份是否相等
a = 1
b = 1.0
a == b #True
a is b #False
id()
查看他们的地址,地址相同身份相同 –is
比较的是地址
a = {1,2,3}
b = {2,1,3}
a == b #True, set无序
a is b #False, 地址不同
判断变量的值、身份、类型 – 对象3特征
==
值
is
身份
isinstance(a, int)
类型isinstance(a, (int, str, float))
a是否是元组里三个类型中的一个,是返回True,否返回False
位运算符
b = 3
bin(b) #'0b11',3
bin(~b) #'-0b100',前面取负末位+1,-4
a = 2
bin(a) #'0b10'
bin(a<<1) #'0b100'
bin(a>>3) #'0b0'
分支、循环、条件和枚举
返回
表达式
什么是表达式
表达式是运算符和操作数组成的序列
表达式优先级
- 一般右结合,出现
=
左结合,与运算符优先级无关 - 运算符优先级最高,然后是比较,逻辑运算符最低:
not > and > or
- 加辅助括号可以改变运算顺序
流程控制语句
条件控制
if d:a = input() #读入的是字符串pass #空语句,占位语句
elif:pass
else:pass
pylint规范
- python中实际没有常量,用大写
- 每个模块开头一段注释,说明
- tab 四个空格、切换到下一个代码编辑区域
- python没有
switch
elif
代替,或者字典处理 - a,b不同时为False:
a or b
循环
while的循环场景
- 递归
counter = 1
while counter <= 10:counter += 1print(counter)
else:print('EOF') #循环结束的时候执行else
for
for target_list in expression_list:pass
else:pass #列表全部打完以后执行else,强制break结束时不会执行else
range
for x in range(0, 10, 2): #范围,步长pass
for x in range(10, 0, -2):printf(x, end=' | ')一定要用for吗?
a = [1,2,3,4,5,6,7,8]
for i in range(0, len(a), 2):print(a[i], end=' | ')
b = a[0:len(a):2]
print(b)
python的组织结构-包、模块、类
返回
- 包(文件夹,包含
__init__.py
),模块,类(用类把函数、变量组织起来)
包.模块seven.c4
,子包 __init__.py
的模块名就是包的名字
导入
import c7 #同级,导入模块
print(c7.a)import t.c7 #子包中
print(t.c7.a)from t.c7 import a, def #导入变量、函数
print(a)from t import c7 #导入模块
print(c7.a)from t.c7 import * #导入所有变量和函数,能不用就不用
__all__ = ['a', 'c']
#在模块开头,改变*关于全部的定义
#模块的内置属性#末尾加反斜杠可以换行, ()也可以换行
from c7 import a, b\
c
from c7 import (a, b
c)
init.py
- 导入包时自动运行:
无论是导入包还是导入包下面的模块,都会自动运行__init__.py
- 在
__init__.py
内设置__all__
可以控制*
时导入的包内模块 - 批量导入包
- 注意点:
① 包和模块不会被重复导入
② 避免循环导入
③ python导入模块时会执行所导入模块的代码
模块内置变量
dir()
返回当前模块的变量列表
dir(sys)
返回指定模块sys
的变量列表- 错误信息:堆栈信息(路径)+详细信息(原因)
__doc__
存放模块注释信息
__file__
存放文件路径
入口文件和普通模块内置变量的区别
print('package: ' + (__package__ or 当前模块不属于任何包)) #当前模块不属于任何包
print('name: ' + __name__) #__main__
print('doc: ' + (__package__ or 当前模块没有文档注释))
print('file: ' + __file__) #文件名c9.py
__name__的经典应用
if __name == '__main__':pass #作为可执行文件时才会执行
#Make a script both importable and executabl
python -m seven.c15
把c15按模块执行,命名空间(?)
python seven\c15.py
路径方式
相对导入和绝对导入
- 决定顶级包的是可执行文件
package2.package4
,demo不是顶级包 - 绝对导入必须从顶级包开始
- 相对路径:
.表示当前目录
…表示上层目录
…表示上上层目录 - 入口文件不能使用相对路径
因为入口文件的__name__
被设置成__main__
无法作为路径使用
一定要在路口文件使用相对路径:
回到demo的上一级,python -m demo.main
,此时相对导入可用,输出demo.package2.package4
- 相对导入
from .m3 import m
from ...m5 import m
# attempted relative import beyond top-level package
Python 函数
返回
函数
round(a, 2)
保留小数点后两位,同时四舍五入help(round)
查看内置函数import this
打印python之禅- 特点:功能性、隐藏细节、避免编写重复的代码
函数的定义和运行特点
def funcname(parameter_list):pass
#1. 参数列表可以没有
#2. return value None
[Previous line repeated 995 more times]
递归超过995次
import sys
sys.setrecursionlimit(100)
#设置最大递归层数
#[Previous line repeated 95 more times]
返回多个结果
def damage(skill1, skill2):damage1 = skill1 * 3damage2 = skill2 * 2return damage1, damage2skill1_damage, skill2_damage = damage(3, 4)
#用两个变量(有意义的变量名)存放两个返回值
#序列解包
序列解包
d = 1, 2, 3
print(type(d)) #tuplea, b, c = d #序列解包
a, b = [1, 2, 3] #报错,用两个变量接收三个值a=b=c=1 #连续赋值√
参数
必须参数与关键字参数
- 必须参数:
c = add(3, 2)
- 关键字参数:
c = add(y=3, x=2)
,不用固定实参的输入顺序 - 备注:
① 二者的差别在函数的调用上,不在定义上
② 定义了多少形参就要传入多少实参
默认参数
- 定义的时候给形参默认值
- 调用时正常传递实参即可按顺序覆盖,没有默认值的形参必须传入实参
- 必须传入的参数必须放在默认参数前面
print_student('lxxx', age=17)
可以不按参数列表顺序传入改变默认值- 默认值参数和必须参数不能混着调用
print_student('lxxx', gender='nv', 17, college='xx')
可变参数/形参列表可变
def demo(*param):print(param) print(type(param)) #tupledemo(1,2,3,4,5,6)a = (1,2,3,4,5)
demo(a) #报错,传递进入的是一个元组
demo(*a) #√ 类似解包,传入的是可变参数def demo(param1, param2=2, *param):print(param1) print(param2)print(param)demo('a', 1,2,3)
#a
#1 默认值参数在前,读完才读可变参数
#(2,3)def demo(param1, *param, param2=2):print(param1) print(param2)print(param)demo('a', 1,2,3, 'param')
#a
#(1,2,3,'param') 可变参数会把剩余全部传入可变
#2demo('a', 1,2,3, param2='param')
#a
#(1,2,3)
#param
尽量保证形参列表的简单
关键字可变参数/任意个数的关键字参数
def city_temp(**param)print(type(param)) #dictfor key,value in param.items():print(key, ':', value)print(param)a = {'bj':'32c', 'sh':'31c'}
city_temp(**a)
city_temp() #{}
作用域
变量作用域
c = 50 #全局变量
def demo():c = 10 #局部变量print(c) #10def demo1():print(c) #50demo()
print(c) #50def demo2():for i in range(0,9):a += iptint(a) #python没有块级变量的概念
作用域链
c = 1
def func1():c = 2def func2():c = 3print(c)func1() #3 2 1
global关键字
def demo():global cc = 2demo()
print(c)
- 全局变量在整个程序里面都能用
小作业1-合成石头划算不
要求
代码
stone.py
'''
this is about class stone
'''class Stone():level = 1value = 0l1_diamond = 8l1_value = 0.75up_num = 12up_gold = 0.39up_vit = 10up_rate = 1def l1_to_l3(self):self.value += 13*self.l1_valueself.value += 13*self.l1_diamond*0.05self.value += self.up_goldself.value += self.up_vit*1self.level = 3self.up_gold = 0.897self.up_vit = 10self.up_rate = 0.4878def l3_to_l4(self):temp_sum = 0temp_sum += 16*self.l1_valuetemp_sum += 16*self.l1_diamond*0.05temp_sum += self.up_goldtemp_sum += self.up_vit*1self.value += temp_sum*self.up_ratetemp_sum = 0temp_sum += 16*self.l1_valuetemp_sum += 16*self.l1_diamond*0.05temp_sum += self.up_goldself.value += temp_sum*(1-self.up_rate)self.level = 4self.up_gold = 19.75self.up_vit = 10self.up_rate = 1def l4_to_l6(self):self.value += 12*self.valueself.value += self.up_goldself.value += self.up_vit*1
main.py
from stone import Stones1 = Stone()
s1.l1_to_l3()
s1.l3_to_l4()
s1.l4_to_l6()
composite_value = s1.value
buy_value = 750
print('composite value is ' + str(composite_value))
if composite_value<buy_value:print('It\'s more cost-effective to synthesize yourself.')
else:print('Buying directly is more cost-effective.')
结果
面向对象
返回
类
- 有意义的面向对象的代码
定义
- 首字母大写,不要用下划线连接
- 类只负责描述定义,不负责执行=类内不能运行调用这个类
一个模块专门用来定义类,调用写进另外的模块 - 类最基本的作用:封装
class Student(): name = ''age = 0def print_file(self): #即使不需要调用任何参数还是要在定义的时候加入selfprint('name:' + self.name)print('age:' + str(self.age))#实例化
student = Student()
student.print_file() #调用类下面的方法
- 方法与函数的区别
方法:设计层面
函数:程序运行的过程式
类和对象的关系
- 实例化
- 类的设计:行为与特征
- 类是模板,可以产生很多不同的对象
构造函数
- 实例化的过程中会自动调用构造函数,一般不显示调用构造函数
- 构造函数不能返回除了None以外的值(也不是用来返回什么东西的)
- 构造函数的作用,让模板生成不同的对象
类变量、实例变量、self
class Student():name = 'qiyue' #类变量age = 0def __init__(self, name, age): #添加参数以后必须要传入参数self.name = name self.age = ageprint('student') #实例变量student1 = Student('石敢当', 18)
student2 = Student() #报错
print(student1.name) #石敢当
print(Sturent.name) #qiyue
- 为什么要写self,显胜于隐
实例方法、类方法、静态方法
- 实例方法:
def do_homework(self):
实例可以调用的方法,操作实例变量 - 在实例方法里面访问类变量
print(Student.sum1)
print(self.__class__.sum1)
不能直接用变量名访问类变量
'''
实例方法调用类变量
'''
class Student():name = ''age = 0sum_s = 0def __init__(self, name, age)self.name = nameself.age = age#self.__class__.sum_s += 1#print('当前学生总数为:' + str(self.__class__.sum_s))'''
定义类方法
'''@classmethoddef plus_sum(cls)cls.sum_s += 1print(cls.sum_s)'''
定义静态方法
'''@staticmethoddef add(x,y):print('This is a static method')s1 = Student('石敢当', 18) #当前学生总数为:1
Student.plus_sum()
s2 = Student('喜小乐', 16) #当前学生总数为:2
Student.plus_sum()
s1.plus_sum() #python中实例对象可以调用类方法,但是不建议这么干!
s1.add(1,2)
Student.add(1,2)
- 静态方法和面向对象关系很弱,像一个普通函数,一般不推荐使用
成员可见性
- 成员:变量和方法
- 类有内外之分
def do_homework(self):self.do_english_homework() #内部调用print('homework')def do_english_homework(self):print('english homework')s1 = Student('石敢当', 18)
s1.do_homework() #外部调用
- 提倡的规范:
所有类下变量的更改都通过方法操作(对数据保护,避免不规范操作)
公开和私有
- 公开的 public:可以在外部直接调用
私有的 private:外部无法直接读取/设置 - python怎么判断公开还是私有?
方法在开头加双下划线__
,变为私有
为什么__init__
可以在外部调用?因为它后面也有下划线!这是python内置函数的命名风格
没有什么是不可以访问的!
s1 = Student('石敢当', 18)
s2 = Student('喜小乐', 16)
s1.__score = -1 #给实例对象创建了一个新的属性并赋值,不是给私有成员赋值
print(s1.__score) #-1
print(s2.__score) #报错
print(s1.__dict__) #打印变量
#{'name':'石敢当', 'age':18, '_Student__score':59, '__score':-1}
print(s1._Student__score) #成功读取!但是没什么意义不建议这么玩
面向对象三大特性
- 继承性、封装性(抽象程度高)、多态性
继承性
- 避免定义重复的方法、重复的变量
from c6 import Human
'''
class Human():sum = 0def __init__(self, name, age):self.name = nameself.age = agedef get_name(self):print(self.name)
'''
class Student(Human):passprint(Student.sum) #0,从Human里面继承的
s1 = Student('石敢当', 18)
print(s1.name) #以下都可以继承
print(s1.age)
s1.getname()
- 单继承。Python允许多继承,单继承都没用好请别用多继承
def __init__(self, school, name, age):self.school = schoolHuman.__init__(self, name, age) #显式调用#为什么不传入self会报错?#类调用了实例方法,就是一个普通方法的调用,参数要传全#s1 = Student() python内部实例化机制自动帮我们调用,会补全self#对比s1.do_homewor()也不需要self,实例调用实例方法#强行需要用类调用:Student.do_homework(s1)#不建议这么干没得意义,Student.do_homework('')都可以,只要传一个参数进入就行super(Student, self).__init__(name, age)#更改父类时只需要在定义类后面的括号里修改父类名称即可
- 子类与父类方法同名
'''def do_homework(self):print('This is a parent method')
'''def do_homework(self):super(Student, self).do_homework() #1print('english homework')s1 = Student('人民路小学', '石敢当', 18)
s1.do_homework() #english homework
#1 This is a parent method
#1 english homework
正则表达式与JSON
返回
- 正则表达式是一个特殊的字符序列,检测一个字符串是否与我们所设定的字符序列相匹配,实现快速检索文本、替换文本的操作。
① 检查一串数字是否是电话号码
② 检测一个字符串是否符合E-mail
③ 把文本里指定的单词替换为另一个单词
import re
#几乎没有意义的常量表达式,没有体现出匹配的优势
#正则表达式的灵魂在于:规则!
a = 'C|C++|Java|C#|Python|Javascript'
r = re.findall('Python', a) #'正则表达式'
if len(r) > 0:print('字符串中包含Python')
元字符
元字符与普通字符
import re
#找a中的所有数字
a = 'C0C++7Java8C#9Python6Javascript'
r = re.findall('\d', a) #\d匹配一个数字符,元字符
#\D匹配所有非数字符
print(r)
#['0','7','8','9','6']
正则表达式匹配的是字符
菜鸟教程–元字符列表
字符集
import re
#找s中找出中间字符是c或者f的单词
s = 'abc,acc,adc,aec,afc,ahc'
r = re.findall('a[cf]c', s) #普通字符+字符集
print(r)
#[acc','afc']
r = re.findall('a[^cfd]c', s) #取反操作
print(r)
#['abc','aec','ahc']
r = re.findall('a[c-f]c', s) #取范围
print(r)
#['acc','adc','aec','afc']
- 普通字符用于辅助定界
- 出现在字符集里面的字符之间是或关系
概括字符集
\d
=[0-9]
,\D
=[^0-9]
\w
=[A-Za-z0-9_]
匹配数字、字母、下划线,\W
['p','y','t','h','o','n']
,[' ','&','\n','\r','\t']
\s
[' ','\n','\r','\t']
–空白字符.
匹配除了换行符以外的所有符号
数量词
a = 'python 1111java678ph'
r = re.findall('[a-z]', a)
print(r) #单个字母的序列
r = re.findall('[a-z][a-z][a-z]', a) #连续匹配3位字符
print(r) #['pyt','hon','jav','php']
r = re.findall('[a-z]{3}', a)
print(r) #['pyt','hon','jav','php']
r = re.findall('[a-z]{3,6}', a) #字符位数范围3-6
print(r) #['python','java','php']
贪婪和非贪婪
- python默认贪婪的匹配方式,一直匹配到某个字符不满足他的要求
r = re.findall('[a-z]{3,6}?', a) #非贪婪
print(r) #['pyt','hon','jav','php']
匹配0次1次或者无限次
*
匹配*前面的字符0次或者无限多次+
匹配*前面的字符1次或者无限多次?
匹配*前面的字符0次或者1次
a = 'pytho0python1pythonn2'
r = re.findall('python*', a)
print(r)
#['pytho','python','pythonn'] #n符合*匹配0次
r = re.findall('python+', a)
print(r)
#['python','pythonn'] #n符合*匹配0次
r = re.findall('python?', a)
print(r)
#['pytho','python','python'] #多出来的次数n会被去掉
?
可以用来去重
边界匹配
^
从字符串的开头开始匹配$
从字符串的末尾开始匹配
qq = '100000001'
r = re.findall('\d{4,8}', qq)
print(r) #['10000000'],在表达式里面寻找,并不完整的匹配字符串
r = re.findall('^\d{4,8}$', qq)
print(r) #[],完整匹配了字符串
r = re.findall('000', qq)
print(r) #['000','000']
r = re.findall('^000', qq)
print(r) #[]
r = re.findall('000$', qq) #最后三个字符得是000
print(r) #[]
组
import re
s = 'pythonpythonpythonpythonpythonpython'
r = re.findall('pythonpythonpython', s)
print(r)
#['pythonpythonpython', 'pythonpythonpython']
r = re.findall('python{3}', s)
print(r)
#[],只能匹配单个字符出现的次数
r = re.findall('(python){3}', s)
print(r)
#['python', 'python'] ????
r = re.findall('(python){3}[JS]', s)
print(r)
#[]
匹配模式参数
re.I
表示匹配忽视字母大小写re.S
表示.
匹配所有符号,包括\n
import re
lanuage = 'PythonC#\nJavaPHP'
r = re.findall('c#', lanuage, re.I) #匹配忽视大小写
print(r) #['C#']
r = re.findall('c#.{1}', lanuage, re.I) #匹配c#和任意一个字符
print(r) #[],.不支持\n
r = re.findall('c#.{1}', lanuage, re.I | re.S)
print(r) #['C#\n']
re模块下的其他函数
re.sub正则替换
import re
lanuage = 'PythonC#Java'
lanuage1 = 'PythonC#JavaC#PHPC#'
r = re.findall('C#', 'GO', lanuage)
print(r) #PythonGOJava
r = re.findall('C#', 'GO', lanuage1, 0) #所有符号的都会被替换
print(r) #PythonGOJavaGOPHPGO
r = re.findall('C#', 'GO', lanuage1, 1) #符合条件的字符替换的最大次数1
print(r) #PythonGOJavaC#PHPC#lanuage1 = lanuage1.replace('C#', 'GO') #内置函数实现替换
print(lanuage1) #PythonGOJavaGOPHPGO
- sub()的第二个参数可以是函数
lanuage1 = 'PythonC#JavaC#PHPC#'
def conver(value): #传入值是C#/非字符串,返回值会替代C#passdef conver1(value):print(value)#<_sre.SRE_Match object; span=(6, 8), match='C#'>,之前偶6个字符,占用的是7和8#<_sre.SRE_Match object; span=(12, 14), match='C#'>#<_sre.SRE_Match object; span=(17, 19), match='C#'>#如何拿到c#?matched = value.group() #表示匹配的字符串return '!!' + matched + '!!'r = r.sub('C#', convert, lanuage1)
print(r)
#PythonJavaPHP,因为返回值是空
r = r.sub('C#', convert1, lanuage1) #c#被动态的替换
print(r)
#Python!!C#!!Java!!C#!!PHP!!C#!!
- 把函数作为参数传入的作用
s = 'A8C3721D86'def convert(value):matched = value.group()if (int)matched >= 6:return '9'else:return '0'r = re.sub('\d', convert, s)
print(r) #A9C0900D99
search和match
match()
从首字母开始匹配,首字母没有就返回空search()
搜索字符串,一旦找到第一个就会返回- 两者匹配成功立刻停止搜索,
findall()
会匹配所有符合的结果
import re
s = 'A83C72D1D8E67'
r = re.match('\d', s)
print(r) #None
r = re.search('\d', s)
print(r) #<_sre.SRE_Match object; span=(0, 1), match='8'>
s = '83C72D1D8E67'
r = re.match('\d', s)
print(r) #<_sre.SRE_Match object; span=(0, 1), match='8'>
print(r.span())
print(r.group()) #8
group分组
#匹配life和python中间的内容
s = 'life is short,i use python'
r = re.search('(life.*python)', s)
print(r.group(0)) #life is short,i use python只有一个组
r = re.search('life(.*)python', s)
print(r.group(0)) #life is short,i use python,第一组存放整体
print(r.group(1)) # is short,i use
r = re.findall('life(.*)python', s)
print(r) #[' is short,i use ']s = 'life is short, i use python, i love python'
r = re.findall('life(.*)python(.*)python', s)
print(r.group(0)) #life is short, i use python, i love python
print(r.group(1)) # is short,i use
print(r.group(2)) #, i love
print(r.group(0,1,2))
#('life is short, i use python, i love python', ' is short,i use ', ', i love ') 用元组返回
print(r.groups())
#(' is short, i use ', ', i love ') 不会返回完整的,只会返回匹配的部分
正则表达式的学习建议
- 完成内置函数无法完成的字符串相关问题
- 常用的qq号,电话号码,email的匹配,可以直接用别人写好的提高效率,分析一下别人怎么写的(学习角度)
- 避免过度依赖内置函数,有意识的多用正则表达式
JSON
- JavaScript Object Notation–JavaScript对象标记
- 是一种轻量级的数据交换格式
- 字符串是JSON的表示形式
- 符合JSON格式的字符串叫JSON字符串
{"name":"qiyue"}
- 优势:易于阅读、解析,网络传输效率高,适合用于跨语言交换数据
反序列化
- 由字符串到某种语言上的数据结构–反序列化
json_str = '{"name":"qiyue", "age":18}'
#json格式字符串必须用双引号,因此python里外层就要用单引号
student = json.loads(json_str)
#把json字符串格式转化成python能接受的数据结构
print(type(student)) #dict
print(student) #{'name':'qiyue', 'age':18}字典
print(student['name']) #qiyue
print(student['age']) #18#JSON object array
json_str = '[{"name":"qiyue", "age":18}, {"name":"qiyue", "age":18}]'
student = json.loads(json_str)
print(type(student)) #list
print(student) #[{'name':'qiyue', 'age':18}, {'name':'qiyue', 'age':18}]json_str = '[{"name":"qiyue", "age":18, "flag":false}, {"name":"qiyue", "age":18}]'
student = json.loads(json_str)
print(student) #[{'name':'qiyue', 'age':18, 'flag':False}, {'name':'qiyue', 'age':18}]
序列化
- python数据类型向JSON字符串转换的过程
json | python |
---|---|
object | dict |
array | list |
string | str |
number | int |
number | float |
true | True |
false | False |
null | None |
import json
student = [{'name':'qiyue', 'age':18, 'flag':False},{'name':'qiyue', 'age':18}]
json_str = json.dumps(student)
print(type(json_str)) #str
print(json_str)
#[{"name":"qiyue", "age":18, "flag":false}, {"name":"qiyue", "age":18}]
- 调用服务拿到字符串(JSON)进python处理
JSON/JSON对象/JSON字符串
- JSON:是一种轻量级的数据交换格式
- JSON字符串:符合JSON格式的字符串叫JSON字符串
- JSON对象:JavaScript里的说法
- JSON数据类型:中间数据类型/语言格式
- JSON是REST服务的标准格式
Python高级语法与用法
返回
枚举
枚举是个类啊!
form enum import Enumclass VIP(Enum):#常量大写,Python没有常量概念#枚举下的类型不易更改、不能重复--枚举类型的保护功能YELLOW = 1GREEN = 2BLACK = 3RED = 4print(VIP.YELLOW) #VIP.YELLOW,并不是1
- 枚举的意义所在,关注的是名字而不是数字,重在标签
相比普通类有什么优势
yellow = 1
green = 2{'yellow':1, 'green':2}class TypeDiamond():yellow = 1green = 2
- 缺陷:可变;没有防止相同值的功能
相关操作
- 取值
#访问对应取值
print(VIP.GREEN.value) #2
#访问标签名
print(VIP.GREEN.name) #GREEN
print(VIP.GREEN) #VIP.GREEN
print(type(VIP.GREEN.name)) #<class 'str'>
print(type(VIP.GREEN)) #<enum 'VIP'>
print(VIP['GREEN']) #VIP.GREEN,通过枚举名称获得枚举类型
- 遍历
for v in VIP:print(v)
#VIP.YELLOW
#VIP.GREEN
#VIP.BLACK
#VIP.RED
- 比较
class VIP1(Enum):YELLOW = 1GREEN = 2BLACK = 3RED = 4result = VIP.GREEN==2
print(result) #False
result = VIP.GREEN==VIP.GREEN
print(result) #Trueresult = VIP.GREEN>VIP.BLACK
print(result) #报错,枚举类型之间不支持大小比较,可以等值比较result = VIP.GREEN is VIP.GREEN
print(result) #身份的比较,Trueresult = VIP.GREEN==VIP1.GREEN
print(result) #False,两个不同的类,即使数值相同也不是一个枚举
枚举转换
- 在数据库里存储–用数字代表类型
- 编写代码时显示定义一个枚举类,用枚举类下的每一个枚举类型对应数据库中的每个数值
- 如何把数字和枚举类型对应起来?
a = 1
print(VIP(a)) #VIP.YELLOW
#使用数值访问具体的枚举类型的一种方案
注意事项
- 标签名不能相同,数值可以相同,但是!!
允许有两个类型数值相等,此时第二种可以看成是第一种的别名 - 遍历时不会打印别名
class VIP(Enum):YELLOW = 1GREEN = 1#YELLOW_ALIAS = 1BLACK = 3RED = 4print(VIP.GREEN) #VIP.YELLOWfor v in VIP:print(v)
#VIP.YELLOW
#VIP.BLACK
#VIP.REDfor v in VIP.__members__.items(): #内置变量属性__members__的items方法print(v)
#('YELLOW', <VIP.YELLOW: 1>)
#('GREEN', <VIP.YELLOW: 1>)
#('BLACK', <VIP.BLACK: 3>)
#('RED', <VIP.RED: 4>)for v in VIP.__members__:print(v)
#VIP.YELLOW
#VIP.GREEN
#VIP.BLACK
#VIP.RED
- IntEnum
from enum import Enum
from enum import IntEnum, unique@unique #装饰器
class VIP(IntEnum):YELLOW = 1YELLOW_A = 1GREEN = 'str'BLACK = 3RED = 4
#报错,IntEnum的赋值必须是整型,Enum不会对枚举的数值有限制
#报错,使用装饰器后不允许相同取值
- 枚举类型在python里面是单例模式,实例化没有意义
进阶–函数式编程
- 基础知识用来写出代码,高阶知识用来写出可复用的代码(包、类库)
尝试着写包和类库,体会高级语法的好处,实践出真知啊!
闭包
- Python一切皆对象
- 函数既可以作传入参数,又可以作返回结果
- 闭包:函数及其在定义时外部的环境变量(非全局),不会受重新复赋值的影响
def curve_pre():a = 25 def curve(x): return a*x*xreturn curvea = 10
f = curve_pre()
print(f(2)) #100
print(f.__closure__) #(<cell at 0x005E4250: int object at 0x5038D5B0>,)
print(f.__closure__[0].cell_contents) #25
- 经典误区
def f1():a = 10def f2():a = 20 #局部变量不影响外部环境变量print(a)print(a)f2()print(a)f1()
#不是闭包
- 小作业:计算旅行者的路径长度
#非闭包法
origin = 0def go(step):#global origin 使得该函数里面引用的origin位全局变量,不会报错new_pos = origin + step #报错,此时局部变量origin没有值origin = new_pos #定义时在左边出现的位局部变量return new_posprint(go(2)) #2
print(go(3)) #5
print(go(6)) #11
print(origin) #11,全局变量的值改变了#闭包方法
def factory(pos):def go(step):nonlocal pos #指定pos为非局部变量,优先取环境变量new_pos = pos + steppos = new_posreturn new_posreturn gof = factory(origin)
print(f(3)) #3
print(f(5)) #8
print(f(7)) #15
print(origin) #0,闭包方法调用函数不会改变全局变量
- 闭包特点:在模块层面简介调用函数内部的局部变量
函数式编程
返回
匿名函数
lambda表达式
- 定义时不需要定义它的函数名
lambda parameter_list: expression #表达式def add(x, y)return x+yprint(add(1,2)) #3
f = lambda x,y: x+y
print(f(1,2)) #3
f = lambda x,y: a = x+y #报错,冒号后面不能是代码块
三元表达式
- xy,x大于y则返回x,否则y
#x>y ? x : y
#条件为真时返回的结果 if 条件判断 else 条件为假时的返回结果
r = x if x>y else y
map(class)
list_x = [0,1,2,3,4,5,6,7,8,9]def square(x):return x*xfor x in list_x:square(x)r = map(square, list_x)
print(r) #<map object at 0x023D4A30>
print(type(r)) #<class 'map'>
print(list(r)) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],转化成列表
- map(函数, 元素集合):将元素按函数方法映射成新的元素集合
map 与 lambda
- 列表传入个数与lambda的参数列表个数相同
- 结果列表元素个数取决于传入列表中元素少的那个
r = map(lambda x: x*x, list_x)
print(list(r)) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],可阅读性比for循环更好list_x = [0,1,2,3,4,5,6,7,8,9]
list_y = [0,1,2,3,4,5,6,7,8,9]
r = map(lambda x, y: x*x + y, list_x, list_y) #可传入可变参数
print(list(r)) #[0, 2, 6, 12, 20, 30, 42, 56, 72, 90]list_y = [0,1,2,3,4,5,6]
r = map(lambda x, y: x*x + y, list_x, list_y)
print(list(r)) #[0, 2, 6, 12, 20, 30, 42]
高阶函数
reduce
from functools import reduce#连续计算,连续调用lambda
list_x = [0,1,2,3,4,5,6,7,8,9]
r = reduce(lambda x,y: x+y, list_x)
#取前两个元素,每次lambda运算的结果作为x送入后面的运算
print(r) #45list_x = ['0','1','2','3','4','5','6','7','8','9']
r = reduce(lambda x,y: x+y, list_x, 'aaa')
#初始值作为第一次运算的传入参数
print(r) #aaa0123456789
filter–过滤
- 帮助我们过滤掉不符合定义格式的元素
- 函数返回至为False
list_x = [1,0,1,0,0,1]
r = filter(lambda x: True if x==1 else False, list_x)
print(r) #<filter object at 0x006E4A10>
print(list(r)) #[1, 1, 1]
函数式编程vs命令式编程
- 命令式编程:def、if else、for
- 函数式编程:map、reduce、filter、lambda
- lisp居然是函数式编程的鼻祖!
装饰器
- 类此C#的特性,JAVA的注解
对修改是封闭的,对扩展是开放的
- 非装饰器方法
import timedef f1():print('This is a function')def f2(): #没有和新增的定义关联起来,依旧是一个独立函数print('This is a function')def print_current_time(func): #传入函数,保证函数时封闭的同时在每次调用函数前输出时间戳--新增功能print(time.time())func()print_current_time(f1)
print_current_time(f2)#和直接打印没有区别
print(time.time())
f1()
print(time.time())
f2()
- 装饰器方法–装饰器是一种模式
import timedef decorator(func): #装饰def wrapper(): #封装print(time.time())func()return wrapperdef f1():print('This is a function1')def f2():print('This is a function2')f = decorator(f1)
f()
python语法糖–甜、甜的?
- 语法糖: 真正体现装饰器功能的高光时刻!即没有改变函数内部实现,也没有改变函数的调用
- 可以接受定义时候的复杂,但是绝对不能接受调用时候的复杂!
import timedef decorator(func): #装饰def wrapper(): #封装print(time.time())func()return wrapper@decorator #真正体现装饰器功能的高光时刻!即没有改变函数内部实现,也没有改变函数的调用
def f1():print('This is a function1')def f2():print('This is a function2')f1() #保持原有的调用方式不变
- 如果函数带各种各样的参数呢?
import timedef decorator(func): #装饰def wrapper(*args): #封装print(time.time())func(*args) #通用意义的变量名?return wrapper@decorator
def f1(func_name):print('This is a function named ' + func_name)@decorator
def f2(func_name1, func_name2):print('This is a function named ' + func_name1)print('This is a function named ' + func_name2)f1('lizzy')
f2('lxxx1', 'lxxx2')
如何兼容通用关键字参数?
import timedef decorator(func): #装饰def wrapper(*args, **kw): #封装print(time.time())func(*args, **kw) #不管函数是怎么定义的,都可以用这个抽象的函数调用方式return wrapper@decorator
def f1(func_name):print('This is a function named ' + func_name)@decorator
def f2(func_name1, func_name2):print('This is a function named ' + func_name1)print('This is a function named ' + func_name2)@decorator
def f3(func_name1, func_name2, **kw): #关键字参数print('This is a function named ' + func_name1)print('This is a function named ' + func_name2)print(kw)f1('lizzy')
f2('lxxx1', 'lxxx2')
f3('test1', 'test2', a=1, b=2, c='123')'''
1587521895.7875009
This is a function named lizzy
1587521895.7885008
This is a function named lxxx1
This is a function named lxxx2
1587521895.7915008
This is a function named test1
This is a function named test2
{'a': 1, 'b': 2, 'c': '123'}
'''
func(*args, **kw)
不管函数是怎么定义的,都可以用这个抽象的函数调用方式
装饰器小结
- 装饰器优势
① 代码的稳定性角度:对被封装的单元做出修改–通过装饰器改变函数的行为
② 代码的复用性角度:语法糖
实战:原生爬虫
返回
- 爬虫的目的性要明确
整理爬虫的常规思路
- 鼠标右键–检查:开html信息
- 点击信息框左上角的小箭头
点击页面中需要的信息–自动定位到html信息中所属的代码段 - 数据提取层级分析:精准选取定位标签,选闭合的父级别标签,尽量不要选兄弟标签
- 正则分析
- 数据精炼
- 数据处理(分析完成你的需求)
错误
- UnicodeDecodeError ‘utf-8’ codec can’t decode byte 0x8b in position 1: invalid start byte报错分析
- StringIO和BytesIO–廖雪峰
- gizp模块介绍–python文档
① 报错代码
from urllib import requestclass Spilder():url = 'https://www.douyu.com/g_jdqs'def __fetch_content(self):r = request.urlopen(Spilder.url)htmls = r.read()htmls = str(htmls, encoding='utf-8') #报错,将htmls按utf-8编码def go(self):self.__fetch_content()s = Spilder()
s.go()
② 调试代码
from urllib import request
from io import BytesIO #BytesIO实现在内存中读写bytes
import gzip #压缩与解压缩的模块class Spider():url = 'https://www.douyu.com/g_jdqs'def __fetch_content(self):r = request.urlopen(Spider.url)htmls = r.read()#print(type(htmls)) <class 'bytes'>buff = BytesIO(htmls) #写入的不是str,而是经过UTF-8编码的bytes,即用一个bytes初始化BytesIO#print(type(buff)) <class '_io.BytesIO'>f = gzip.GzipFile(fileobj=buff) #将BytesIO对象解压缩成GzipFile对象fprint(type(f)) #<class 'gzip.GzipFile'>htmls = f.read().decode('utf-8') #读取f中的字节数据并按utf-8解码为strprint(type(htmls)) #<class 'str'>a = 1def go(self):self.__fetch_content()s = Spider()
s.go()
③ 修改代码
from urllib import request
from io import BytesIO
import gzipclass Spider():url = 'https://www.douyu.com/g_jdqs'def __fetch_content(self):r = request.urlopen(Spider.url)htmls = r.read()buff = BytesIO(htmls)f = gzip.GzipFile(fileobj=buff)htmls = f.read().decode('utf-8')a = 1def go(self):self.__fetch_content()s = Spider()
s.go()
- 我跳票了我去爬B站学习直播区了再见斗鱼!
from urllib import request
from io import BytesIO
import gzipclass Spider():url = 'https://live.bilibili.com/p/eden/area-tags?parentAreaId=1&areaId=27&visit_id=4tmkk5fiu6m'def __fetch_content(self):r = request.urlopen(Spider.url)htmls = r.read()htmls = str(htmls, encoding = 'utf-8')return htmlsdef __analysis(self, htmls):passdef go(self):htmls = self.__fetch_content()self.__analysis(htmls)s = Spider()
s.go()
- anomalous backslash in string: ‘\s’. string constant might be missing an r prefix.
问题:\s
首先被认为是转义字符,在正则中多加一个\
解决:([\\s\\S]*?)
加一个反斜杠 root_info
提取不到信息:页面显示的数据格式和抓取的数据格式有出入,根据抓取到的数据修改正则表达式
代码规范
- 模块、类、方法:块注释,内部首部多行
- 语句注释:在上面,注释上空行
- 不要滥用空行,不要在一个函数里面写多行代码(函数越小越灵活复用性越高,10-20行,最多30行)
- 写出来也要写好
- 爬虫扩展:BeautifulSoup、Scrapy等框架;爬虫、反爬虫、反反爬虫;ip如果被封了–代理ip库
实现代码
- main.py
from spider import Spiderspider1 = Spider()
spider1.go()
- spider.py
from urllib import request
import reclass Spider():'''一个爬虫类。属性:url连接地址父集信息匹配格式root_pattern名字、人气信息的匹配格式name_pattern、number_pattern方法:外部接口go()获取页面内容__fetch_content(self)对页面内容分析提取所需信息__analysis(self, htmls)对数据提炼__refine(self, anchors)排序__sort(self, anchors)与排序规则__sort_seed(self, anchor)展示__show(self, anchors)'''__url = 'https://live.bilibili.com/p/eden/area-tags?parentAreaId=1&areaId=27&visit_id=4tmkk5fiu6m'__root_pattern = '<div class="room-anchor card-text p-relative" data-v-191d6a08>([\\s\\S]*?)</div>'__name_pattern = '<span title="([\\s\\S]*?)" data-v-191d6a08>'__number_pattern = '<span class="v-middle" data-v-191d6a08>([\\s\\S]*?)</span>'#页面显示的信息:<div data-v-191d6a08="" class="room-anchor card-text p-relative"><span data-v-191d6a08="" title="丸乌咪">丸乌咪</span><div data-v-191d6a08="" class="popular-ctnr p-absolute"><i data-v-191d6a08="" class="icon-font icon-popular v-middle dp-i-block"></i><span data-v-191d6a08="" class="v-middle">2460</span></div></div>#实际抓取的信息:<div class="room-anchor card-text p-relative" data-v-191d6a08><span title="padango" data-v-191d6a08>padango</span><div class="popular-ctnr p-absolute" data-v-191d6a08><i class="icon-font icon-popular v-middle dp-i-block" data-v-191d6a08></i><span class="v-middle" data-v-191d6a08>3199</span></div></div></div></div>def __fetch_content(self):'''获取页面的内容'''r = request.urlopen(Spider.__url)htmls = r.read()htmls = str(htmls, encoding = 'utf-8')return htmlsdef __analysis(self, htmls):'''从提取的页面内容中匹配所需信息'''root_info = re.findall(Spider.__root_pattern, htmls)anchors = []for info in root_info:name = re.findall(Spider.__name_pattern, info)number = re.findall(Spider.__number_pattern, info)anchor = {'name':name, 'number':number}anchors.append(anchor)return anchorsdef __refine(self, anchors):'''数据精炼,转化成易于处理的格式'''l = lambda anchor:{#strip()删除多余的换行和空格'name':anchor['name'][0].strip(),'number':anchor['number'][0]}return map(l, anchors)def __sort(self, anchors):'''对数据排序'''#字典不支持比较,要取可以个支持比较的元素#sorted()默认从小到大,reverse=True从大到小anchors = sorted(anchors, key=self.__sort_seed, reverse=True)return anchorsdef __sort_seed(self, anchor):'''排序规则'''r = re.findall('\\d*', anchor['number'])number = float(r[0])if '万' in anchor['number']:number *= 10000return numberdef __show(self, anchors):'''数据展示'''for rank in range(0, len(anchors)):print('rank ' + str(rank+1)+ ':' + anchors[rank]['name']+ ' ' + anchors[rank]['number'])def go(self):'''作为接口供外部调用的方法'''htmls = self.__fetch_content()anchors = self.__analysis(htmls)anchors = list(self.__refine(anchors))anchors = self.__sort(anchors)self.__show(anchors)
存在的问题与改进方向
- 动态加载的页面只能读取30条信息–如何读取动态页面?
- 如何使程序间隔xx时间重复爬取更新信息
- 图形界面数据展示
- 获得的数据还能做哪些方向的分析……?
Pythonic与Python杂记
返回
用字典代替switch
switcher = {0 : 'Sunday',1 : 'Monday',2 : 'Tuesday'
}day = 2
day_name = switcher[day]
print(day_name)day = 6
day_name = switcher[day]
print(day_name) #报错,6不存在
#get()方法有容错性
day_name = switcher.get(day, 'Unknown') #找不到时返回Unknown
print(day_name)
- 字典内部对应为函数(实现一个分支多个语句)
def get_sunday():return 'Sunday'def get_monday():return 'Monday'def get_tuesday():return 'Tuesday'def get_default():return 'It\'s false.'switcher = {0 : get_sunday,1 : get_monday,2 : get_tuesday
}day = 6;
day_name = switcher.get(day, get_default)()
print(day_name)
列表推导式
a = [1,2,3,4,5,6,7,8]#map实现
b = map(lambda i: i*i, a)
print(list(b))#列表推导式实现
b = [i*i for i in a]
print(b)
#[1, 4, 9, 16, 25, 36, 49, 64]
b = [i**3 for i in a]
print(b)
#[1, 8, 27, 64, 125, 216, 343, 512]
- 推荐:有选择性的筛选运算的场合
a = {1,2,3,4,5,6,7,8}
b = [i**2 for i in a if i>=5]
print(b)
#[25, 36, 49, 64]
b = {i**2 for i in a if i>=5}
print(b)
#{64, 25, 36, 49}
- 列表、字典、元组、集合都可以用
- 字典如何编写列表推导式
students = {'喜小乐': 18,'石敢当': 20,'横小五': 15
}b = [key for key,value in students.items()]
print(b)
#['喜小乐', '石敢当', '横小五']
b = {value:key for key,value in students.items()}
print(b)
#{18: '喜小乐', 20: '石敢当', 15: '横小五'}#元组不可变,操作受限
b = (key for key,value in students.items())
print(b)
#<generator object <genexpr> at 0x0059A5A0>
for x in b:print(x)
"""
喜小乐
石敢当
横小五
"""
iterator与generator
- 可迭代对象(凡是可以被for in遍历的),迭代器
- 可迭代对象不一定是迭代器(列表元组字典),迭代器一定是可迭代对象
- 如何让自定义的class可以被遍历?–迭代器。
class Book:passclass BookCollection:def __init__(self):self.data = ['《往事》', '《只能》', '《回味》']self.cur = 0def __iter__(self):return self#for in调用nextdef __next__(self):if self.cur >= len(self.data):raise StopIteration()r = self.data[self.cur]self.cur += 1return rbooks = BookCollection()
#迭代器一次性
for book in books:print(book)
#迭代器异常
for book in books:print(book)print(next(books))
print(next(books))
print(next(books))
#迭代器异常
print(next(books))
- 如何迭代两次?
books = BookCollection()
import copy
#浅拷贝
books_copy = copy.copy(books)
#迭代器一次性
for book in books:print(book)
for book in books_copy:print(book)
- 生成器–yield的用法
def gen(max):n = 0while n<=max:#print(n),我们想要的是0-10000的返回值,而不是直接在函数内处理#接着上次执行的结果继续执行下去yield nn += 1g = gen(10000)
for i in g:print(i)
None
- 无论是从【类型】还是【值】上面来讲,【None】都不等于【空字符串、空列表,0,False】
print(type(None))
#<class 'NoneType'>
not a
和a is None
等同吗?
def fun():return None
a = fun()
if not a:print('S')
else:print('F')
#S
if a is None:print('S')
else:print('F')
#Sa = []
if not a:print('S')
else:print('F')
#S
if a is None:print('S')
else:print('F')
#F
- 推荐的判空操作:
if a:
if not a:
不要用None
来进行判空操作
对象存在不一定是True
- None永远对应False
- 自定义的对象和True和False是怎么对应的?
class Test():passtest = Test()
if test:print('S') #S,不存在len和bool时默认trueclass Test1():def __len__(self):return 0test = Test1()
if test:print('S')
else:print('F') #F
__len__
与__bool__
内置方法
class Test():def __len__(self):return 8#只能返回int,'8'会报错,'1.0'也会报错,bool可以print(len(Test())) #8
print(bool(Test())) #True,没有bool方法就看len方法class Test1():def __bool__(self):return False #0报错,强制要bool类型def __len__(self):return 8print(len(Test1())) #8
print(bool(Test1())) #False
#加入__bool__以后bool取值不再看len
我!结!课!了!
Python语法--Mooc七月相关推荐
- Python 语法小知识
为什么80%的码农都做不了架构师?>>> 序列解包 将含有多个值的序列解开,然后把值存放到变量中,当函数或者方法返回元组时这个特性很有用,可以把返回的序列值直接赋值 ...
- python语法书籍推荐_python语法的书
广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 四大基本语法分别从变量命名规则.缩进原则.特殊关键字和特殊运算符四个方面,总结 ...
- python身份运算符的语法规则_7 Python语法入门之与用户交互、运算符
本文对应的视频讲解如下: 与用户交互:python快速入门(一)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibiliwww.bilibili.com 一 程序与用户交互 1.1.什么是与用户交互 用 ...
- python语法错误概述_python语法错误
广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 我是python中的新手,当我想在模块中编译代码时,我遇到语法错误:invail ...
- 人工智能实践:TensorFlow笔记学习(二)—— Python语法串讲
Python语法串讲 大纲 2.1 Linux指令.HelloWorld 2.2 列表.元组.字典 2.3 条件语句 2.4 循环语句 2.5 turtle模块 2.6 函数.模块.包 2.7 类. ...
- python【数据结构与算法】Python语法查询大宝剑(全)
最近发现自己语法基础捉急,从来没有系统学过python语法. 所以更新一份python基础语法查询大宝剑. 文章目录 1 标准库 1.1 math和cmath 1.2 string 1.3 rando ...
- python基本语法语句-python 语法基础篇 一
安装篇 编辑篇: 编辑python 一 : 在终端环境下输入python命令,回车键运行.这种方式称为 交互方式. 1️⃣ 打开终端: 2️⃣ 输入python 回车 3️⃣ 输入python 语法 ...
- python语法手册-python语法手册
广告关闭 腾讯云双11爆品提前享,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高满返5000元! 常用的也不超过十个,这种相对于更为复杂的html标记语言来说,markdown可谓 ...
- python语法教程-Python语法教程总结规范
Python语法易错点记录 本文提供全流程,中文翻译. Chinar坚持将简单的生活方式,带给世人! (拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar-- 心分享.心 ...
最新文章
- asp.net 2.0中设定默认焦点按钮
- java中 private final_Java笔记:final与private关键字
- 总结 | “卷积”其实没那么难以理解
- 力扣-589. N 叉树的前序遍历
- CDOJ 483 Data Structure Problem DFS
- 数字通信原理_推荐 | 从飞鸽传书到数字信号,你不得不懂的通信原理
- 2种方式打开jar文件
- 如何拆分PDF成多个文件?这样拆分非常简单
- 【转载】30个高质量但免费的自学网站
- 基于MM、STP、ECN、MTF的外汇平台模式深度分析
- ie浏览器flash player不能用的解决方案
- 2022年企业CS1升级到CS2需要什么条件 ?有什么流程?
- 使用JavaFX2.0的控件
- 【单片机】单片机课程设计(测温打铃)附完整代码和电路图
- JQuery ajax使用总结
- GitHub 学生认证,申请 GitHub 学生包
- 软件产品测试验收报告介绍
- C#利用QQ游戏破解QQ密码
- 容积卡尔曼滤波CKF—目标跟踪中的应用(算法部分—I)
- 处理/root/jdk8/jdk1.8.0_241/bin/java: /lib/ld-linux.so.2: bad ELF interpreter: No such file or di错误