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

时间: 2024-12-27 23:52:50

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

致那些努力却迷茫的走在成功道路上人们

It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of

初学python 遇到的坑

这最近人工智能比较火,看了一下大多都是python的代码,最近看看python 的代码,一出来就遇到了坑,空格的问题先不说了直接上代码吧 # coding = utf-8 import urllib.request #import ssl #ssl._create_default_https_context = ssl._create_unverified_context response = urllib.request.urlopen('https://www.douban.com/') p

Python编码爬坑指南

自己最近有在学习python,这实在是一门非常短小精悍的语言,很喜欢这种语言精悍背后又有强大函数库支撑的语言.可是刚接触不久就遇到了让人头疼的关于编码的问题,在网上查了很多资料现在在这里做一番总结,权当一个记录也为后来的兄弟姐妹们服务,如果可以让您少走一些弯路本人将倍感荣幸. 先来描述下现象吧: import os for i in os.listdir("E:\Torchlight II"): print i 代码很简单我们使用os的listdir函数遍历了E:\Torchlight

Python一路走来 RabbitMQ

一:介绍:(induction) Rabbitmq 是一个消息中间件.他的思想就是:接收和发送消息.你可以把它想成一个邮政局.当你把你的邮件发送到邮箱的,首先你需要确认的是:邮政员先生能把你的邮件发送给你想发送的地方.在这个比喻中,rabbitmq就是一个邮箱.一个邮政局.一个邮递员. 在这里rabbitmq和传统邮政局的区别:rabbitmq不处理信纸.取而代之的是:接收.储存.发送二进制数的消息. rabbitmq和消息用如下专业术语: 生产者意思发送.A程序发送消息被称为:producer

Python一路走来 线程 进程

Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time   def show(arg):     time.sleep(1)     print 'thread'+str(arg)   for i in range(10):     t = thr

win7 python pdf2image入坑经历

Python开发菜鸟入坑 项目要求pdf转成图片,网上较多的方案对于windows极其不友好,wand,Pythonmagick(win下载地址:www.lfd.uci.edu/~gohlke/pythonlibs/#pythonmagick),imagemagick(win下载地址:www.imagemagick.org/download/),poppler(win下载地址://blog.alivate.com.au/poppler-windows/)等多个方案尝试后仍然不行,并且第三方的模块

对Python中一些“坑”的总结及技巧

一.赋值即定义 1.运行以下代码会出现报错 #!/usr/bin/env python #_*_conding:utf-8_*_ x = 100 def outer(): def inner(): x += 100 #其实这里等效于"x = x + 100",我们直到这是一个赋值语句,会优先计算右边的等式,即"x + 100".而在此时由于x变量赋值即定义,即此时的x和全局作用域的x并非同一个对象. print(x) return inner foo = outer

越走窄的道路,谁能带我飞

今天,早上起的很早,不到八点,被舍友的闹钟叫起. 吃过早餐,开始了一天的工作,这段时间已经进入稳定状态.过了刚开始的焦虑期,稳定状态下,内心很平静,相信只要坚持走,就没有到不了的终点.上午,下午都在平静的修改论文,晚上的时候,差不多已经改完了第一章第二小节.关于论文综述,嗯,写下来,总是会发现一些问题. 晚上,跑完步,看到优秀研究生传授经验的文章(这种文章,我认为相对于经验,那些获得的成就让能触动我).突然觉得这几年,自己的路越走越窄.跑步的时候,还想到,这几年如果在外工作的话,至少会收获一些财

写python的一些坑:pocket api,类型判断,unicode写文件,raise

1.pocket api pocket新版api不允许直接发送用户名跟密码,所以需要先申请app的consumer_key,然后再get_request_token,拿到一个request_token,再通过consumer_key和request_token用浏览器访问authorize网站,之后手工点击授权,然后返回access_token.今后在应用里使用consumer_key和access_token就可以向使用账号的操作(添加.删除)了. 用python很好实现. 2.python类