python 之走坑的道路
### python之 继续走函数的坑
上篇文章简单介绍了函数的一些简单的使用,这次继续踩函数的坑
1.函数对象
函数其实也可以当做一个参数传给另一个函数,也可以使用赋值的方式来给另一个,而且这两个的内存地址都是一
样的
def f1():
print('这个是引用的函数测试')
func = f1
print(f1) # 不加括号为foo函数的内存地址 这个其实很有用处,稍后解释
print(func) # func指向foo内存地址
func() # foo内存地址,加()执行
####函数可以被引用
# def f1():
# print('这个是引用的函数测试')
#
# func = f1
# print(f1) # 不加括号为foo函数的内存地址
# print(func) # func指向foo内存地址
# func() # foo内存地址,加()执行
#########函数可以当做参数
# def f ():
# print('this is from f')
#
# def f2(func): ####这里就是吧把函数当做一个参数传递进去
# func()
# print('this is from f2')
# f2(f)
###########函数可以作返回值
# def foo():
# print('from foo')
# def bar(func):
# return func
# f=bar(foo)
# print(f)
# f()
# '''
# 结果
# <function foo at 0x7f9491f04f28>
# from foo
# '''
###########函数可以当作容器类型的元素
#### 容器对象(list、dict、set等)中可以存放任何对象,包括整数、字符串,函数也可以作存放到容器对象中
#### 这个在我练习的时候用到的,而且很是有用,
def foo():
print('from foo')
dic={'func':foo}
foo()
print(dic['func'])
dic['func']()
**例子如下
def select(sql):
print('========>select')
def insert(sql):
print('========>add')
def delete(sql):
print('=======>delete')
def update(sql):
print('-=---->update')
func_dic={
'select':select,
'update':update,
'insert':insert,
'delete':delete
}
def main():
while True:
sql = input('sql: ').strip()
if not sql:continue
l = sql.split()
cmd = l[0]
if cmd in func_dic:
func_dic[cmd](l)
#按照以前的思路肯定这么写,写的超多,而且很多都是重复的,用了上面的方法就很简单了....
def main():
while True:
sql = input('sql: ').strip()
if not sql:continue
l = sql.split()
if 'select' == l[0]:
select(l)
if 'update' == l[0]:
update(l)
if 'delete' == l[0]:
delete(l)
if 'insert' == l[0]:
insert(l)
####函数的嵌套
# x= 1
# def f(x):
# # print(x)
# def f2(x):
# print(x)
# def f3(x):
# print(x)
# f3(2)
# f2(3)
# f(4)
#如果函数里面没有写f3(2),f2(3) 这种东西,那么他就不会有任何的输出
###原因很简单,看下面的例子,我定义了三个函数,但是当我调用的时候我只调用了f()这个函数,
###f2(),f3()这两个函数虽然定义了,但是我没有调用(注意,虽然我f2()与f3()在大函数f()当中,但是
###他没有被调用啊,虽然你调用了f(),但是他不会主动去调用自己函数内部的东西
x= 1
def f(x):
print(x)
def f2():
print('from 2')
def f3():
print('from3')
# f3(2)
# f2(3)
f(4)
2.说说函数的名称空间和作用域
先说说怎么定义一个名字
import time
name = 'lisi'
def foo():
pass
class Foo:
pass
上面这些都是在定义一个名字,当你调用的时候,如果没有像上面这么定义,那么就会报这个错误'NameError: name 'name' is not
defined' 也就是说当我们导入 包名 定义函数 定义类 定义一个变量的时候 就是在定义一个名字.
可以简单的理解为是在声明一个变量(个人认为,不是很准确).
python中有三种函数名称空间
1. 内置名称空间
这个是随着python解释器的启动而生成,比如:
max()
min()
sum()
2. 全局名称空间:文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入改空间
在我理解当中就是一个全局变量的含义,对于python来说,很好判断,就是顶格写.前面没有空格的那种.
#x=1
# if x ==1 :
# y=2
# import time
# def func():
# pass
#
# class Foo:
# pass
3 局部名称空间: 调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束解绑定
也就是说只在函数内部生效
# x=10000
# def func():
# x=1
# def f1():
# pass
print(x)##这里的x打印的不是1,而是10000
python中的作用域: 安照博主浅显的理解就是你定义的那个'变量' 生效的范围,
作用域的范围:
1.全局作用域 :全局名称空间,内置名称空间
2.局部作用域 :局部名称空间
名字('变量')的查找顺序: 总的来说 局部作用域----->全局作用域
局部名称空间--->全局名称空间--->内置名称空间
#查看全局作用域内的名字:gloabls()
#查看局局作用域内的名字:locals()
他返回的是一个字典的格式,print(gloabls()), print(locals())
可以查看里面的函数是不是全局还是局部
生效时长:
#全局作用域:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕
#局部作用域的名字:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效
栗子:
x=111
def f1():
def f2():
print(x)
def f3():
x=1000
print(x)
f3() ###先找自身,找到即返回
f2() ###这个找自身的范围,自身没有找上一级,上一级没有在往上找
f1()
结果: 这个可以很好的说明作用域
''' 111
111
1000
'''
3.闭包函数:
==========
顾名思义,闭包就是把一个已经存在的函数封装起来,但是他封装的不只是自己,还有上层的作用域
函数嵌套的一种方式,必须遵守以下规则:
a. 定义在内部函数
b. 包含对外部作用域而非全局作用域的引用,该内部函数就成为闭包函数
简单的栗子:
def foo ():
x=1000
def bar():
print(x)
return bar ###注意这里返回的是一个内存地址,而不是函数结果
print(foo())
#这里打印的是一个内存地址,不是结果当然如果你非得相想用foo,那你可以foo()()
f = foo()
f()
应用:
惰性计算:
from urllib.request import urlopen
def index(url):
def get():
return urlopen(url).read()
return get
content=index('http://baidu.com')
# print(content().decode('utf-8'))
# print(content.__closure__[0].cell_contents)
其实闭包函数多用于装饰器,
装饰器
=====
###### 装饰器: 就是一种工具,可以添加功能的一个函数,
他本身可以是任何可以调用的对象,被装饰的对象也可以是任意可调用的对象
###### 为啥用装饰器:
1.开放封闭原则: 对修改是封闭的,对扩展是开放的
2.为了在不修改被装饰对象的源代码以及调用方式的前提下,为其添加新功能,
###### 一个简单例子
import time
def timmer(fuc):
def wrapper():
start_time = time.time()
fuc()
stop_time = time.time()
print("run time is %s" % (stop_time-start_time))
return wrapper
@timmer
def index():
time.sleep(3)
print('welcome to new world')
index()
这个本来是没有统计运行时间的功能,但是使用装饰器给添加上一个,
而且并没有对原有的代码进行修改.
###### 流程分析
index()这个函数是原有的,我需要在添加,一个时间的函数,所以我写了一个闭包函数(装饰器就用闭包函数来实现),4
这个函数就是为了添加一个计时的功能,
def timmer(fuc): #这个地方必须接受一个值,而且这个值是一个函数.
def wrapper(): #这个地方的参数根据被装饰函数来添加 ,开始运行
start_time = time.time()
fuc() #开始执行函数,执行的函数就是被装饰的函数
stop_time = time.time()
print("run time is %s" % (stop_time-start_time))
return wrapper ##这个是返回的一个值,这个值是wrapper函数+它上面的作用域.
def index():
time.sleep(3)
print('welcom to new world!!!!!!')
f = timmer(index) ##这个时候返回的wrapper() + 上面的作用域 ,总的是个内存地址
f() 就可以执行
结果:
'''
welcom to new world!!!!!!
run time is 3.008370876312256
'''
但是为了保证调用的是index()而不是其他的函数
于是对函数又重新赋值,这样操作的话,就会发现和原来调用一样,但是此时的index()不是 原来定义的那个函数了而是wrapper()+上面的作用域 的整个值
在index()上加了@就可以这么调用了
index=timmer(index)
index()
###### 有返回值的函数
如果有返回值的函数,也是可以解决的,
def timmer(fuc):
def wrapper():
start_time = time.time()
res=fuc() ###在这里就接受好了.
stop_time = time.time()
print("run time is %s" % (stop_time-start_time))
return res ##然后返回去
return wrapper
@timmer ##修饰一下
def index():
time.sleep(3)
print('welcom to new world!!!!!!')
return 1 ##这里有个返回值.
###### 有参数的函数
import time
def timmer(fuc):
def wrapper(*args,**kwargs): #在这里就传参数好了
start_time = time.time()
fuc(*args,**kwargs) #当然在这里也得需要.
stop_time = time.time()
print("run time is %s " %(stop_time-start_time))
result wrapper
def hompage(name):
time.sleep(1)
print('welcome to %s' % name)
###### 例子
login_user={'user':None,'status':False} ##这个是保存一个状态
def auth(func):
def wrapper(*args,**kwargs):
if login_user['user'] and login_user['status']: ##这个是检查状态,如果通过,则直接返回函数.
## 不在进行下面的判断.如果你问这个有啥用,当你
##执行的时候就会发现,如果咩有,你得输入两次
res = func(*args,**kwargs)
return res
else:
name = input('name: ')
pwd = input('password: ')
if name == 'liukang' and pwd == '123':
login_user['user']=name
login_user['status']=True
res=func(*args,**kwargs)
return res
else:
print('auth failed')
return wrapper
##底下是主页,现在要添加一个认证的功能.
@auth
def index():
print('welcome to index page')
@auth
def home(name):
print('%s welcome to home page' %name)
index()
home('liukang')def ha()
###### 函数的迭代器
为啥用迭代:
1.它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。
2.对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式
迭代的概念:
重复+上一次迭代的结果为下一次迭代的初始值,重复的过程称为迭代,每次重复即一次迭代,
并且每次迭代的结果是下一次迭代的初始值
迭代器的优点和缺点
优点:
1.提供了一种不依赖下标的迭代方式
2.就跌迭代器本身来说,更节省内存
缺点:
1. 无法获取迭代器对象的长度
2. 不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退
可迭代的对象 都有 __iter__方法
# [1,2].__iter__()
# 'hello'.__iter__()
# (1,2).__iter__()
#
# {'a':1,'b':2}.__iter__()
# {1,2,3}.__iter__()
迭代器:执行__iter__方法,得到的结果就是迭代器,迭代器对象有__next__方法,这底下都是迭代器
# i=[1,2,3].__iter__()
# print(i)
# print(i.__next__())
# print(i.__next__())
# print(i.__next__())
# print(i.__next__()) #如果没有元素的话就抛出异常:StopIteration
如何判断一个对象是否可迭代呢
from collections import Iterable,Iterator
##以下是各个对象的测试
# 'abc'.__iter__()
# ().__iter__()
# [].__iter__()
# {'a':1}.__iter__()
# {1,2}.__iter__()
# f=open('a.txt','w')
# f.__iter__()
#下列数据类型都是可迭代的对象
# print(isinstance('abc',Iterable))
# print(isinstance([],Iterable))
# print(isinstance((),Iterable))
# print(isinstance({'a':1},Iterable))
# print(isinstance({1,2},Iterable))
# print(isinstance(f,Iterable))
但是!!!
#只有文件是迭代器对象
# print(isinstance('abc',Iterator))
# print(isinstance([],Iterator))
# print(isinstance((),Iterator))
# print(isinstance({'a':1},Iterator))
# print(isinstance({1,2},Iterator))
# print(isinstance(f,Iterator))
可迭代对象:只有__iter__方法,执行该方法得到的迭代器对象
迭代协议:
对象有__next__
对象有__iter__,对于迭代器对象来说,执行__iter__方法,得到的结果仍然是它本身
###### 生成器
#生成器函数:只要函数体包含yield关键字,该函数就是生成器函数
生成器就是迭代器
如下的例子: 这种的的话只能返回单个的值,如果要是返回全部的话就得麻烦下(不用生成器的前提)
# def foo():
# return 1
# return 2
# return 3
# return 4
# res1=foo()
# print(res1)
# res2=foo()
# print(res2)
如果这样:
def foo():
# print('first')
# yield 1
# print('second')
# yield 2
# print('third')
# yield 3
# print('fourth')
# yield 4
# print('fifth')
#
# g=foo()
# for i in g:
# print(i)
其实就是这么做的:
# print(g)
# print(next(g)) #触发迭代器g的执行,进而触发函数的执行,所以生成器就是一个迭代器
# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))
yield的功能:
1.相当于为函数封装好__iter__和__next__
2.return只能返回一次值,函数就终止了,
而yield能返回多次值,每次返回都会将函数暂停,下一次next会从
上一次暂停的位置继续执行
例子: 模拟tail -f 加 grep的功能
#tail -f a.txt | grep 'python'
import time
def tail(filepath):
with open(filepath,encoding='utf-8') as f:
f.seek(0,2)
while True:
line=f.readline().strip()
if line:
yield line
else:
time.sleep(0.2)
def grep(pattern,lines):
for line in lines:
if pattern in line:
yield line
g=grep('python',tail('a.txt'))
print(g)
for i in g:
print(i)
#######说明一下啊,我这个格式是markdown格式的(即使那个妈蛋文件)但是复制到这里就不行了,各位就是看看吧,有问题的话下面说一下.内置函数下次再说