函数草稿

阅读目录

一:为何用函数之不使用函数的问题
#组织结构不清晰
#代码冗余
#无法统一管理且维护难度大


二:函数分类:
1. 内置函数
2. 自定义函数


三:为何要定义函数
函数即变量,变量必须先定义后使用,未定义而直接引用函数,就相当于在引用一个不存在的变量名
代码演示?

四:定义函数都干了哪些事?
只检测语法,不执行代码


五:如何定义函数(函数名要能反映其意义)
def ...


六:定义函数的三种形式
无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
空函数:设计代码结构


七 :函数的调用
1 先找到名字
2 根据名字调用代码

八:函数调用的三种形式
1 语句形式:foo()
2 表达式形式:3*len('hello')
4 当中另外一个函数的参数:range(len('hello'))

九:函数的参数:
1 形参和实参定义
2 形参即变量名,实参即变量值,函数调用则将值绑定到名字上,函数调用结束,解除绑定
3 具体应用
位置参数:按照从左到右的顺序定义的参数
位置形参:必选参数
位置实参:按照位置给形参传值

关键字参数:按照key=value的形式定义实参
无需按照位置为形参传值
注意的问题:
1. 关键字实参必须在位置实参右面
2. 对同一个形参不能重复传值

默认参数:形参在定义时就已经为其赋值
可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
注意的问题:
1. 只在定义时赋值一次
2. 默认参数的定义应该在位置形参右面
3. 默认参数通常应该定义成不可变类型


可变长参数:
针对实参在定义时长度不固定的情况,应该从形参的角度找到可以接收可变长实参的方案,这就是可变长参数(形参)
而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参也应该有两种解决方案,分别是*args,**kwargs

===========*args===========
def foo(x,y,*args):
print(x,y)
print(args)
foo(1,2,3,4,5)

def foo(x,y,*args):
print(x,y)
print(args)
foo(1,2,*[3,4,5])


def foo(x,y,z):
print(x,y,z)
foo(*[1,2,3])

===========**kwargs===========
def foo(x,y,**kwargs):
print(x,y)
print(kwargs)
foo(1,y=2,a=1,b=2,c=3)

def foo(x,y,**kwargs):
print(x,y)
print(kwargs)
foo(1,y=2,**{'a':1,'b':2,'c':3})


def foo(x,y,z):
print(x,y,z)
foo(**{'z':1,'x':2,'y':3})

===========*args+**kwargs===========

def foo(x,y):
print(x,y)

def wrapper(*args,**kwargs):
print('====>')
foo(*args,**kwargs)

命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
可以保证,传入的参数中一定包含某些关键字
def foo(x,y,*args,a=1,b,**kwargs):
print(x,y)
print(args)
print(a)
print(b)
print(kwargs)

foo(1,2,3,4,5,b=3,c=4,d=5)
结果:
1
2
(3, 4, 5)
1
3
{'c': 4, 'd': 5}


=======================本节课新内容==========================
一:函数对象:函数是第一类对象,即函数可以当作数据传递
1 可以被引用
2 可以当作参数传递
3 返回值可以是函数
3 可以当作容器类型的元素
#利用该特性,优雅的取代多分支的if
def foo():
print('foo')

def bar():
print('bar')

dic={
'foo':foo,
'bar':bar,
}
while True:
choice=input('>>: ').strip()
if choice in dic:
dic[choice]()

二:函数的嵌套
1 函数的嵌套调用
def max(x,y):
return x if x > y else y

def max4(a,b,c,d):
res1=max(a,b)
res2=max(res1,c)
res3=max(res2,d)
return res3
print(max4(1,2,3,4))

2 函数的嵌套定义
def f1():
def f2():
def f3():
print('from f3')
f3()
f2()

f1()
f3() #报错


三 名称空间和作用域:
名称空间:存放名字的地方,三种名称空间,加载顺序是?
名字的查找顺序
作用域即范围(作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关)

查看作用域:globals(),locals()

global
nonlocal


LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间



四:闭包:内部函数包含对外部作用域而非全局作用域的引用

def counter():
n=0
def incr():
nonlocal n
x=n
n+=1
return x
return incr

c=counter()
print(c())
print(c())
print(c())
print(c.__closure__[0].cell_contents) #查看闭包的元素



闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
应用领域:延迟计算
from urllib.request import urlopen

def index(url):
def get():
return urlopen(url).read()
return get

baidu=index('http://www.baidu.com')
print(baidu().decode('utf-8'))


五: 装饰器

1 为何要用装饰器:
开放封闭原则:对修改封闭,对扩展开放

2 什么是装饰器
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。

3. 先看简单示范
import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper

@timmer
def foo():
time.sleep(3)
print('from foo')
foo()


4
def auth(driver='file'):
def auth2(func):
def wrapper(*args,**kwargs):
name=input("user: ")
pwd=input("pwd: ")

if driver == 'file':
if name == 'egon' and pwd == '123':
print('login successful')
res=func(*args,**kwargs)
return res
elif driver == 'ldap':
print('ldap')
return wrapper
return auth2

@auth(driver='file')
def foo(name):
print(name)

foo('egon')

5 装饰器语法:
被装饰函数的正上方,单独一行
@deco1
@deco2
@deco3
def foo():
pass

foo=deco1(deco2(deco3(foo)))



六:迭代器
迭代的概念:重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
# while True: #只满足重复,因而不是迭代
# print('====>')

#迭代
l=[1,2,3]
count=0
while count < len(l): #只满足重复,因而不是迭代
print('====>',l[count])
count+=1


为何要有迭代器?
可迭代的对象?
哪些是可迭代对象?
迭代器?
l={'a':1,'b':2,'c':3,'d':4,'e':5}
i=l.__iter__() #等于i=iter(l)

print(next(i))
print(next(i))
print(next(i))
StopIteration?

for循环

迭代器的优缺点:
优点:
提供统一的且不依赖于索引的迭代方式
惰性计算,节省内存
缺点:
无法获取长度
一次性的,只能往后走,不能往前退

迭代器协议



七 生成器
yield:
把函数做成迭代器
对比return,可以返回多次值,挂起函数的运行状态



# def foo():
# return 1
# return 2
# return 3
#
# res=foo()
# print(res)


def foo():
yield 1
yield 2
yield 3

res=foo()
print(res)

from collections import Iterable,Iterator
print(isinstance(res,Iterator))

print(next(res))
print(next(res))
print(next(res))


应用一:
def counter(n):
print('start')
i=0
while i < n:
yield i
i+=1
print('end')

c=counter(5)
# print(next(c)) #0
# print(next(c)) #1
# print(next(c)) #2
# print(next(c)) #3
# print(next(c)) #4
# print(next(c)) #5 --->没有yield,抛出StopIteration


for i in counter(5):
print(i)

应用二:管道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()
if line:
yield line
else:
time.sleep(0.5)

def grep(pattern,lines):
for line in lines:
if pattern in line:
yield line

for i in grep('python',tail('a.txt')):
print(i)


#协程函数
def eater(name):
print('客人%s来吃饭了' %name)
food_list=[]
while True:
food=yield food_list
food_list.append(food)
print('%s 吃了 %s' %(name,food))

e=eater('egon')
e.send(None) #next(e) #初始化装饰器,
e.close() #关闭

面向过程编程:
import os
def init(func):
def wrapper(*args,**kwargs):
g=func(*args,**kwargs)
next(g)
return g
return wrapper



def search(file_dir,target):
for par_dir,_,files in os.walk(file_dir):
for file in files:
filepath='%s\%s' %(par_dir,file)
target.send(filepath)

@init
def opener(target):
while True:
filepath=yield
with open(filepath) as f:
target.send((f,filepath))
@init
def cat(target):
while True:
res=False
f,filepath=yield res
for line in f:
print(line,end='')
res=target.send((line,filepath))
if res:
break


@init
def grep(pattern,target):
res = False
while True:
line,filepath=yield res
res=False
if pattern in line:
res=True
target.send(filepath)

@init
def printer():
while True:
filepath=yield
print(filepath)

search(r'C:\Users\Administrator\PycharmProjects\test\字符编码\a',
opener(cat(grep('python',printer()))))



八:生成器表达式
with open(r'C:\Users\Administrator\PycharmProjects\test\字符编码\spider.py',encoding='utf-8') as f:
g=max(len(line.strip()) for line in f)
print(g)


九:函数的递归调用
图解:递推和回溯

# salary(5)=salary(4)+300
# salary(4)=salary(3)+300
# salary(3)=salary(2)+300
# salary(2)=salary(1)+300
# salary(1)=100
#
# salary(n)=salary(n-1)+300 n>1
# salary(1) =100 n=1

def salary(n):
if n == 1:
return 100
return salary(n-1)+300

print(salary(5))


十:二分法
l=[1,2,10,2,30,40,33,22,99,31]
def search(num,l):
print(l)
if len(l) > 1:
mid=len(l)//2
if num > l[mid]:
#in the right
l=l[mid:]
search(num,l)
elif num < l[mid]:
#in the left
l=l[:mid]
search(num,l)
else:
print('find it')
else:
if num == l[0]:
print('find it')
else:
print('not exists')

search(100,l)
posted @ 2017-05-27 17:06  ForeverPine  阅读(100)  评论(0)    收藏  举报
TOP