导语
Python是一个动态语言.(属于解释型语言,类似的有JavaScript)
Python是一个面向对象的语言. 既有动态脚本的特性, 又有面向对象的特性.
Python相对于编译型语言(c、c++)、Java运行效率慢
第3章 理解什么时写代码与Python的基本类型
什么是写代码?
代码是现实世界事物在计算机世界中的映射.
什么是写代码?
写代码是将现实世界中的事物用计算机语言来描述.
3-1 、Python的基本数据类型
1、Number: 数字
整数: int
浮点数: float
比如: print(type(2/2)) 打印结果: <class 'float'>
print(type(2//2)) 打印结果: <class 'int'>
/是除法,结果会自动转成浮点数;
//是整除,结果会自动转换成整数.
10进制: 1,2,3,4,5,6,7,8,9,10...
2进制: 0,1,10,11...
8进制: 0,1,2,3,4,5,6,7,10...
16进制:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
在Python里表示不同的进制:
0b10 二进制10 =2
0o10 八进制10 =8
0x10 十六进制10 =16
各进制之间的转换:
bin() 把其他进制转换为2进制;比如: bin(0o7)
oct() 把其他进制转换为8进制;
int() 把其他进制转换为10进制;
hex() 把其他进制转换为16进制;
bool 布尔类型:
非0为真 True
0和空值和none为假 False
complex 复数
2、str字符串
'双单引号'
"双引号"
'''三引号'''
"""三引号""" 三引号可显示长字符及换行字符,除了print时转义字符有效,其他情况下转义字符无效.
\ 转义字符:(三种)
特殊的字符
无法"看见"的字符 比如:\n换行;\t横向制表符;\r回车
与语言本身语法有冲突的字符
r显示原始字符串:
print(r'c:\northwind\northwest')
打印结果:c:\northwind\northwest
字符串的运算:
用+拼接字符串,比如: "hello"+"world"
用*重复字符串,比如: "hello"*3
截取字符串中第几个字符,比如:
"hello"[3] 输出:l
"hello"[-1] 输出:o
"hello"[0:2] 输出:he (:是切片操作)
"hello"[0:-1] 输出:hell (从0到倒数第一个字符之间的字符)
"hello"[-2:] 输出:lo (从倒数第二个到末尾)
"hello"[:-3] 输出:he (从开头到倒数第三个之间的字符)
3、序列与集合
列表- list []
列表运算 跟 字符串运算 操作一致;
嵌套列表.
元祖- tuple ()
元祖运算 跟 字符串运算 操作一致;
注意:元祖()跟数学运算()的区分,比如定义只有一个元素的元祖,(1,),也就是加个逗号
定义一个空元祖:()
str list tuple 都是序列.
//序列共有操作:
除去相同的运算操作外,以下也是,以序列中list为例,
3 in [1,2,3,4] 3是否在list中,
3 not in [1,2,3,5] 3是否不在list中,
len([1,2,3,4,5]) 列表的元素个数,
max([1,2,3,4,5]) 列表中最大值,通过ASSIC码来比较的,输出ASSIC码的值用ord(),比如: ord('d')
min([1,2,3,4,5]) 列表中最小值
集合- set {}
无序的,没有索引,不属于序列,无法进行序列运算操作
里面元素不重复
支持长度判断,比如:len({1,2,3})
支持包含判断,比如:1 not in {1,2,3}
求两个集合差集,比如:{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}
如何定义一个空集合: set()
字典- dict {key:value}
并不是序列类型,是集合类型
字典中不能有相同的key,key必须是不可变类型.
定义一个空的字典: {}
第5章 变量与运算符
5-1、变量
= 赋值符号
变量名规范:
首字符不能是数字,
变量名只能是字母、数字、下划线,
系统关键字(保留关键字)不能用在变量名中
变量没有类型限制,不需要声明变量类型
int str tuple 是值类型(不可改变), list set dict(可变) 是引用类型,比如:
a = 1
b = a
a = 3
print(b) 此时输出1
a = [1,2,3]
b = a
a[0] = '1'
print(b) 此时输出['1',2,3]
print(id(b)) 输出b的内存地址
总结:
值类型: 不可改变值,只能让指针指向新值来实现改变;
引用类型: 可改变值,直接在旧值的基础上添加或删除数据,指针不变,依然指向旧址.
5-2、运算符
算法运算符:(对数字运算)
+ 加
- 减
[1]*3 = [1,1,1] 乘
/ 除
3//2 = 1 整除
5%2 = 1 余数
2**5 = 32 二的5次方
赋值运算符:(先做运算再赋值)
=
-=
+=
*=
/=
%=
**=
//=
比较(关系)运算符:(返回布尔结果)
==
!=
>
<
>=
<=
总结: ord('a')//比较的是对应的ASCII值,输出a的ASCII码值
逻辑运算符:(返回布尔值)
and 并且 比如:1 and 3 //输出3
or 或者 比如: 1 or 2 //输出1
not 非
总结: int float中,0被认为是False,非0表示Ture; 对于字符串类型,空字符串被认为是False,否则为True.
运算优先级: not>and>or.比如:1 or 2 and 3 //输出1
成员运算符:(一个元素是否在另一组运算符里)
in
not in
总结: 这里特别注意,判断某个字符是否在字典中存在,判断的是key是否和这个字符相同.
身份运算符:(判断两个变量是否相等)
is
is not
总结: 关系运算符比较的两个变量的值是否相等; 身份运算符比较的是两个变量身份(内存地址)是否相等.
位运算符:(把数字当做二进制数进行运算)
& 按位与 比如: a=2 b=3 a&b输出:2. 解析:a转化二进制为1 0 ,b转化二进制为1 1,当同位对应的数为都为1时为1,同位上一个为1一个为0时为0,所以结果是1 0
| 按位或 解析: 只要两个数转二进制后,同位上有一个为1,那么就为1
^ 按位异或
~ 按位取反
<< 左移动
>> 右移动
对象三个特性: 值(id)、身份(value)、类型(type)
//判断变量类型方法一:
type('hello') == int 输出:False
//判断变量类型方法二(推荐):
isinstance('hello',str) 输出:True
isinstance('hello',(int,str,float)) 输出:True (是否是元祖中任意类型是任意一种)
第6章 分支、循环、条件与枚举
6-1 表达式
表达式(Expression)是运算符(operator)和操作数(operand)所构成的序列
6-2 vscode开发工具—Python插件
1. Python
2. Terminal 想在另一个IDE里运行代码,比如小程序开发
3. view in Browser
4. Vim
5. vscode Icon
6-3 流程控制语句---(解决选择性问题)
1. 条件控制--- if else 可以判断变量和表达式,比如下面例子:
mood = True
if mood:
print('go to left')
else :
print('go to right')
2. 循环控制--- for while
3. 分支--- switch (Python里面没有switch)
6-4 注释
# 单行注释
'''
多行注释
'''
6-5 Python代码特点
# 语句结束时;不是必须的, 一般情况下省略
# 通过缩进(四个空格)来做代码包裹
# Python建议用_来组合两个单词的命名
# Python里面并不存在真正意义上的常量, (假装)常量命名规范是单词大写,比如: ACCOUNT - 'qiyue'
# 比较运算符的两侧各加一个空格
# pass 空语句/占位语句
# Python规定一行里面的字符个数不能超过80个, 换行的方法一:末尾加\ ,这样就可以下一行继续编写代码. 方法二:用() 比如下面的例子:
from c9 import a,b,\
c
from c9 import (a,b,
c)
#
第7章 包、模块、函数与变量作用域**
7-1 循环
# while循环
counter = 1
while counter <= 10 :
counter += 1 # while代码块内必须有影响条件判断的语句,否则出现死循环
print(counter)
else:
print('所有元素都遍历完,打印这里')
# for循环 主要是用来遍历/循环 序列或者集合、字典
a = ['apple','orange']
for x in a:
print(x,end='') # 默认情况下,print打印出来的数据,呈现列的排布print(x,end='\n');想让每个元素都在一行打印出来 print(x,end='')
else:
print('所有元素都遍历完,打印这里')
# for循环---区间
for x in range(10,20,2):# 创建一个递增序列,从10开始循环到19,步长为2
print(x,end='|') # 打印: 10|12|14|16|18
for x in range(20,10,-2):# 创建一个递减数列,从20开始循环到11,步长为-2
print(x,end='|') # 打印: 20|18|16|14|12
### break 和 continue 区别:
b = [1,2,3]
for x in b:
if x ==2:
break # 终止循环操作, 并且不会执行else语句; 如果是嵌套循环,break不会影响外部的循环继续
print(x) # 打印: 1
c = [1,2,3]
for x in c:
if x ==2:
continue # 跳过本次循环, 还会打印else语句
print(x) # 打印: 1 3
### 思维拓展: 取出数组d,等差数列,步长为2
d = [1,2,3,4,5,6,7,8]
方法一:
for i in range(0,len(d),2)
print(d[i],end='')
方法二:
b = d[0:len(d):2]
print(b)
7-2 Python项目的组织结构
包 (文件夹) #想让一个普通的文件夹变成包,在文件夹下创建一个__init__.py文件,__init__.py的模块名就是包名
模块 (.py文件)
类
函数和变量
7-3 模块的导入
# 在同一个包中, c8.py中导入使用c7.py里的变量和函数
在c7.py中:
a = 2
在c8.py中:
import c7
print(c7.a) //使用c7模块的变量
# 在不同包中, c8.py中导入使用t包下的c7.py里的变量和函数
在t包下的c7.py中:
__all__ = ['a','c']//sp1
a = 2
b = 3
c = 4
在c8.py中:
方法一:(导入具体模块)
import t.c7 as m
#print(t.c7.a) 此时命名空间过长,用as简化
print(m.a)
方法二:(导入具体变量/模块/函数)
from t.c7 import a,b,c
print(a)
方法三: (*默认导入所有变量,如果不想导入所有变量,需配合sp1导入部分变量)
from t.c7 import * //sp2
print(a)
print(c)
print(b)//无法打印,因为sp1没有导入b
7-4 vscode中设置---隐藏不想显示的文件/文件夹
让文件目录中隐藏 __pycache__缓存文件夹
#匹配文件路径所依据的 glob模式,设置为true或false可启用或禁用该模式
用户设置>>搜索files.exclu>>进行下面的操作👇:
// 配置 glob 模式已排除文件和文件夹.
"files.exclude":{
"**/.git":true,
"**/.svn":true,
"**/.hg":true,
"**/CVS":true,
"**/.DS_Store":true,
"**/__pycache__":true //添加这行
}
7-5 包下init文件的使用场景
#包和模块是不会被重复导入的
#避免循环导入,比如: p1.py导入p2.py,同时p2.py也导入p1.py,就会出现循环的导入
#导入.py文件,会执行一次所导入.py文件里的代码.(并且不管导入多少次,也只执行这一次)
当一个包被导入的时候,会先执行__init__.py文件
通常会在包的__init__.py文件做一些初始化的工作
# 应用一:不同包情况下,c11.py中导入t包
在t包下的__init__.py文件中:
__all__ = ['c7'] # 这里只定义了c7
在t包下的c7.py文件中:
__all__ = ['a','c']
a = 2
c = 3
d = 4
在t包下的c8.py文件中:
e = 2
f = 3
g = 4
在c11.py中
from t import *
print(c7.a) # 打印:2
print(c8.e) # 无法打印,因为没有导入c8
# 应用二: 批量导入库
在t包下的__init__.py文件中:
import sys
import datetime #引入多个包
import io
其他包的c13.py文件中t
import t
print(t.sys.path) #导入t就可以使用t导入的sys包了
小技巧:
终端清屏: clear
第8章 Python函数
8-1 函数
a = 1.12386
print(round(a,2)) #round函数给a保留两位小数(四舍五入),输出: 1.12
# python默认最大递归数是995次,可以设置最大递归数如下:
import sys
sys.setrecursionlimit(996)#数可以任意设置
#定义一个函数(一个返回值)
def add(x,y): //x和y是形参
result = x + y
return result
b = add(1,2) //1和2是实参
print(b)
#定义一个函数(多个返回值)
def damage(skill1, skill2):
damage1 = skill1 * 3
damage2 = skill2 *2 + 10
return damage1, damage2
damages = demage(3,6)
print(type(damages)) #输出: <class 'tuple'>
skill1_damage, skill2_damage = damage(3,6) #序列解包接收结果
print(skill1_damage, skill2_damage)
#序列解包
a = 1
b = 2
c = 3
可简写成: a,b,c = 1,2,3
a,b,c = 1,1,1
可简写成: a=b=c=1 #链式赋值
d = 1,2,3
print(type(d)) #输出:<class 'tuple'>
a,b,c = d #序列解包,这里要使接收变量和返回值个数相同
8-2 参数
1.必须参数 #按顺序传参
2.关键字参数#可以不按顺序传参
def add(x,y):
result = x + y
return result
c = add(y=3, x=2)
3.默认参数 #默认按形参顺序传, 可以用关键字参数方式传
def add(name,age,x=10,y=13): #必须将必须参数和关键字参数分开调用,不要混合调用
result = x + y
return result
第9章 高级部分: 面向对象
9-1定义类
# 在c1.py中:
class Student():
name = 'shiyue' #类变量
age = 0
sum1 = 0
#定义构造函数,只能返回None
def __init__(self,name,age):
self.name = name# 定义实例变量
self.age = age
print(Student.sum1)# 打印类变量,方法一
print(self.__class__.sum1)# 打印类变量,方法二
self.__class__.sum1 += 1
print('当前班级学生总数为:' + str(self.__class__.sum1))
#定义实例方法
def print_file(self):
print('name:' + self.name) # 调用本类的属性,必须加self
print('age:' + str(self.age))
#定义类方法
@classmethod
def plus_sum(cls):
cls.sum1 += 1
print(cls.sum1)# 调用本类的属性,必须加cls
#定义静态方法:(不推荐使用,完全可以被类方法取代)
@staticmethod
def add(x,y):
print('This is a static method')
print(Student.sum1)#调用类的属性
student = Student('石敢当',18)#实例化时,自动调用__init__函数
student.print_file()#方法 和 函数的区别:方法是设计层面; 函数:程序运行,过程式的一种称谓
print(student.__dict__) #打印实例student里面所有的变量
print(Student.__dict__) #打印类Student里面所有的变量
# 从另外一个模块中引用类:
from c1 import Student
student = Student()
student.print_file()#调用实例方法
Student.plus_sum()#调用类方法
student.add(1,2)
Student.add(1,2)#类和实例变量都可以调用静态方法
##### Python寻找相关变量的机制:
如果我们尝试去访问一个实例变量,Python首先会尝试在实例变量里面查找有没有这个变量; 如果没有,Python不会立即返回None,它会在类变量里面寻找有没同名的变量; 如果有,把这个类变量的值返回出来.
9-2 可见性
class Student():
def __init__(self, name, age):
self.name = name
self.age = age
self.__score = 0#严格意义上讲,Python是没有私有变量的,它只是把私有变量变成了: _类名__私有变量名 这样一个变量
def marking(self, score):
if score < 0:
return '不能够给别人打负分'
self.__score = score
print(self.name + '同学本次考试分数为:' + str(self.__score))
def __siyou(self, name):
print('从外部强制访问此私有方法会报错')
student1 = Student('石敢当', 18)
result = student1.marking(-1)
print(result)
student.score = -1
# 总结:
# 不要直接在外部给变量赋值,会使数据不可限制,不安全; 建议通过方法给变量赋值,进行操控,可以保护变量.
# 一旦只在方法或变量前面加了双下划线(__),Python就会认为你这个方法或变量是私有的.
# 前后都加双下划线(__)是Python内置函数和变量的风格,非私有.
9-3 面向对象三大特性
# 继承性 -- 实例变量、类变量都是可以继承的. 支持多继承.
在c6.py中
class Human():#最好一个模块文件定义一个类
sum = 0
def __init__(self, name, age):
self.name = name
self.age = age
def get_name(self)
print(self.name)
在其他.py中
from c6 import Human
class Student(Human):# 让Student类继承Human类
def __init__(self, school, name, age):
self.school = school
#在子类里调用父类的构造函数,方法一:(不推荐下面这样调用)
Human.__init__(self, name, age) #为什么这里要传self?这里只是类调用一个普通方法,所以要传self,用实例调用的话就不用传self
#在子类里调用父类的构造函数,同样调用父类的普通实例方法也是这样写,方法二:(推荐)
super(Sutdent, self).__init__(name, age)
student1 = Student('人民路小学','石敢当', 18)
print(student1.sum) # 输出: 0
print(Student1.sum) # 输出: 0
print(student1.name) # 输出: 石敢当
print(student1.age) # 输出: 18
student1.get_name() # 输出: 石敢当
# 封装性
# 多态性
第10章 正则表达式与JSON
快读检测文本、实现一些替换文本的操作
10-1 正则表达式— 查找re.findall()
import re
# 查找字符串中的'Python'字符(普通字符)
a = 'c|c++|Java|c#|Python|Javascript'
r = re.findall('Python',a)#'Python'字符为一组进行查询
print(r) #返回一个列表: ['Python']
# 查找字符串中的所有'数字'字符(元字符)
a = 'c0c++7Java8c#9Python6Javascript'
r = re.findall('\d',a)
print(r) #输出: ['0','7','8','9','6']
# 查找字符串里,单词中间是'c'或是'f'的单词
s = 'abc, acc, adc, aec, afc, ahc'
r = re.findall('a[cf]c',s)# 在[]内字符是"或"关系
r = re.findall('a[^cfd]c',s)# 在[]内字符是"或"关系,^是取反操作
r = re.findall('a[c-f]c',s)# 在[]内字符是"或"关系,-这里是c到f的意思
print(r)
# 概括字符集,都可以用字符集表示出来
\d 数字
\D 非数字
\w 单词字符 A-Za-z0-9_
\W 非单词字符 空格、\t、&、\n、\r
\s 空白字符
\S 非空白字符
. 匹配除换行符\n之外其他所有字符
# 数量词
a = 'python 1111java678php'
r = re.findall('[a-z]{3}',a) #从字符串中匹配3个a-z的字符,3个字母为一组
r = re.findall('[a-z]{3,6}',a) #贪婪匹配,匹配3到6个a-z的字符
##数量词-贪婪和非贪婪
默认情况下,Python正则匹配倾向贪婪模式.
'''
* 匹配0次或无限多次
+ 匹配1次或无限多次
? 匹配0次或者1次. (在?前有范围时,用做贪婪非贪婪转换; ?前是固定字符时,用作匹配0次或1次.)
'''
r = re.findall('[a-z]{3,6}?',a) #非贪婪匹配, 通过?转换为非贪婪模式
a = 'pytho0python1pythonn2'
r = re.findall('python*',a) # *前面的这个字符匹配0次或无限次
r = re.findall('python+',a) # +前面的这个字符匹配1次或无限次
r = re.findall('python?',a) # ?前面的这个字符匹配0次或1次 输出:['pytho','python','python'],能打印出来第二个'python'是因为,'pythonn2'中'n2'前的'python'是符合匹配的. 因此可以用?做去重的操作.
# 边界匹配---^$
# ^表示以某字符为开头开始匹配,$表示以某字符为末尾开始匹配
qq = '10000001'
r = re.findall('^\d{4,8}$',qq) #qq号是否满足4-8位
# 组----()
a = 'PythonPythonPythonPythonPythonPython'
r = re.findall('(Python){3}',a) # 'Python'为一组,重复3次,进行匹配
# 匹配模式参数--- re.I(忽略大小写), re.S(改变.的匹配行为,使得.能够匹配到换行符\n)
lanuage = 'PythonC#\nJavaPHP'
r = re.findall('c#',lanuage,re.I) # 第三个参数(匹配模式)设置为re.I,使的匹配忽略字母大小写
r = re.findall('c#.{1}',lanuage,re.I | re.S) #这里的|是且关系, 输出: ['C#\n']
10-2 正则表达式--字符替换re.sub()
'''
re.sub(pattern, repl, string, count=0, flags=0)
参数一: pattern表示: 正则表达式
参数二: repl表示: 匹配成功之后,需要替换成功的字符串
参数三: string表示: 要搜索的原字符串
参数四: count表示: 能匹配的最大次数,默认0(表示将无限制的匹配下去)
参数五: flags表示: 匹配模式参数
'''
import re
lanuage = 'PythonC#\nJavaC#PHPC#'
r = re.sub('C#', 'GO', lanuage,1)#将lanuage里的'C#'字符替换为'GO'字符
lanuage = lanuage.replace('C#','GO')# 是sub的简化版替换
# 第二个参数可以传入一个函数: 可以实现根据不同的匹配结果实现不同的替换
def convert(value):
print(value) #打印出来是个对象,携带的额外信息中:span表示匹配所在位置,match表示匹配内容
matched = value.group()#value对象的分组信息,获取到'match'信息里的字符
retun '!!' + matched + '!!'
r = re.sub('C#', convert, lanuage,1)#当正则匹配到一个结果后,它会把结果传递到函数里面去,函数的返回结果将作为替换字符串
##例子: 把函数作为参数传递
s = 'ABC3721D86'
def conver(value):#替换字符串中的数字字符,>5的替换为9,不大于5的替换为0
matched = value.group()
if int(matched) >= 6:
return '9'
else:
return '0'
r = re.sub('C#', convert, lanuage,1)
10-3 re.match和re.search
# 这两个函数跟findall功能跟用法几乎一样,但没有findall好用,一般用findall.
import re
s = 'ABC3721D8E67'
r = re.match('\d',s) #打印出来是:None
print(r.span())#打印匹配到的位置
r = re.search('\d',s) #打印出来是一个匹配对象
print(r.group())#打印匹配到的值
re.match和re.search总结:
不同点:
match的特点是: 从字符串的首字母开始匹配,如果match没有找到相应的匹配结果,那么它将返回一个None. 上面例子中因为开头不是数字所以没有匹配到结果;
search的特点: 搜索这个字符串,直到找到第一个满足正则表达式的结果.然后将这个匹配结果返回回来.
共同点:
它们匹配到之后都会返回一个对象,例如返回值:<_sre.SRE_Match object; span=(0, 1),match='8'>;
匹配到一个结果后,立即停止搜索.(findall会一直搜索)
# 分组:
s = 'life is short,i use python'#正则找出'lift'和'python'之间的内容
r = re.search('life(.*)python',s)
print(r.group(1))#group(0), 默认参数是0,参数表示组号,方便选择第几组的内容.
## 总结: 正则表达式用()来进行分组, 访问分组的话用.group(); group函数默认参数是0,永远代表正则所有内容.()分组的话必须从1开始访问. 特别说明:findall不存在这种问题.
r = re.findall('life(.*)python',s)
print(r)#打印结果同上
# 多个分组
s = 'life is short,i use python, i love python'
r = re.search('life(.*)python(.*)python',s)
print(r.group(0))
print(r.group(1))
print(r.group(2))
print(r.group(0,1,2))#简写上面三个打印, 输出一个元祖
print(r.groups())#输出一个元祖,对比上面打印:只会打印()分组部分,没有完整匹配.
10-4 理解JSON
JavaScript Object Notation 翻译过来: JavaScript对象标记
JSON 是一种轻量级的数据交换格式.
字符串是JSON的表现形式(载体).
JSON同样遵循EMSSCRIPT,是跟js平行的一种语言.
JSON、JSON字符串 区别:
符合JSON格式的字符串叫做 JSON字符串;
JSON 是一种轻量级的数据交换格式
优点: 易于阅读, 易于解析, 网络传输效率高, 跨语言交换数据
import json
# 反序列化
josn_str = '{"name":"qiyue", "age":18}'
student = json.loads(json_str)#json转Python数据类型
print(type(student))#打印出来: <class 'dict'>
# json对应python的转换类型
json python
object dict
array list
string str
number int
number float
true True
false False
null None
# 序列化
student = [
{'name': 'qiyue', 'age': 18, 'flag':False},
{'name': 'qiyue', 'age': 18}
]
json_str = json.dumps(student) #python数据类型转换成json字符串
print(type(json_str)) # <class 'str'>
如果一定要存储对象到数据库,建议用NOSQL数据库,否则效率太低,强烈反对对象序列化!
第11章 Python的高级语法与用法
11-1 枚举--Enum
# 定义枚举
from enum import Enum # 枚举值可以是任意类型
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 'str'
print(VIP.YELLOW)#获取枚举的类型(<class 'str'>),打印: VIP.YELLOW
print(VIP.YELLOW.name)# 获取标签的名字(<enum 'VIP'>),打印: YELLOW
print(VIP.YELLOW.value)# 获取枚举值
'''
和普通类相比,枚举的特点:
不可变
防止相同值的功能(类似常量,所以建议大写)
'''
# 遍历枚举
for v in VIP:
print(v)
# 枚举的比较运算
枚举类型只能与枚举类型进行等值(==)比较, 不支持枚举间进行大小(><)比较;
枚举间可以进行身份(is)比较.
# 枚举转换--- 把数字转换成枚举类型
a = 1
print(VIP(a)) #打印: VIP.YELLOW
# Enum 和 IntEnum区别
from enum import IntEnum #枚举值只能是数字
class VIP(IntEnum):
YELLOW = 1
GREEN = 1
BLACK = 3
RED = 4
# 限制枚举里有相同的值
from enum import IntEnum,unique #unique不允许有相同的枚举值
@unique
class VIP(IntEnum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
枚举是一种单利模式,不用初始化.
11-2 函数式编程—闭包
# 函数式编程
# 闭包
# 在python里面函数是一个对象
# python里一切皆对象
# 闭包 = 函数+环境变量(函数定义时的外部变量)
def f1():
a = 10
def f2():
# a被python认为是一个局部变量
c = 20 * a
return f2
f = f1()
print(f)
# 修改全局变量的值,来记录上次的状态---非闭包的方式解决旅行者行走多少步的问题
origin = 0
def go(step:)
global origin # 声明为全局变量
new_pos = origin + step
origin = new_pos
return new_pos
print(go(2))
print(go(3))
print(go(1))
# 使用闭包来记录上次的状态---闭包的方式解决旅行者行走多少步的问题
origin = 0
def factory(pos):
def go(step):
nonlocal pos # 闭包的环境变量,有保存现场的功能,可以记忆上一次调用的状态
new_pos = pos + step #这种写法让pos成为了一个环境变量, 具有保存状态的能力(记忆上一次调用的状态)
pos = new_pos
return new_pos
return go
tourist = factory(origin)#这里设置初始值factory(0)
print(tourist(3))# 这里类似调用go(3)
print(tourist(3))
print(tourist(2))
# 总结: 代码规范大全中, 函数中尽量少的使用全局变量, 所以推荐闭包
#在函数的外部间接调用函数内部的值
#闭包因为环境变量有保存状态的能力,所以要小心内存泄漏的问题
第12章 函数式编程: 匿名函数、高阶函数、装饰器**
12-1 匿名函数
# 用lambda声明一个匿名函数的定义
lambda parameter_list: expression #parameter_list对应参数部分, expression对应表达式(函数定义部分,不能是代码块),比如下面匿名函数👇
f = lambda x,y: x+y
print(f(1,2))
相当于下面的普通函数:
def add(x,y):
return x+y
print(add(1,2))
lambda用三元表达式比较多.
# python版本的三元表达式:
条件为真时返回的结果 if 条件判断 else 条件为假时的判断结果
比如:如果x和y, 如果x>y, 就返回x, 否则返回y.
r = x if x > y else y
print(r)
# map函数用法---映射
list_x = [1,2,3,4,5,6,7,8]
def square(x):
return x * x
r = map(square,list_x)#遍历list的每一项,并且每一项都作为参数,去执行一个函数.
print(r)#打印出一个map对象
print(list(r))#将打印出来的map对象转化为一个列表
# map(映射)与lambda结合使用
## 传入一个参数
list_x = [1,2,3,4,5,6,7,8]
r = map(lambda x: x*x, list_x) # 用lambda表达式代替上面的例子
print(list(r))
## 传入两个或多个参数---结果集合个数,取几个参数中较少元素的集合的个数.
list_x = [1,2,3,4,5,6,7,8,9,10]
list_y = [1,2,3,4,5,6,7,8]
r = map(lambda x, y: x*x + y, list_x, list_y)
print(list(r))# 得到的集合个数是8个
# reduce(归约)与lambda结合使用
from functools import reduce
list_x = [1,2,3,4,5,6,7,8]
r = reduce(lambda x,y:x+y, list_x) #连续计算, 连续调用lambda: 上一次的计算结果,作为这一次的参数进行计算
print(r)#相等于:(((((((1+2)+3)+4)+5)+6)+7)+8)
##reduce第三个参数
list_x = ['1','2','3','4','5','6','7','8']
r = reduce(lambda x,y:x+y, list_x, 'aaa')
print(r)#输出:aaa12345678
# filter(过滤)与lambda结合使用
list_x = [1,0,1,0,0,1]
filter(lambda x: True if x==1 else False, list_x)#过滤掉list中的0 , 返回False会被剔除掉
print(list(r))#输出:[1,1,1]
12-2 函数式编程VS命令式编程
命令式编程,比如:
def
if else
for
函数式编程,比如:
map reduce filter
lambda(算子)
12-3 装饰器
# 原则: 对修改是封闭的, 对扩展是开放的
# 我们可以接受定义时候的复杂, 不接受调用时候的复杂.
import time
def f1():
print('This is a function')
def f2():
print('This is a function')
# 让所有的函数都添加一个方法, 比如:给f1和f2前,添加一个打印时间戳的功能
## 方案一:
def print_current_time(func):
print(time.time())#unix 时间戳--定义为从格林或治时间1970年01月01日00时00分
func()
print_current_time(f1)
print_current_time(f2)#这方案的弊端:添加的打印时间方法,并不是f1和f2本身的
## 方案二: 装饰器
def decorator(func):
def wrapper():
print(time.time())
func()
return wrapper
f = decorator(f1)
f()#同样没有解决方案一的弊端
## 方案三: 装饰器的语法糖✅
def decorator(func):
def wrapper():
print(time.time())
func()
return wrapper
@decorator
def f1():
print('This is a function')
f1() #妙在没有改变原来调用的逻辑.
# 装饰器支持函数带参数的情况
def decorator(func):
def wrapper(func_name):
print(time.time())
func(func_name)
return wrapper
@decorator
def f1(func_name):
print('This is a function' + func_name)
f1('test func')
# 装饰器支持带多个参数的情况
def decorator(func):
def wrapper(*args):
print(time.time())
func(*args)
return wrapper
@decorator
def f1(func_name):
print('This is a function' + func_name)
@decorator
def f2(func_name1,func_name2):
print('This is a function' + func_name1)
print('This is a function' + func_name2)
f1('test func')
f2('test func1','test func2')
# 装饰器的完整形态,可以传入任意值
def decorator(func):
def wrapper(*args, **kw):
print(time.time())
func(*args, **kw)
return wrapper
@decorator
def f1(func_name):
print('This is a function' + func_name)
@decorator
def f2(func_name1,func_name2):
print('This is a function' + func_name1)
print('This is a function' + func_name2)
@decorator
def f3(func_name1, func_name2, **kw):#**关键字参数
print('This is a function' + func_name1)
print('This is a function' + func_name2)
print(kw)
f1('test func')
f2('test func1','test func2')
f3('test func1','test func2', a=1, b=2, c='1,2,3')
#总结: 装饰器最基本的思想:如果我们想对某一个封装的单元(比如函数),做出一个代码上的修改的话,可以不去改动具体实现,而是通过装饰器这样一种形式来改变函数的行为.
也就是说如果想改变函数的功能, 又不想改变它的内部代码实现.那么装饰器是很好的解决方案.
第13章 实战:原生爬虫**
13-1 爬虫步骤
爬虫前奏:
明确目的
找到数据对应的网页
分析网页的结构找到数据所在的标签位置
模拟HTTP请求, 向服务器发送这个请求, 获取到服务器返回给我们的HTML
用正则表达式提取我们要的数据(名字, 人气)
爬虫框架: BeautifulSoup , Scrapy
13-2 爬取主播姓名和在线观看人数
from urllib import request #python自带的网络请求框架
class Spoder():
url = 'https://www.panda.tv/cate/lol'
root_pattern = '<div class="video-info">([\s\S]*?)</div>'
name_pattern = '</i>([\s\S]*?)</span>'
number_pattern = '<span class="video-number">([\s\S]*?)</span>'
def __fetch_content(self):#sp1.创建一个私有函数,获取全部数据
r = rquest.urlopen(Spider.url)
htmls = r.read()#获取到请求后的内容
htmls = str(htmls, encoding='utf-8')#获取到的bytes数据转字符串
return htmls
def __analysis(self, htmls):#sp2.创建私有函数,正则匹配出想要的数据
root_html = re.findall(Spider.root_pattern, htmls)
anchors = [] #定义一个列表
for html in root_html:
name = re.findall(Spider.root_pattern, html)
number = re.findall(Spider.number_pattern, html)
anchor = {'name':name, 'number':number}
anchors.append(anchor)
return anchors
def _refine(self, anchors):#sp3.创建私有函数,数据精炼,变成我们想要的结构
l = lambda anchor:{'name':anchor['name'][0].strip(),
'number':anchor['number'][0]
} #去除文本里面的换行符和空格
return map(l, anchors)
def __sort(self, anchors):#sp4.创建私有函数,数据排序
#filter
anchors = sorted(anchors,key=self.__sort_seed,reverse==True)#根据key来进行大小排序,reverse反序排序
return anchors
def __sort_seed(self,author): #sp4-2.创建一个私有函数,为sp4提供可比较大小的key
r = re.findall('\d*',anchor['number']) #提取这一个文本中的数字
number = float(r[0])#转换为float
if '万' in anchor['number']
number *= 10000
return anchor['number']
def __show(self, anchors):#sp5.创建私有函数,展示数据
# for anchor in anchors:
# print(anchor['name'] + '-------' + anchor['number'])
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)
two_anchors = list(self.__refine(anchors))
three_anchors = self.__sort(two_anchors)
self.__show(three_anchors)
spider = Spider()
spider.go()
''' 断点调试的几个快捷键:
启动应用程序F5,
单步执行F10,
一个断点跳到下一个断点F5,
进入某一个函数或对象的内部F11
'''
关于注释:
方法注释、类注释和模板注释用''' ''', 其中方法注释写在方法里面, 而不是方法上面;
单行注释推荐写在代码上面# ;
函数行数最好控制在10-20行之内
第14章 Pythonic与Python杂记
14-1 用字典映射代替switch case语句
day = 6
def get_sunday():
return 'Sunday'
def get_monday():
return 'Monday'
def get_tuesday():
return 'Tuesday'
def get_default():
return 'Unkown'
switcher = {
0 : get_sunday,
1 : get_monday,
2 : get_tuesday
}
# day_name = switcher[day] #用下标的方式来访问,如果没有对应项会报错
day_name = switcher.get(day,get_default)() #如果找不到值的情况下返回 'Unknown'
print(day_name)
14-2 列表推导式
#列表推导式
#集合推导式
# 使用map filter也可以实现列表推导式,不过稍微复杂.
# set 也可以被推导
# dict 也可以被推导
根据一个已经存在的列表, 来推导一个新的列表, 就用到列表推导式.(set集合和dict也可以被推导)
a = [1,2,3,4,5,6,7,8]
# 用列表推导式,使a的每一个元素平方, 生成一个新的列表.
b = [i**2 for i in a]
print(b)#输出:[1,4,9,16,25,36,49,64]
# 在列表推导式里做筛选,a里面元素>=5的才平方,生成一个新列表
b = [i**2 for i in a if i>=5]
print(b)#输出: [25,36,49,64]
# 集合使用列表推导式
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}#外面用{}包裹则生成set集合
print(b)#输出: {25,36,49,64}
# 字典的列表推导式
students = {
'喜小乐': 18,
'石敢当': 20,
'横小五': 15
}
b = [key for key,value in students.items()]
print(b)#输出: ['喜小乐', '石敢当', '横小五']
b = {value:key for key,value in students.items()}#让原字典key和value做颠倒,生成新字典
元祖是不可变的,不建议转元祖
14-3 None
None 类型和值都不等于 空字符串、空列表、0、False.
print(type(None))#输出 <class 'NoneType'>
所以做判空操作, 用if a: 或 if not a: ,别用 if a is None.
# 对象存在不一定是True
class Test():
def __len__(self):
return 0
test = Test()
if test:
print('s')
else:
print('F')








网友评论