JSON: JavaScript Object Notation, JavaScript 对象标记
JSON 本质:是一种轻量级的数据交换格式
1. 轻量级 是 和 XML作比较
2. 数据交换格式 :JSON 是一种数据交换格式, 它的载体是字符串(字符串是JSON的表现形式。)
Ps. JSON 对象 和 JSON 字符串的区别
符合JSON格式的字符串叫做JSON字符串, i.e { "name":"John"}
Ps. JSON VS XML , JSON 在互联网领域更受欢迎。
JSON优势:易于阅读、解析,网络传输效率高,是一种跨语言交换数据(XML也是跨语言的)
反序列化
json_str='{"name":"小气","age":18}' #JSON 字符串
json_array='[{"name":"小气","age":18},{"name":"小气","age":18}]'#JSON数组
里面 是双引号的话,外面必须是单引号
JSON格式的字符串键值必须是双引号 数字可以不加双引号
json字符串loads,转换成dict字典;jsonarray数组loads,转换成列表
JSON字符串到某种语言的解析过程叫反序列化
MongoDB是nosql数据库的代表,比较适合存储序列化后的数据
反序列化是将JSON数据类型转化成python数据类型
关键在于loads函数上
json字符串loads,转换成dict字典;jsonarray数组loads,转换成列表
序列化是将python 数据类型转化成JSON数据类型
序列化实例 关键在dumps函数上
枚举
python中所有枚举类型都是enum模块下Enum类的子类。如:
枚举中的标识最好全部使用大写。
注:枚举的意义重在标签而不在于数值,使用print(VIP.YELLOW)打印结果不是1而是VIP.YELLOW,这也符合枚举的意义。
枚举类的优势
不用枚举的话字典是一个表示种类的方式
{'yellow':1,'green':2}
或者用类表示
class Type():
yello = 0
....
以上两种方法的缺点是
1 可以轻易的在代码里更改
2 没有防止标签值重复的功能
而这些枚举类型都解决了
枚举类型是不能通过代码改变
枚举类型不允许有两个值相同的类型出现
枚举类型、枚举名称与枚举值:
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
print(VIP.GREEN.value) 返回值2,是枚举对应的取值
print(VIP.GREEN.name)返回GREEN,是str类型,对应的标签名字
print(VIP.GREEN)返回VIP.GREEN,是enum类型
枚举类型是可以被遍历的
枚举的比较运算
1.枚举类型之间可以进行等值比较(==),但直接和数值比较会返回False,如:
VIP.GREEN == 2 返回False
2.枚举类型之间不支持大小比较操作符(>、<)的.
3.枚举类型可以进行身份比较(is),如:
VIP.GREEN is VIP.GREEN 返回 True
4.不同枚举类中的枚举类型进行比较都会返回False。
枚举不能有相同的标签
枚举在使用的时候所面临的误区
枚举类中不同枚举类型的值可以相同,此时这两个枚举类型中的第二个名称是第一个的别名,建议使用第一个的名称+_ALIAS作为名称。
此外,若枚举类中存在别名,在遍历打印时只会打印出非别名的所有枚举类型。若想输出所有枚举成员,可以使用枚举类的内置变量__members__,如:
for v in VIP.__members__:
print(v)
结果为:
YELLOW
YELLOW_ALIAS
BLACK
RED
枚举的转换·
枚举类型建议用数字来存储在数据库中,这样可以占据更少的存储空间。但是不建议使用数字来代表枚举的类型,影响代码的可读性
如何把数据库中的存储的数字转换成为枚举类型
使用枚举类名(数值)进行类型转换
例:
进阶知识
1.函数式编程
进阶语法很大程度与函数式编程相关,不过它跟着不同语言,定义也有所变化
它可以简化代码和更优秀的接口。在认为写的代码很别扭、繁琐时尝试使用。
这部分内容对于没有多少编程经验的人来说,先记下来,写的时候思考一下能不能用
2.闭包:概念晦涩,不建议从标准定义上来理解
闭包和函数关系很大。
函数在别的很多语言只是一段可执行的代码,并不是对象,因此也不能实例化。
也不能给函数赋值,而python可以,在python里一切皆对象(类)。
(可以用type函数检验,返回一个class)
python还可以成为另一个函数的参数,传递到另外的函数里
还可以把一个函数当做另外一个函数的返回结果
Py中函数可以直接赋值给一个变量
闭包
1.python在函数内部还可以定义函数,但该函数作用域只在外部函数内部有效,除非作为外部函数的返回值被返回,在外部函数的外部用一个变量接收后就可以调用它了。
2.python中闭包的定义:由函数及其在定义时外部的环境变量(不能是全局变量)构成的整体。
闭包 = 函数 + 环境变量(函数定义时候)通俗的说就是整个函数里a的值必然取25
3.如图,可以通过函数的内置变量__closure__来访问函数的环境变量
闭包的意义在于保存了一个环境。尤其是函数中调用函数时,如果没有闭包,很容易被外部变量所影响。
闭包必须满足两个条件:
1. 函数嵌套着函数
- 而且内部的函数必须要引用到外部函数(父函数)的这个变量,假如在这个内部函数中存在着冲突的调用变量,那么这就不叫闭包
通过一个实例来看闭包
下面这个例子中 闭包是不存在的 因为f2中定义了一个局部变量 与之就不会去引用a=10的环境变量
也就是说闭包在这个例子是不存在
输出的结果是 10 20 10
分析闭包就要从最外层开始分析
先看第二个输出a 因为没有执行f2函数所以首先执行他的输出 且为10
再看f2()那一行 因为执行了函数f2 所以结果为20
再到print(a)的最后一行 因为局部变量是没有改变全局变量的能力的
所以局部变量就无效 故最内层输出为10
浅谈函数式编程
1. 工厂模式,factory
2. JavaScript VS Python 闭包对比。python 通过闭包的方式间接调用函数内部的环境变量
3. 环境变量是常驻内存内,极容易造成内存泄露,在使用环境变量时一定要注意。 JavaScript内的环境变量会影响浏览器卡顿,影响用户体验。
4. 函数式编程, 不会操纵全局变量。函数式编程
5. 闭包只是函数式编程思想的一种应用。闭包 不等于 函数式编程。
闭包的作业
非闭包方法
Py认为在方法里,函数等号左边的变量是局部变量
即便是此变量被赋值为全局变量,但如果在函数内部出现了变量赋值,即使出现在函数最后一条语句,这个变量也会被认为是局部变量,执行时不再往外找值,赋值前使用报未定义的错误。
解决办法之一是将变量赋值为global。
闭包方法
因为在py中对局部变量的认为方式 ,在等号左边的被认为是局部变量
所以需要在圈红处把这个变成非局部 使用了关键字nolocal 强制转成环境变量
而变量new_pos能保存记忆现场 记忆上一次调用函数的状态特性
闭包的优势就在于 不会改变全局变量oringin的值 反而非闭包方法会改变其值
匿名函数(lambda)
匿名函数(lambda表达式): 定义函数时不需要函数名
用关键字lambda来实现
lambda parameter_list: expression
expression只能是简单的表达式,且不能完整实现函数内部的代码块,且不能在:后面加上赋值之类的,因此叫lambda表达式其实更合适一些
想要调用这个lambda 直接赋值给f
f = lambda x,y: x+y
#冒号之后的计算结果作为返回值
#通过把函数赋值给一个变量实现调用
三元表达式格式:(py的三元表达式和Java中的是不同的)
条件为真时返回的结果 if 条件判断 else 条件为假时的返回结果
例:x if x > y else y
三元表达式经常用于lambada表达式部分 例如:
res=lambda x,y:x if x>y else y print(res(5,4))
Java是 x>y ? x:y
Py是 x if x >y else y
Map的使用
map #class map 是一个类
不推荐在业务代码中大量用闭包,如果是框架、包、类库可以尝试
用法:map(func,list) #第二个参数可以是list 或者其他集合类型
意思是 对list运行func函数 然后重新赋值给一个新list
r = map(func,list) #r返回的是 object map这个对象
可以根据需要将r转换为需要的类型
print(list(r))
map可以结合lambda表达式一起使用
list_x = [1,2,3,4,5]
list_y = [1,2,3,4,5]
r = map(lambda x, y: x*x + y, list_x, list_y)#py中给的定义是逗号后面都为可变参数,所以就往里加
#map类的第二个参数是可变参数,可以直接 加入多个列表
map里的列表的传入个数必须与lambda表达式的参数个数一致
使用map与lambda可以替代函数和for循环,代码看上去更简洁,不过并不会提高运行效率
Lambda表达式和map共同使用时候要保证传入lambda表达式中的list内部的参数个数相同
Reduce
1. reduce 通过 from functools import reduce 来导入。reduce 必须接收两个参数
2. Google推出的map/reduce 在大数据应用里是一个编程模型,map 在大数据里 称为 映射,reduce 则称为 归约。这个map/reduce模型在大数据里主要用来进行并行计算。大数据里的 map/reduce 模型,借鉴的就是函数式编程思想。
3. reduce是高度抽象的函数
4. reduce 不是在内部连续相加,而是在内部连续计算
第三个函数aaa 是首先进行运算的
Filter
Filter和map返回的最后都是一个集合,reduce而是一个数值
filter:过滤掉不符合我们定义规则的元素,可以理解为过滤掉布尔类型为False的元素
#把数字看成布尔类型的话,用lambda x: x就可以实现相同的功能
print(list(r))
注意返回的是集合,不像reduce,是一个数值
此外,filter中的lambda表达式一定是要可以判断真假
命令式编程vs函数式编程
命令式编程:
1. def 定义函数
2. if else 条件判断
3. for 循环
4. 包、模块;类、对象也是重要部分,但不是必须
函数式编程:
1. 最基本的三个函数 map / reduce / filter
2. lambda表达式 -- 在函数式编程里被称为算子
lambda 表达式作为函数式编程里最基本单元理论上可以替换命令式编程里的函数
map/reduce 是理论上可以替换 命令式编程里的循环
Python, 包含 Java, C#等语言还是命令式编程,只是具有支持函数式编程的特性。
lisp 是函数式编程的鼻祖。lisp 在人工智能(AI)领域用的也比较多。
装饰器
装饰器1
1、装饰器所要解决的问题:在不修改原始代码逻辑的情况下,增加函数的功能。
2、对修改是封闭的,对拓展是开放的。
import time
def f()
print(time.time())
3、例子:
def f1():
print("this is a f1")
def f2():
print("this is a f2")
def print_current_time(fun_name):
print(time.time())
fun_name()
print_current_time(f1)
print_current_time(f2)
装饰器2
内聚性更高
真正的业务逻辑是在wapper里实现的
def decorator(func): #实现装饰器要用到嵌套函数
def wrapper():#封装 包装 要封装的功能放这里面
print(time.time())#通过wrapper 封装实现不改变原来的函数实现新的功能
func()#如何体现装饰器的功能这
return wrapper
def f1():
print('This is a function1')
f = decorator(f1) #这样f就是一个函数可以调用
f()#但是这样很不好用 反而写了嵌套函数比较麻烦
示例和打印结果
装饰器3
圈红部分是装饰器功能
可以直接在f1()函数里直接调用decorator
装饰器4
装饰器中可以使用可变参数*可变参数来解决对不同函数中不同参数的个数
装饰器5
要想满足关键字参数的调用
#完整的装饰器写法
def decorator(func):
def wrapper(*args, **kw):#**kw公认表示keyword关键字
print(time.time())
func(*args, **kw)#print(kw) 在函数中可以当作字典打印出来
return wrapper
装饰器6
装饰器思想:
如果想对某个被封装的单元,比如函数,作代码上的修改,我们可以不去改动函数的具体实现,而是通过装饰器的形式来改变函数的行为。这是从代码的稳定性的角度来说。
换个角度,从代码的复用性再来说明下装饰器用法。i.e 打印时间的功能,就是新增的一个逻辑。现在把这个逻辑封装成一个装饰器。凡是需要打印时间的函数,都可以通过 @装饰器名 来把装饰器的逻辑强行加载到调用函数,这个被称为代码的复用。
如果想增加一个函数的功能,但又不想更改函数的实现,怎么办? 利用装饰器,不需要破坏函数的原始实现。
一个函数 可以 添加 一个或多个装饰器。
装饰器体现的是AOP思想。