#-*- coding: utf-8 -*-
print("===============数据类型的底层实现===============")
#列表的底层实现
#引用数组的概念,列表内的元素可以分散的存储在内存中,列表存储的,实际上是这些元素的地址,这些地址的存储在内存中是连续的
list_1 = [1,[22,33,44],(5,6,7),{"name":"Sarah"}]
#浅拷贝只是将这些地址复制了一份,但是这些地址所指向的内容是相同的
list_2 = list(list_1) #浅拷贝 与list_1.copy()功能一样
#新增元素
list_1.append(100) #对list_1新存储一个地址,指向100
list_2.append("n")#对list_2新存储一个地址,指向n
print (list_1)
print (list_2)
#修改元素 将地址改为已经修改元素的地址
list_1[0] = 10
list_2[0] = 20
print("list_1: ",list_1)
print("list_2: ",list_2)
#对列表型元素进行操作,由于两个地址指向同一个列表行元素的地址,所以列表型元素的内容修改,两个列表内容都会修改
list_1[1].remove(44)
list_2[1] += [55,66]
print("list_1: ",list_1)
print("list_2: ",list_2)
#对元组型元素进行修改,注意元组是不可变的,对元组进行操作,会生成一个新的元组,原来的元组并没有改变
list_2[2] += (8,9)
print ("list _1:",list_1)
print ("list_2: ",list_2)
#对字典进行操作,原理和对列表进行操作一样,两个列表都会改变
list_1[-2]["age"] = 18
print("list_1: ",list_1)
print("list_2: ",list_2)
#引入深拷贝 深拷贝将所有层级的相关元素全部复制,完全分开,泾渭分明,避免了上述问题
import copy
list_1 = [1,[22,33,44],(5,6,7),{"name":"Sarah"}]
list_2 = copy.deepcopy(list_1)
list_1[-1]["age"] = 18
list_2[1].append(55)
print("list_1: ",list_1)
print("list_2: ",list_2)
#神秘的字典 字典的查找操作远远快于列表
#字典通过稀疏数组来实现值的存储和访问
#字典的创建过程 第一步:创建一个散列表(稀疏数组 N >>需要存储的值 n)
#第二步 根据计算的散列值确定其在散列表中的位置 极个别时候散列值会发生冲突,则内部有相应的解决冲突方法
#第三步 在该位置上存入值 访问的同理 而列表是从头开始顺序查找 所以速度比字典慢很多
#字符串的存储通过紧凑数组直接存储元素
#列表遍历需要注意的问题,注意用这种方式无法删除列表中所有的d,因为每一次删除之后,列表都会改变,但是for循环还是按照顺序循环的
#比如删除第一个d之后,新的列表就是["d","d","2","2","d","d","4"],但是for循环记得已经取过0个元素了,所以开始取第一个元素,于是少取了一个d
alist = ["d","d","d","2","2","d","d","4"]
for s in alist:
if s == "d":
alist.remove("d") #删除列表中第一次出现的该元素
print(alist)
#解决办法,使用负向索引,从-8访问到-1,先访问-8,再访问-7,以此类推,可以将所有d都删除掉
alist1 = ["d","d","d","2","2","d","d","4"]
for i in range(-len(alist),0):
if alist[i] == "d":
alist.remove(alist[i])
print(alist)
#多维列表的创建,注意乘以5是浅拷贝
ls = [[0]*10]*5
print (ls)
ls[0][0] = 1
print(ls)
#使用解析语法创建多维列表,在中括号里面,后面是对可迭代对象的遍历,每次取一个元素,执行相应的操作
#这个例子中,是每次取一个元素,就执行一次[0]*10 操作,创建一个[0]*10数组,最终生成一个5*10数组
ls = [[0]*10 for i in range(5)]
print (ls)
ls[0][0] =1
#因为各个数组是独立创建的,所有只修改其中一个
print(ls)
print("===================解析语法=================")
#解析语法的基本结构 以列表解析为例子(也称为列表推导)
#[expression for value in iterable if condition]
#三要数 :表达式,可迭代对象,if条件
#执行过程:从可迭代对象中拿出一个元素,通过if条件(如果有的话),对元素进行筛选,若通过筛选,则把元素传递给表达式,若未通过,则进入下一次迭代
# 将表达式产生的结果作为列表的一个元素,直到迭代对象迭代结束,返回新创建的列表
#等价于如下代码
#result = []
#for value in iterabe:
# if condition:
# result.append(expression)
#例子 求20以内的奇数的平方
squares = []
for i in range(1,21):
if i%2 == 1:
squares.append(i**2)
print(squares)
print ([i**2 for i in range(1,21) if i%2 == 1])
#支持多变量
x = [1,2,3]
y = [1,2,3]
results = [i*j for i,j in zip(x,y)]
print (results)
#支持嵌套循环
colors = ["black","while"]
sizes = ["S","M","L"]
tshirts = ["{} {}".format(color,size) for color in colors for size in sizes]
print (tshirts)
#其它解析语法的例子
#解析语法构造字典(字典推导)
squares = {i:i**2 for i in range(10)}
for k,v in squares.items():
print(k,": ",v)
#解析语法构造集合(集合推导)
squares = {i**2 for i in range(10)}
print(squares)
#生成器推导 可以进行迭代
squares = (i**2 for i in range(10))
for square in squares:
print(square)
#条件表达式 expr1 if condition else expr2 如果条件成立,就执行expr1 ,否则执行expr2
#将n的绝对值赋值给x
n = -10
x = n if n>=0 else -n
print (x)
print("======================三大神器 生成器 迭代器 装饰器====================")
#生成器 如果要计算列表中1到100每个数的平方,采用列表迭代的方式,占用大量内存,此时可以使用生成器
#生成器采用惰性计算,海量数据,不需要存储 一边迭代一边计算 每次只算出当次需要的值,后面的值用到的时候再计算
#生成器实际上一直在执行next()操作,取到下一个值,直到无值可取
#squares = (i**2 for i in range(10000))
#for i in squares
# pass
#采用生成器无需显示存储全部数据,节省内存
print (sum(i for i in range(101)))
#生成器函数 yield
#以生成斐波那契数列为例子 数列的前两个元素为1,1,之后的元素为其前两个元素之和
def fib(max):
ls = []
n,a,b = 0,1,1
while n < max:
#ls.append(a)
print (a) #每次打印输出斐波那契数列就可以了
a,b = b,a+b
n = n+1
return ls
fib(10)
#使用yield,遇到yield语句,会将后面的元素返回,当它执行完返回后,就会停在这里,知道进行下一次next操作,它会从停止的地方继续执行
def fib(max):
n,a,b = 0,1,1
while n < max:
yield a
a,b = b,a+b
n = n +1
fib(10)
for i in fib(10):
print(i)
#迭代器
#可直接用于for循环的对象称为可迭代对象:iterable
#列表 元组 字符串 字典 集合 文件 都是可迭代对象 我们可以使用isinstance()判断一个对象是否是iterable对象
from collections import Iterable
print(isinstance([1,2,3],Iterable))
print(isinstance({"name":"Sarah"},Iterable))
print(isinstance('Python',Iterable))
#生成器也是可迭代对象
squares = (i**2 for i in range(5))
print(isinstance(squares,Iterable))
#生成器不但可以用于for循环,还可以被next()函数调用
#每调用一次next函数,取出一个元素,直到没有数据可取,抛出StopIteration
print(next(squares))
print(next(squares))
#可以被next()函数调用并且不断返回下一个值,直到没有数据可取的对象称为迭代器: Iterator
#可以使用isinstance()判断一个对象是否是iterator对象
#生成器都是迭代器
from collections import Iterator
squares = (i**2 for i in range(5))
print(isinstance(squares,Iterator))
#列表 元组 字符串 字典 集合不是迭代器
print(isinstance([1,2,3],Iterator))
#可通过iter(iterable)创建迭代器
print(isinstance(iter([1,2,3]),Iterator))
#zip enumerate 等 itertools里的函数是迭代器
x = [1,2]
y = ["a","b"]
zip(x,y)
for i in zip(x,y):
print(i)
print(isinstance(zip(x,y),Iterator))
#文件是迭代器
with open("test.txt","r",encoding="utf-8") as f:
print(isinstance(f,Iterator))
#迭代器是可耗尽的
#range()不是迭代器,它不可以被next调用 且无法被耗尽,它是一种懒序列
numbers = range(10)
print(isinstance(numbers,Iterator))
#装饰器
#适用场景 需要对已经开发上线的程序添加某些功能,不能对程序中函数的源代码进行修改,不能改变程序中函数的调用方式
#函数对象 函数是python中的第一类对象 可以把函数赋值给变量 对该变量进行调用 可实现原函数的功能
def square(x):
return x**2
print(type(square)) #square 是function类的一个实例
pow_2 = square #可以理解为给这个函数起了一个别名pow_2
print(pow_2(5))
print(square(5))
#可以将函数作为参数传递
#高阶函数 接收函数作为参数,或者返回一个函数 满足这两个条件之一的函数称之为高阶函数
def square1(x):
return x**2
def pow_2(fun): #高阶函数
return fun
f = pow_2(square1) #将square1这个函数作为参数赋值给pow_2,它的返回值还是square1这个函数
print(f(8))
print(f==square1)
#嵌套函数 在函数的内部定义一个函数,并且调用
def outer():
print("outer is running")
def inner():
print("inner is running")
inner()
outer()
#闭包
#闭包是延伸了作用域的函数,如果一个函数定义在另一个函数作用域内,并且引用了外层函数的变量,则该函数称为闭包
#闭包是由函数及其相关的引用环境组合而成的实体(即 闭包=函数+引用环境),即不但返回内部函数,还返回外部环境的引用
def outer1():
x = 1
z = 10
def inner():
y = x + 100
return y,z
return inner
f = outer1() #f实际上包含了inner函数本身+outer函数的环境
print(f)
res = f()
print(res) #在inner函数中用到了outer函数的变量
#一旦在内层函数重新定义了相同名字的变量,则变量成为局部变量
def outer2():
x = 1
def inner():
#x = x + 100 #这里x定义在内层函数中,默认为局部变量,内层找不到x的值,所以报错
nonlocal x #用nonlocal声明x不是举报变量
x = x + 10
return x
return inner
f = outer2()
f()
#一个简单的装饰器
#嵌套函数的实现
import time
#定义timer装饰器函数
def timer(func):
#定义嵌套函数inner
def inner():
print("inner run")
start = time.time()
#在inner中运行传递过来的函数,并且在前后用两个时间戳获得它运行的时间
func()
end = time.time()
print("{}函数运行用时{:.2f}秒".format(func.__name__,(end-start)))
return inner()
#定义一个f1函数,我们希望它在运行的时候,统计一下用了多长时间
def f1():
print("f1 run")
time.sleep(1)
#将f1函数传递到timer()函数里面去,返回值是inner,此时返回值f1不单单包括inner函数,还包括timer函数的外部环境,包括参数func
f1 = timer(f1)
f1
#语法糖
@timer #相当于实现了f2 = timer(f2)
def f2():
print("f1 run")
time.sleep(1)
f2
#装饰有参函数
def timer1(func):
#定义嵌套函数inner
def inner(*args, **kwargs):
print("inner run")
start = time.time()
#在inner中运行传递过来的函数,并且在前后用两个时间戳获得它运行的时间
func(*args,**kwargs)
end = time.time()
print("{}函数运行用时{:.2f}秒".format(func.__name__,(end-start)))
return inner()
@timer1
def f3(n1,n2):
print("f3 run")
time.sleep(n)
#f3(3) 报错?
#装饰器本身也要传递一些额外的参数 理解闭包是关键
#何时执行装饰器 一装饰就执行 不必等调用
#通过python内部装饰器 @wraps可以将掩饰掉的原函数的属性重新回来