函数编程
1 函数的概念
1.1 没有函数的缺点
- 1、代码的组织结构不清晰,可读性差
- 2、遇到重复的功能只能重复编写实现代码,代码冗余
- 3、功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一管理且维护难度极大
1.2 函数
函数是指一段在一起的、可以做某一件事儿的程序
在程序设计中,常将一些常用的功能模块编写成函数,放在函数库中供公共选用。要善于利用函数,以减少重复编写程序段的工作量。
1.3 函数分类
内置函数
为了方便我们的开发,针对一些简单的功能,python解释器已经为我们定义好了的函数即内置函数。对于内置函数,我们可以拿来就用而无需事先定义,如len(),sum(),max()
自定义函数
很明显内置函数所能提供的功能是有限的,这就需要我们自己根据需求,事先定制好我们自己的函数来实现某种功能,以后,在遇到应用场景时,调用自定义的函数即可
2 函数语法
2.1 定义函数
def 函数名(参数1,参数2,参数3,...):
'''注释'''
函数体
return 返回的值
2.2 函数调用
1 语句形式:foo()
2 表达式形式:3*len('hello')
3 当中另外一个函数的参数:range(len('hello'))
注意 函数名后面有()
才是调用
2.3 函数的形式
#1、无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
#2、有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
#3、空函数:设计代码结构
#定义阶段
def tell_tag(tag,n): #有参数
print(tag*n)
def tell_msg(): #无参数
print('hello world')
#调用阶段
tell_tag('*',12)
tell_msg()
#结论:
#1、定义时无参,意味着调用时也无需传入参数
#2、定义时有参,意味着调用时则必须传入参数
# 空函数
def auth(user,password):
pass
def get(filename):
'''
:param filename:
:return:
'''
pass
2.4 Python函数的特点
- Python函数先定义 再调用
- 函数在定义阶段 ,只检测语法,不执行代码。也就说,语法错误在函数定义阶段就会检测出来,而代码的逻辑错误只有在执行时才会知道
3 函数返回值
无return->None
return 1个值->返回1个值
return 逗号分隔多个值->元组
什么时候该有返回值?
调用函数,经过一系列的操作,最后要拿到一个明确的结果,则必须要有返回值
通常有参函数需要有返回值,输入参数,经过计算,得到一个最终的结果
什么时候不需要有返回值?
调用函数,仅仅只是执行一系列的操作,最后不需要得到什么结果,则无需有返回值
通常无参函数不需要有返回值
注意 函数名()
这是函数调用表达式, 函数调用表达式的结果是 函数的返回值
4 函数参数
4.1 形参和实参
形参: 函数定义时候的参数; 实参:函数调用时给的参数
4.2 默认参数
可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
注意的问题:
1. 只在定义时赋值一次
2. 默认参数的定义应该在位置形参右面
3. 默认参数通常应该定义成不可变类型
4.3 可变参数
#可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。
# number是元组
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
#调用
>>> calc(1, 2)
>>> calc()
#Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:
nums = [1, 2, 3]
calc(*nums)
4.4 关键字参数
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict
'''
按照key=value的形式定义的实参
无需按照位置为形参传值
注意的问题:
1. 关键字实参必须在位置实参右面
2. 对同一个形参不能重复传值
'''
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
#定义
person('Adam', 45, gender='M', job='Engineer')
person('Bob', 35, city='Beijing')
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra)
4.5 命名关键字参数
对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。
如果要限制关键字参数的名字,就可以用命名关键字参数#
和关键字参数**kw
不同,命名关键字参数需要一个特殊分隔符*
,*
后面的参数被视为命名关键字参数。
# 只接收city和job作为关键字参数
def person(name, age, *, city, job):
print(name, age, city, job)
# 调用
#命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:
person('Jack', 24, city='Beijing', job='Engineer')
#命名关键字参数可以有缺省值,从而简化调用
def person(name, age, *, city='Beijing', job):
print(name, age, city, job)
如果没有可变参数,就必须加一个*
作为特殊分隔符。
4.6 参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def foo(x,y,*args,a=1,b,**kwargs):
print(x, y, args, a, b, kwargs)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
4.7 传参的简化语法
nums = [1, 2, 3]
calc(*nums) #*nums表示把nums这个list的所有元素作为可变参数传进去
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra) # **extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数 命名关键字参数也可以接收到
5 函数对象
5.1 函数是第一类对象 即函数是数据类型的一种
- 函数可以被引用
- 函数名就是变量名
- 函数可以当作参数传递
- 返回值可以是函数
- 函数是可以当作容器类型的元素
5.2 函数特殊用法
利用该特性,优雅的取代多分支的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]()
6 函数嵌套
6.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))
6.2 嵌套定义
def f1():
def f2():
def f3():
print('from f3')
f3()
f2()
f1()
f3() #报错,为何?
7 名称空间与作用域
7.1 名称空间
名称空间
,也可以成为 名字空间
、命名空间
: 意为 存放名字的地方。 名称空间正是存放 变量名 与值 绑定关系的地方
7.2 名称空间的加载顺序
执行 pyton test.py
1、python解释器先启动,因而首先加载的是:内置名称空间
2、执行test.py文件,然后以文件为基础,加载全局名称空间
3、在执行文件的过程中如果调用函数,则临时产生局部名称空间
7.3 作用域
由于名称空间的存在,所以产生了作用域
作用域是变量的可用范围
全局范围 全局作用域(内置名称空间与全局名称空间属于该范围):全局存活,全局有效 这种变量是 全局变量
局部范围 局部作用域(局部名称空间属于该范围):临时存活,局部有效 这种变量是 局部变量
函数命名空间的作用域
作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关
x=1
def f1():
def f2():
print(x)
return f2
x=100
def f3(func):
x=2
func()
x=10000
f3(f1())
查看作用域内的变量
globals() # 返回字典 全局作用域下所有的变量
locals() # 返回字典 本作用域(局部作用域)下所有的变量
7.4 LEGB
LEGB是Python中名字(变量)的查找顺序
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
7.5 global关键字和nonlocal关键字
global 关键字
global关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也可以不使用global关键字。
# 如果在局部要对全局变量修改,需要在局部使用 global 声明该全局变量
gcount = 0
def global_test():
global gcount
gcount+=1
print (gcount)
global_test()
# 在局部如果不声明全局变量,并且不修改全局变量。则可以正常使用全局变量
gcount = 0
def global_test():
print (gcount)
global_test()
nonlocal 关键字
nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量。
def func():
count = 1
def foo():
nonlocal count
count = 12
foo()
print(count)
func() #输出12
###################################
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
def make_counter_test():
mc = make_counter()
print(mc())
print(mc())
print(mc())
make_counter_test()
8 闭包函数
8.1 什么是闭包
- 闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境) (看不懂 没关系,去他妹的)
- 函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包
8.2 形成闭包的三个条件
1)必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套
2)内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量
3)外部函数必须返回内嵌函数——必须返回那个内部函数
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) #查看闭包的元素
8.3 闭包的意义与应用
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
应用领域:延迟计算(原来我们是传参,现在我们是包起来)
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'))
9 回调函数和高阶函数
一个函数就可以接收另一个函数作为参数,作为参数的函数被称之为回调函数,接收函数作为参数的函数被称作高阶函数
前面闭包中,可以把一个函数作为返回值返回的函数也是高阶函数
def f(x):
return x % 2
def add(x, y, f):
return f(x) + f(y)
# 函数 f 就是回调函数
# 函数 add 是高阶函数
def index(url):
def get():
return urlopen(url).read()
return get
#函数 index()也是高阶函数
9.1 Python内置高阶函数
- map()
- reduce()
- filter()
# 列表对象 的sort() 方法 就可以接收一个回调函数 作为参数
def f(item) {
return item['age']
}
list = [{'name':'曹操', 'age':10}, {'name':'曹植','age':12}, {'name':'罗永浩','age':23}]
list.sort(key=f)
# Python内置的 map() 函数是个高阶函数,接收回调函数作为参数
# map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回
def f(x):
return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
list(r) # 输出结果 [1, 4, 9, 16, 25, 36, 49, 64, 81]
# Python内置的reduce() 函数 也是高阶函数
# reduce把一个回调函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算
from functools import reduce
def add(x, y):
return x + y
reduce(add, [1, 3, 5, 7, 9]) # 求和计算25
def fn(x, y):
return x * 10 + y
reduce(fn, [1, 3, 5, 7, 9]) # 把列表中的成员组合成 整数 13579
# Python内置的 filter() 函数 同样是 高阶函数
# 和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) # # 结果: [1, 5, 9, 15] 只保留了奇数
# 注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。
9.2 排序算法 内置高阶函数
python内置的sorted()
函数就可以对list进行排序
sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
此外,sorted()
函数也是一个高阶函数,它还可以接收一个key
函数来实现自定义的排序,
# 按照绝对值排序
sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
# 字符串排序 不区分大小写
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
# 用一组tuple表示学生名字和成绩 按照成绩排序
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def my_sort(item):
return item[1]
sorted(L, key=my_sort)
9.3 最大值最小值 内置高阶函数
salaries={
'发哥':3000,
'铭哥':100000000,
'丹丹':10000,
'老朱':2000
}
# 迭代字典,取得是key,因而比较的是key的最大和最小值
>>> max(salaries)
>>> min(salaries)
# 可以取values,来比较
>>> max(salaries.values())
>>> min(salaries.values())
# 但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
>>> max(salaries,key=lambda k:salary[k])
>>> min(salaries,key=lambda k:salary[k])
10 匿名函数
匿名函数就是没有名字的函数
# 有名
def func(x,y,z=1):
return x+y+z
# 匿名
lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字
# 可以把匿名函数赋值给变量使其有名,但这样没意义了
func=lambda x,y,z=1:x+y+z
func(1,2,3)
# 有名函数:循环使用,保存了名字,通过名字就可以重复引用函数功能
# 匿名函数:一次性使用,随时随时定义,通常作为回调函数(高阶函数的参数)
list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
# 结果 [1, 4, 9, 16, 25, 36, 49, 64, 81]
11 递归函数
11.1 什么是递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
# 用递归实现 n 的阶乘
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
11.2 递归的层级限制
调用函数会产生局部的名称空间,占用内存,因为上述这种调用会无需调用本身,python解释器的内存管理机制为了防止其无限制占用内存,对函数的递归调用做了最大的层级限制(默认1000),称之为递归最大深度. 当然递归最大深度是可以修改的
import sys
sys.getrecursionlimit() # 获取当前递归最大深度
sys.setrecursionlimit(2000) # 设置递归最大深度
11.3 递归过程剖析
- 递归调用应该包含两个明确的阶段:回溯,递推
- 回溯就是从外向里一层一层递归调用下去,回溯阶段必须要有一个明确地结束条件,每进入下一次递归时,问题的规模都应该有所减少(否则,单纯地重复调用自身是毫无意义的)
- 递推就是从里向外一层一层结束递归
#2、示例+图解。。。
# 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))
11.4 尾递归优化
python中的递归效率低,需要在进入下一次递归时保留当前的状态,在其他语言中可以有解决方法:尾递归优化,即在函数的最后一步(而非最后一行)调用自己,但是python又没有尾递归,且对递归层级做了限制。
# 尾递归优化 举例 但是没有软用
def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num - 1, num * product)
11.5 递归应用:文件操作
# 统计目录大小
# 删除目录
# 复制目录
11.6 递归应用: 二分法
想从一个按照从小到大排列的数字列表中找到指定的数字,遍历的效率太低,用二分法(算法的一种,算法是解决问题的方法)可以极大低缩小问题规模
# 使用二分法 判断某个值 是否存在于列表中 类似于运算符 in
l=[1,2,10,30,33,99,101,200,301,311,402,403,500,900,1000] #从小到大排列的数字列表
def search(n,l):
print(l)
if len(l) == 0:
print('not exists')
return
mid_index=len(l) // 2
if n > l[mid_index]:
#in the right
l=l[mid_index+1:]
search(n,l)
elif n < l[mid_index]:
#in the left
l=l[:mid_index]
search(n,l)
else:
print('find it')
search(3,l)
# 使用二分法 判断 某个值在列表中第一次 出现的位置 类似于列表对象的 index方法
l=[1,2,10,30,33,99,101,200,301,402]
def search(num,l,start=0,stop=len(l)-1):
if start <= stop:
mid=start+(stop-start)//2
print('start:[%s] stop:[%s] mid:[%s] mid_val:[%s]' %(start,stop,mid,l[mid]))
if num > l[mid]:
start=mid+1
elif num < l[mid]:
stop=mid-1
else:
print('find it',mid)
return
search(num,l,start,stop)
else: #如果stop > start则意味着列表实际上已经全部切完,即切为空
print('not exists')
return
search(301,l)
12 装饰器
装饰器(decorator)就是闭包函数的一种应用场景
12.1 为何要用装饰器
开放封闭原则:对修改封闭,对扩展开放
12.2 什么是装饰器
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
12.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()
有参装饰器
def auth(driver='file'):
def auth2(func):
def wrapper(*args,**kwargs):
name=input("user: ")
pwd=input("pwd: ")
if driver == 'file':
if name == 'dandan' 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('dandan')
12.4 装饰器语法
被装饰函数的正上方,单独一行
@deco1
@deco2
@deco3
def foo():
pass
foo=deco1(deco2(deco3(foo)))
12.5 wraps
from functools import wraps
def deco(func):
@wraps(func) #加在最内层函数正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper
@deco
def index():
'''哈哈哈哈'''
print('from index')
print(index.__doc__)
14 偏函数
偏函数(Partial function) 是Python的functools
模块提供的功能
14.1 偏函数的意义
# int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:
int('12345')
# 但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换
int('12345', base=8)
int('12345', 16)
# 假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去
def int2(x, base=2):
return int(x, base)
int2('1000000')
int2('1010101')
# functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2()
import functools
int2 = functools.partial(int, base=2)
int2('1000000') # 64
int2('1010101') # 85
所以,简单总结functools.partial
的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
14.2 偏函数语法
import functools
functools.partial(函数, base=需要固定的参数)
# 注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:
int2('1000000', base=10) # 1000000
14.3 创建偏函数时的参数
创建偏函数时,实际上可以接收函数对象、*args
和**kw
这3个参数
# 接收**kw
int2 = functools.partial(int, base=2) # 实际上固定了int()函数的关键字参数base
# 接收 *args
max2 = functools.partial(max, 10)
# 实际上会把10作为*args的一部分自动加到左边,也就是: max2(5, 6, 7) 等同于 max(10,5,6,7)
15 Python内置函数
内置函数详情 查看 官方文档
format() 了解
#字符串可以提供的参数 's' None
>>> format('some string','s')
'some string'
>>> format('some string')
'some string'
#整形数值可以提供的参数有 'b' 'c' 'd' 'o' 'x' 'X' 'n' None
>>> format(3,'b') #转换成二进制
'11'
>>> format(97,'c') #转换unicode成字符
'a'
>>> format(11,'d') #转换成10进制
'11'
>>> format(11,'o') #转换成8进制
'13'
>>> format(11,'x') #转换成16进制 小写字母表示
'b'
>>> format(11,'X') #转换成16进制 大写字母表示
'B'
>>> format(11,'n') #和d一样
'11'
>>> format(11) #默认和d一样
'11'
#浮点数可以提供的参数有 'e' 'E' 'f' 'F' 'g' 'G' 'n' '%' None
>>> format(314159267,'e') #科学计数法,默认保留6位小数
'3.141593e+08'
>>> format(314159267,'0.2e') #科学计数法,指定保留2位小数
'3.14e+08'
>>> format(314159267,'0.2E') #科学计数法,指定保留2位小数,采用大写E表示
'3.14E+08'
>>> format(314159267,'f') #小数点计数法,默认保留6位小数
'314159267.000000'
>>> format(3.14159267000,'f') #小数点计数法,默认保留6位小数
'3.141593'
>>> format(3.14159267000,'0.8f') #小数点计数法,指定保留8位小数
'3.14159267'
>>> format(3.14159267000,'0.10f') #小数点计数法,指定保留10位小数
'3.1415926700'
>>> format(3.14e+1000000,'F') #小数点计数法,无穷大转换成大小字母
'INF'
#g的格式化比较特殊,假设p为格式中指定的保留小数位数,先尝试采用科学计数法格式化,得到幂指数exp,如果-4<=exp<p,则采用小数计数法,并保留p-1-exp位小数,否则按小数计数法计数,并按p-1保留小数位数
>>> format(0.00003141566,'.1g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留0位小数点
'3e-05'
>>> format(0.00003141566,'.2g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留1位小数点
'3.1e-05'
>>> format(0.00003141566,'.3g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留2位小数点
'3.14e-05'
>>> format(0.00003141566,'.3G') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留0位小数点,E使用大写
'3.14E-05'
>>> format(3.1415926777,'.1g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留0位小数点
'3'
>>> format(3.1415926777,'.2g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留1位小数点
'3.1'
>>> format(3.1415926777,'.3g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留2位小数点
'3.14'
>>> format(0.00003141566,'.1n') #和g相同
'3e-05'
>>> format(0.00003141566,'.3n') #和g相同
'3.14e-05'
>>> format(0.00003141566) #和g相同
'3.141566e-05'
evel()与exec()
#1、语法
# eval(str,[,globasl[,locals]])
# exec(str,[,globasl[,locals]])
#2、区别
#示例一:
s='1+2+3'
print(eval(s)) #eval用来执行表达式,并返回表达式执行的结果
print(exec(s)) #exec用来执行语句,不会返回任何值
'''
None
'''
#示例二:
print(eval('1+2+x',{'x':3},{'x':30})) #返回33
print(exec('1+2+x',{'x':3},{'x':30})) #返回None
# print(eval('for i in range(10):print(i)')) #语法错误,eval不能执行表达式
print(exec('for i in range(10):print(i)'))
compile()
# compile(str,filename,kind)
# filename:用于追踪str来自于哪个文件,如果不想追踪就可以不定义
# kind可以是:single代表一条语句,exec代表一组语句,eval代表一个表达式
s='for i in range(10):print(i)'
code=compile(s,'','exec')
exec(code)
s='1+2+3'
code=compile(s,'','eval')
eval(code)
16 练习
1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作
2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。
4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。字典中的value只能是字符串或列表
dic = {"k1": "v1v1", "k2": [11,22,33,44]}
7、利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']:
8、文件内容如下,标题为:姓名,性别,年纪,薪资
brotherming male 18 3000
brotherfa male 38 30000
dandan female 28 20000
junjun female 28 10000
要求: 从文件中取出每一条记录放入列表中, 列表的每个元素都是{'name':'egon','sex':'male','age':18,'salary':3000}的形式
9、 根据1得到的列表,取出薪资最高的人的信息
10、 根据1得到的列表,取出最年轻的人的信息
11、 根据1得到的列表,将每个人的信息中的名字映射成首字母大写的形式
12、 根据1得到的列表,过滤掉名字以a开头的人的信息
13、 使用递归打印斐波那契数列(前两个数的和得到第三个数,如:0 1 1 2 3 4 7...)
14、 一个嵌套很多层的列表,如l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]],用递归取出所有的值
15、编写装饰器,为函数加上统计时间的功能
16、 编写装饰器,为函数加上认证的功能
17、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码 注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式
18、编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录
19、编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
20、为题目五编写装饰器,实现缓存网页内容的功能: 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中
21、还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作
22、 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径可以指定
注意:时间格式的获取
import time
time.strftime('%Y-%m-%d %X')