Python函数

在这里插入图片描述
以下内容是整理极客时间Python核心技术与实战课程的笔记。

Python 函数嵌套

函数嵌套,也就是指函数里面又有函数。

def f1():
    print('hello')
    def f2():
        print('world')
    f2()
f1()
 
# 输出
hello
world

函数嵌套的优势?
第一点:函数的嵌套能够保证内部函数的隐私。内部函数只能被外部函数所调用和访问,不会暴露在全局作用域,因此,如果你的函数内部有一些隐私数据(比如数据库的用户、密码等),不想暴露在外,那你就可以使用函数的的嵌套,将其封装在内部函数中,只通过外部函数来访问。我们只能通过调用外部函数来访问它,这样一来,程序的安全性便有了很大的提高。

def connect_DB():
    def get_DB_configuration():
        ...
        return host, username, password
    conn = connector.connect(get_DB_configuration())
    return conn

第二点:合理的使用函数嵌套,能够提高程序的运行效率。如果不使用函数嵌套,那么每调用一次递归便会检查一次,这是没有必要的,也会降低程序的运行效率。

def factorial(input):
    # validation check
    if not isinstance(input, int):
        raise Exception('input must be an integer.')
    if input < 0:
        raise Exception('input must be greater or equal to 0' )
    ...
 
    def inner_factorial(input):
        if input <= 1:
            return 1
        return input * inner_factorial(input-1)
    return inner_factorial(input)
 
 
print(factorial(5))

所以合理的使用嵌套函数,能保证数据的隐私性,提高程序运行效率

闭包

闭包和嵌套函数类似,不同的是,这里外部函数返回的是一个函数,而不是一个具体的值。返回的函数通常赋于一个变量,这个变量可以在后面被继续执行调用。
外部函数 nth_power() 返回值,是函数 exponent_of()。

def nth_power(exponent):
	"""返回值是 exponent_of 函数"""
    def exponent_of(base):
        return base ** exponent
    return exponent_of # 返回值是 exponent_of 函数

 # 计算一个数的平方
square = nth_power(2)
 # 计算一个数的立方
cube = nth_power(3) 
print(square(2))  # 计算 2 的平方
# 4 # 2^2
print(cube(2)) # 计算 2 的立方
# 8 # 2^3

为什么要闭包呢?
上面的程序,也可以写成下面的形式。

def nth_power_rewrite(base, exponent):
    return base ** exponent

闭包是让程序变得更简洁易读。比如你需要计算很多个数的平方,闭包现在就很简洁易懂了。

# 不适用闭包
res1 = nth_power_rewrite(base1, 2)
res2 = nth_power_rewrite(base2, 2)
res3 = nth_power_rewrite(base3, 2)
...
 
# 使用闭包
square = nth_power(2)
res1 = square(base1)
res2 = square(base2)
res3 = square(base3)

所以合理地使用闭包,则可以简化程序的复杂度,提高可读性

匿名函数

匿名函数搭配map()、filter() 和 reduce()使用。

map

map(function, iterable) 函数,对 iterable 中的每个元素,都运用 function 这个函数,最后返回一个新的可遍历的集合。

对于下面这个例子,要对列表中的每个元素乘以 2,返回一个集合。

l = [1, 2, 3, 4, 5]
new_list = map(lambda x: x * 2, l) # [2, 4, 6, 8, 10]

map() 函数直接由 C 语言写的,运行时不需要通过 Python 解释器间接调用,并且内部做了诸多优化,相比于for 循环和 list,运行速度更快。

filter

filter(function, iterable) 函数,它和 map 函数类似,function 同样表示一个函数对象。filter() 函数表示对 iterable 中的每个元素,都使用 function 判断,并返回 True 或者 False,最后将返回 True 的元素组成一个新的可遍历的集合。

返回一个列表中的偶数。

l = [1, 2, 3, 4, 5]
# [2, 4]
new_list = filter(lambda x: x % 2 == 0, l) 

reduce

reduce(function, iterable) 函数,它通常用来对一个集合做一些累积操作。它有两个参数,表示对 iterable 中的每个元素以及上一次调用后的结果,运用 function 进行计算,所以最后返回的是一个单独的数值。

计算某个列表元素的乘积,就可以用 reduce() 函数来表示。

l = [1, 2, 3, 4, 5]
# 1*2*3*4*5 = 120
product = reduce(lambda x, y: x * y, l) 

对于相加、累积这种简单操作,优先考虑 map、filter、reduce

装饰器

所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改
在 Python 中,函数是一等公民,同时函数也是对象。
###一个例子

# -*- coding: utf-8 -*-

def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()

    return wrapper


@my_decorator
def greet():
    print('hello world')


greet()
# 输出
#wrapper of decorator
#hello world

@my_decorator就相当于把函数greet作为参数和传给my_decorator函数,也就是greet=my_decorator(greet),它把真正需要执行的函数== greet==() 包裹在自己内部,并且改变了它的行为,但是原函数 greet() 不变。

若greet函数有参数,通常情况下,我们会把*args和**kwargs,作为装饰器内部函数 wrapper() 的参数。*args和**kwargs,表示接受任意数量和类型的参数,因此装饰器就可以写成下面的形式:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
    return wrapper

用法如下:

# -*- coding: utf-8 -*-

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
    return wrapper


@my_decorator
def greet(str1,str2):
    print('hello world')
    print(str1)
    print(str2)


greet("python","function")
#wrapper of decorator
#hello world
#python
#function

装饰器的用处
身份认证、日志记录、输入合理性检查、缓存等。
身份认证,比如用户对某篇文章的评论。都会先检查用户是否处于登录状态,如果是登录状态,则允许这项操作;如果没有登录,则不允许。
例子

import functools
 
def authenticate(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        request = args[0]
        if check_user_logged_in(request): # 如果用户处于登录状态
            return func(*args, **kwargs) # 执行函数 post_comment() 
        else:
            raise Exception('Authentication failed')
    return wrapper
    
@authenticate
def post_comment(request, ...)
    ...

日志记录:统计函数的耗时,装饰器 log_execution_time 记录某个函数的运行时间,并返回其执行结果。如果你想计算任何函数的执行时间,在这个函数上方加上@log_execution_time即可。

import time
import functools
 
def log_execution_time(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        res = func(*args, **kwargs)
        end = time.perf_counter()
        print('{} took {} ms'.format(func.__name__, (end - start) * 1000))
        return res
    return wrapper
    
@log_execution_time
def calculate_similarity(items):
    ...

输入合理性检查:比如用装饰器对其输入(往往是很长的 json 文件)进行合理性检查。从而避免输入不正确对机器造成的巨大开销。

import functools
 
def validation_check(input):
    @functools.wraps(func)
    def wrapper(*args, **kwargs): 
        ... # 检查输入是否合法
    
@validation_check
def neural_network_training(param1, param2, ...):
    ...

做机器学习的知道,在模型训练的时候,数据量大,若处理半天,读取数据不对是一个很耗时的过程,所以这一步在这点上非常有必要。
缓存:python内部的lru算法就是使用装饰器@lru_cache。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值