函数编程

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内置函数

内置函数
abs() delattr() hash() memoryview() set()
all() dict() help() min() setattr()
any() dir() hex() next() slice()
ascii() divmod() id() object() sorted()
bin() enumerate() input() oct() staticmethod()
bool() eval() int() open() str()
breakpoint() exec() isinstance() ord() sum()
bytearray() filter() issubclass() pow() super()
bytes() float() iter() print() tuple()
callable() format() len() property() type()
chr() frozenset() list() range() vars()
classmethod() getattr() locals() repr() zip()
compile() globals() map() reversed() __import__()
complex() hasattr() max() round()

内置函数详情 查看 官方文档

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')

results matching ""

    No results matching ""