### 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格式的(即使那个妈蛋文件)但是复制到这里就不行了,各位就是看看吧,有问题的话下面说一下.内置函数下次再说

python 之走坑的道路的更多相关文章

  1. Python 的赋值坑 , a=b=c=1???

    原文地址:https://www.v2ex.com/amp/t/443384 Python 的赋值坑 , a=b=c=1??? 今天回答了一个主题, 一不小心进入了一个坑, 耗费了好多时间终于弄懂了我 ...

  2. 跳出python的各种坑(1)

    2017-11-1915:38:17 一定要跳出python的各种坑,一开始遇到的好多思维上的认知错误,因为刚开始学习,对python是个什么都不清楚,所以记录一下自己遇到的各种坑.不用担心自己遇到的 ...

  3. Python语言防坑小技巧

    Python语言防坑小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.赋值即定义  1>.运行以下代码会出现报错 #!/usr/bin/env python #_*_ ...

  4. python socket.io 坑。

    python下star最高的是https://github.com/miguelgrinberg/python-socketio 是flask作者写的.client server都有了,而且还提供了a ...

  5. Python一路走来 RabbitMQ

    一:介绍:(induction) Rabbitmq 是一个消息中间件.他的思想就是:接收和发送消息.你可以把它想成一个邮政局.当你把你的邮件发送到邮箱的,首先你需要确认的是:邮政员先生能把你的邮件发送 ...

  6. Python一路走来 线程 进程

    Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env pytho ...

  7. 初学python 遇到的坑

    这最近人工智能比较火,看了一下大多都是python的代码,最近看看python 的代码,一出来就遇到了坑,空格的问题先不说了直接上代码吧 # coding = utf-8 import urllib. ...

  8. Python的入坑之路(1)

    (故事背景:由于涉及到机密的原因,暂时不方便透露,待后期再写.) 国庆长假过完之后,回来上班第二天下午,Boss跟龙哥把我叫了出去,问我要不要转人工智能.一脸懵逼的我,带着一脸懵逼听Boss说人工智能 ...

  9. win7 python pdf2image入坑经历

    Python开发菜鸟入坑 项目要求pdf转成图片,网上较多的方案对于windows极其不友好,wand,Pythonmagick(win下载地址:www.lfd.uci.edu/~gohlke/pyt ...

随机推荐

  1. 对百度WebUploader的二次封装,精简前端代码之图片预览上传(两句代码搞定上传)

    前言 本篇文章上一篇: 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传) 此篇是在上面的基础上扩展出来专门上传图片的控件封装. 首先我们看看效果: 正文 使用方式同 ...

  2. lua table表

    lua table表 语法结构 创建一个 table 直接使用 "{}" 即可 table1 = {} -- 赋值 table1["name"] = " ...

  3. Mvc自定义验证

    假设我们书店需要录入一本书,为了简单的体现我们的自定义验证,我们的实体定义的非常简单,就两个属性,一个名称Name,一个出版社Publisher. public class BookInfo { pu ...

  4. 【Java 并发】详解 ThreadPoolExecutor

    前言 线程池是并发中一项常用的优化方法,通过对线程复用,减少线程的创建,降低资源消耗,提高程序响应速度.在 Java 中我们一般通过 Exectuors 提供的工厂方法来创建线程池,但是线程池的最终实 ...

  5. 记一次使用修改字节码的方法解决java.lang.NoSuchMethodError

    接兔兔国际sdk ane 充值界面选择兔币充值就会闪退, 观察logcat 04-19 10:10:54.224: E/AndroidRuntime(20315): FATAL EXCEPTION: ...

  6. 今天开始上Linux运维课。

    2017年4月25日,北京.沙河老男孩教育,Linux运维. 我是其中一员,希望顺利!

  7. [ext4]010 磁盘布局 - 如何查找inode的磁盘位置

    在linux系统中,任何一个文件,都有一个inode与其对应,也就是说,在一个文件系统中,一个文件都有唯一的ino来标示他,那么在ext4系统中,ino是如何确定的哪? 当我们新创建的文件或目录时,会 ...

  8. CSS的position/float/display

    一.position position属性取值:static(默认).relative.absolute.fixed.inherit. postision:static:始终处于文档流给予的位置.它可 ...

  9. Gym - 101102C线段树

    Judge Bahosain was bored at ACM AmrahCPC 2016 as the winner of the contest had the first rank from t ...

  10. mysql数据库面试总结

    数据库优化 建表优化 1)数据库范式 l 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列. 如电话列可进行拆分---家庭电话.公司电话 l 第二范式(2NF):首先是 1NF,另外包 ...