闭包、装饰器

闭包

  • 闭包其实就是在一个函数中嵌套另一个函数的定义。
  • 闭包的作用:包括了外部函数的局部变量,这些局部变量在外部函数返回后也继续存在,并能被内部函数引用。
======================程序====================
def test(number):
    def test_in(number_in):
        print("in test_in 函数, number_in is %d" % number_in)
        return number+number_in
    # 其实这里返回的就是闭包的结果
    return test_in
  
# 给test函数赋值,这个20就是给参数number
ret = test(20)
# 注意这里的100其实给参数number_in
print(ret(100))
#注 意这里的200其实给参数number_in
print(ret(200))
  
====================运行结果===================
in test_in 函数, number_in is 100
120
in test_in 函数, number_in is 200
220

关于闭包的实际例子
====================程序===============
def line_conf(a, b):
    def line(x):
        return a*x + b
    return line
  
line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))
  
 ====================结果===============
6
25

这个例子中,函数line与变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。


如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。


注意点:
由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存


闭包内修改外部函数的变量

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

c1 = counter(5)
print(c1())
print(c1())

c2 = counter(50)
print(c2())
print(c2())

print(c1())
print(c1())

print(c2())
print(c2())
  • 思考:函数、匿名函数、闭包、对象 当做实参时 有什么区别?
    1. 匿名函数能够完成基本的简单功能,传递是这个函数的引用 只有功能
    2. 普通函数能够完成较为复杂的功能,传递是这个函数的引用 只有功能
    3. 闭包能够将较为复杂的功能,传递是这个闭包中的函数以及数据,因此传递是功能+数据
    4. 对象能够完成最为复杂的功能,传递是很多数据+很多功能,因此传递是功能+数据

装饰器

在Python中函数也是一个对象,所以可以

  • 将函数复制给变量
  • 将函数当做参数
  • 返回一个函数

它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能 装饰器的返回值也是一个函数/类对象

  • 闭包主要的应用就是充当装饰器
  • 形式为@<函数名>(实际上==》<函数名> = set_fun(<函数名>))
装饰器在调用函数之前,已经被python解释器执行了,所以要牢记 当调用函数之前 其实已经装饰好了,尽管调用就可以了
装饰器(decorator)功能
  1. 引入日志
  2. 函数执行时间统计
  3. 执行函数前预备处理
  4. 执行函数后清理功能
  5. 权限校验等场景
  6. 缓存
def f1():
    print('---这是第一个语句验证----')
    print('-----test1----')
    print('---这是第二个语句验证----') 

def f2():
    print('---这是第一个语句验证----')
    print('-----test2----')
    print('---这是第二个语句验证----') 
    
def f3():
    print('---这是第一个语句验证----')
    print('-----test3----')
    print('---这是第二个语句验证----') 

f1()
f2()
f3()
***************执行结果***************

再看另一份代码:
def set_func(func):
	def call_func():
		print("---这是第一个语句----")
		func()
		print("---这是第二个语句----")
	return call_func

@set_func  # 等价于test1 = set_func(test1) 
def test1():
	print("-----test1----")

# test1 = set_func(test1) 
test1()

***************执行结果***************
---这是第一个语句----
-----test1----
---这是第二个语句----

两段代码的执行结果都是相同的,但是用了装饰器的代码 相对于比较方便.

  • 代码中@set_func 等价于test1 = set_func(test1)
  • 执行过程:当执行 @set_func 时,相当于把 test1 当作实参传给了 set_func()
  • test1先作为参数赋值给func后, test1接收指向set_fun返回的call_func
    test1()

而此时 func形参 指向了函数 test1
然后到执行 return call_func时
就是返回call_func这个引用给 test1(因为是test1调用的set_func)
也就是说这时test1 指向的就是 call_func() 函数
然后调用 test1() 时,就相当于调用 call_func()
执行到func() 时,因为它指向的是 test1 里面的语句
所以执行的是 print("-----test1----")

装饰有参数无返回值的程序
def set_func(func):
	def call_func(a):
		print("---这是权限验证1----")
		print("---这是权限验证2----")
		func(a)
	return call_func

@set_func  # 相当于 test1 = set_func(test1)
def test1(num):
	print("-----test1----%d" % num)

test1(100)

# xx = set_func(test1)

***************执行结果***************
---这是权限验证1----
---这是权限验证2----
-----test1----100
同一个装饰器对多个函数进行装饰
def set_func(func):
	print("---开始进行装饰")
	def call_func(a):
		print("---这是测试1----")
		print("---这是测试2----")
		func(a)
	return call_func


@set_func  # 相当于 test1 = set_func(test1)
def test1(num):
	print("-----第%d条测试----" % num)


@set_func  # 相当于 test2 = set_func(test2)
def test2(num):
	print("-----第%d条测试----" % num)

test1(100)
test2(200)

***************执行结果***************

---开始进行装饰
---开始进行装饰

---这是测试1----
---这是测试2----
-----100条测试----

---这是测试1----
---这是测试2----
-----200条测试----
装饰器在没有调用函数之前已经装饰了
装饰器在调用函数之前,已经被python解释器执行了,所以要牢记 当调用函数之前 其实已经装饰好了,尽管调用就可以了
对不定长参数的函数进行装饰
def set_func(func):
	print("---开始进行装饰")
	def call_func(*args, **kwargs):
		print("---这是另一组测试---")
		# func(args, kwargs)  # 不行,相当于传递了2个参数 :1个元组,1个字典
		func(*args, **kwargs)  # 拆包
	return call_func


@set_func  # 相当于 test1 = set_func(test1)
def test1(num, *args, **kwargs):
	print("-----test1----%d" % num)
	print("-----test1----" , args)
	print("-----test1----" , kwargs)

test1(100)
test1(100, 200)
test1(100, 200, 300, mm=100)

***************执行结果***************

---开始进行装饰
---这是另一组测试---
-----test1----100
-----test1---- ()
-----test1---- {}

---这是另一组测试---
-----test1----100
-----test1---- (200,)
-----test1---- {}

---这是另一组测试---
-----test1----100
-----test1---- (200, 300)
-----test1---- {'mm': 100}
对带有返回值的函数进行装饰
def set_func(func):
	def call_func(*args, **kwargs):
		print("---这是另一组测试---")
		# func(args, kwargs)  # 不行,相当于传递了2个参数 :1个元组,1个字典
		return func(*args, **kwargs)  # 拆包
	return call_func


@set_func  # 相当于 test1 = set_func(test1)
def test1(num, *args, **kwargs):
	print("-----test1----%d" % num)
	print("-----test1----" , args)
	print("-----test1----" , kwargs)
	return "好的,我是返回值"


@set_func
def test2():
	pass

ret = test1(100)
print(ret)

ret = test2()
print(ret)

***************执行结果***************
---这是另一组测试---
-----test1----100
-----test1---- ()
-----test1---- {}
好的,我是返回值

---这是另一组测试---
None
多个装饰器对同一函数进行装饰
def add_qx(func):
	print("---开始进行第一111个装饰器---")
	def call_func(*args, **kwargs):
		print("---这是第一111个的功能----")
		return func(*args, **kwargs)
	return call_func


def add_xx(func):
	print("---开始进行第二222个装饰器---")
	def call_func(*args, **kwargs):
		print("---这是第二222个的功能----")
		return func(*args, **kwargs)
	return call_func


@add_qx
@add_xx
def test1():
	print("------test1------")


test1()


***************执行结果***************
---开始进行第二222个装饰器---
---开始进行第一111个装饰器---
---这是第一111个的功能----
---这是第二222个的功能----
------test1------

装饰时,@add_qx 的底下不是一个函数,然后就开始执行@add_xx ,等 @add_xx 装饰好时,相当于一个函数,这时@add_qx底下是一个函数,所以就可以进行装饰了。

  • 多个装饰器装饰函数时 从最下面的函数开始往上调用
  • 多个装饰器对同一函数进行装饰-----再举例子
def set_func_1(func):
	def call_func():
		# "<h1>haha</h1>"
		return "<h1>" + func() + "</h1>"
	return call_func

def set_func_2(func):
	def call_func():
		return "<td>" + func() + "</td>"
	return call_func


@set_func_1
@set_func_2
def get_str():
	return "haha"

print(get_str())

***************执行结果***************
<h1><td>haha</td></h1>
使用类当做装饰器
# def set_func_1(func):
# 	def call_func():
# 		# "<h1>haha</h1>"
# 		return "<h1>" + func() + "</h1>"
# 	return call_func


class Test(object):
	def __init__(self, func):
		self.func = func

	def __call__(self):
		print("这里是装饰器添加的功能.....")
		return self.func()


@Test  # 相当于get_str = Test(get_str)
def get_str():
	return "haha"

print(get_str())

***************执行结果***************
这里是装饰器添加的功能.....
haha
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GeoPandas是一个开源的Python库,旨在简化地理空间数据的处理和分析。它结合了Pandas和Shapely的能力,为Python用户提供了一个强大而灵活的工具来处理地理空间数据。以下是关于GeoPandas的详细介绍: 一、GeoPandas的基本概念 1. 定义 GeoPandas是建立在Pandas和Shapely之上的一个Python库,用于处理和分析地理空间数据。 它扩展了Pandas的DataFrame和Series数据结构,允许在其中存储和操地理空间几何图形。 2. 核心数据结构 GeoDataFrame:GeoPandas的核心数据结构,是Pandas DataFrame的扩展。它包含一个或多个列,其中至少一列是几何列(geometry column),用于存储地理空间几何图形(如点、线、多边形等)。 GeoSeries:GeoPandas中的另一个重要数据结构,类似于Pandas的Series,但用于存储几何图形序列。 二、GeoPandas的功能特性 1. 读取和写入多种地理空间数据格式 GeoPandas支持读取和写入多种常见的地理空间数据格式,包括Shapefile、GeoJSON、PostGIS、KML等。这使得用户可以轻松地从各种数据源中加载地理空间数据,并将处理后的数据保存为所需的格式。 2. 地理空间几何图形的创建、编辑和分析 GeoPandas允许用户创建、编辑和分析地理空间几何图形,包括点、线、多边形等。它提供了丰富的空间操函数,如缓冲区分析、交集、并集、差集等,使得用户可以方便地进行地理空间数据分析。 3. 数据可视化 GeoPandas内置了数据可视化功能,可以绘制地理空间数据的地图。用户可以使用matplotlib等库来进一步定制地图的样式和布局。 4. 空间连接和空间索引 GeoPandas支持空间连接操,可以将两个GeoDataFrame按照空间关系(如相交、包含等)进行连接。此外,它还支持空间索引,可以提高地理空间数据查询的效率。
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操 Python 对象一样操数据库,这大大简化了数据库操的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值