当前位置:   article > 正文

日知录(四):python函数理解_def create_counter():counter1-create_counter()

def create_counter():counter1-create_counter()

一、返回函数

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
def函数可以嵌套在另一个def函数之中。调用外层函数时,运行到的内层def语句仅仅是完成对内层函数的定义,而不会去调用内层函数,除非在嵌套函数之后又显式的对其进行调用。

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

f = lazy_sum(1, 3, 5, 7, 9)
print(f())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

1.这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。
2.当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数。
3.打个比方: 一个大盒子,内部有一个小盒子,小盒子里用到一些东西是来自这个大盒子,那么这些来自大盒子的东西,就是闭包。

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
print(f1(),f2(),f3())

·
·
·
9 9 9 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

1.在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。
2.原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。
3.返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量
4. fs.append(f) 这里的f是函数,fs是个list,此处并不是对f()进行了调用,输出3个相同引用状态的f()函数f1(), f2(), f3() ,输出3个相同的, 当i=3时刻对应的f()函数值, 即f(3)=9

eg1

利用闭包返回一个计数器函数,每次调用它返回递增整数

# -*- coding: utf-8 -*-
def createCounter():        #法一
    i=0    #  此处i在外函数定义, 因为内函数引用了i, 变量i会保存在内容中  ,不加这一行的话返回结果为1,1,1···
    def counter():
        nonlocal i    # 声明变量i为局部变量
        i=i+1         # 声明后变量i可以修改     
        return i
    return counter

# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('测试通过!')
else:
    print('测试失败!')


# -*- coding: utf-8 -*-
def createCounter():    # 法二 选择数值可变但是地址不变的变量类型——数组
    i = [0] # 初始化数组    
    def counter():
        i[0] += 1 #不修改数组, 只修改数组中元素数值, 数组的地址不变        
        return i[0]
    return counter

# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('测试通过!')
else:
    print('测试失败!')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

关于法二:
在counter函数中,我们并不能改变的i 值,但是如果我们传的i 是一个列表的话,其实本质上传递的是一个地址,在这个地址上我们可以做任意改变.只要这个列表还是这个列表,他的地址就不会变.利用这种特性,我们就可以随便折腾了.

二、匿名函数

灵活运用lambda表达式
只能有一个表达式,不用写return

三、装饰器

装饰器的作用就是可以定义之后,给每个函数都装饰上, 显示程序执行的开始、结束,显示函数执行时间
贴一个up主的讲解,十分清楚。

https://www.bilibili.com/video/BV11s411V7Dt/

step1:在求出素数的同时并给出系统求取素数所需的总时间
可读性低,prime_nums()中既有逻辑又有计时,为了分开这两部分并且规范,所以有了step2

import time

def is_prime (num):
    if num<2:
        return False
    elif num ==2:
        return True
    else:
        for i in range (2,num):
            if num %i==0:
                return False
        return True

def prime_nums():
    t1=time.time()
    for i in range(2,10000):
        if is_prime(i):
            print(i)
    t2 =time.time()
    print(t2-t1)

prime_nums()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

step2

import time
def display_time(func):
    def wrapper():
        t1 = time.time()
        func ()
        t2 = time.time()
        print(t2 - t1)
    return wrapper

def is_prime (num):
    if num<2:
        return False
    elif num ==2:
        return True
    else:
        for i in range (2,num):
            if num %i==0:
                return False
        return True
@display_time
def prime_nums():

    for i in range(2,10000):
        if is_prime(i):
            print(i)

prime_nums()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

step3:如果prime_nums()函数有返回值时,计算有多少个素数。1229个素数。

import time
def display_time(func):
    def wrapper():
        t1 = time.time()
        result=func ()
        t2 = time.time()
        print('Total time is:{:.4}s '.format(t2-t1))
        return result
    return wrapper

def is_prime (num):
    if num<2:
        return False
    elif num ==2:
        return True
    else:
        for i in range (2,num):
            if num %i==0:
                return False
        return True
@display_time
def count_prime_nums():
    count=0
    for i in range(2,10000):
        if is_prime(i):
            count =count+1
    return count

count =count_prime_nums()
print(count)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

step4:从2到任意数字,求取素数。

import time
def display_time(func):
    def wrapper(*args):
        t1 = time.time()
        result=func (*args)
        t2 = time.time()
         print("Total time is:{:.4f}s ".format(t2-t1))
        return result
    return wrapper

def is_prime (num):
    if num<2:
        return False
    elif num ==2:
        return True
    else:
        for i in range (2,num):
            if num %i==0:
                return False
        return True
@display_time
def count_prime_nums(maxnum):
    count=0
    for i in range(2,maxnum):
        if is_prime(i):
            count =count+1
    return count

count =count_prime_nums(10000)
print(count)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

四、偏函数

当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
在这里插入图片描述

五、模块

创建自己的模块时,要注意:

1.模块名要遵循Python变量命名规范,不要使用中文、特殊字符;
2.模块名不要和系统模块名冲突,最好先查看系统是否已存在该模块,检查方法是在Python交互环境执行import abc,若成功则说明系统存在此模块。

3.每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。init.py可以是空文件,也可以有Python代码。一个目录+init.py 它就是包;没有__init__.py的就是个普通目录。

if name== ‘main’
如果模块是被导入的,则被导入的模块不直接运行。要进行调用,用 if_name_ == ‘main’ 来规范调用。
当模块直接运行的时候,就执行 if name== ‘main’ 下的代码块 。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/105502
推荐阅读
相关标签
  

闽ICP备14008679号