当前位置: 首页 > 编程笔记 >

Python延迟绑定问题原理及解决方案

邓俊材
2023-03-14
本文向大家介绍Python延迟绑定问题原理及解决方案,包括了Python延迟绑定问题原理及解决方案的使用技巧和注意事项,需要的朋友参考一下

延迟绑定出现在闭包问题中。下面我们看一个闭包的例子:

def (n):
  def mul(x):
    return n*x
  return mul
double = gen_mul(2)
doubled_value = double(6) 

可以看出满足闭包的几点:

  • 有内部函数
  • 内部函数引用了外部函数中的自由变量
  • 内部函数被返回

闭包的优点:

  • 可以避免使用全局变量
  • 可以持久化变量,达到静态变量的作用

闭包的缺点:

  • 可能会消耗大量的内存
  • 可能会导致内存泄漏

当然缺点可以通过人为避免。

现在我们来看看另一个会引出延迟绑定的例子:

def multipliers():
  return [lambda x : i * x for i in range(4)]
print([m(2) for m in multipliers()]) # [6,6,6,6]

上边的例子会输出[6,6,6,6],而不是我们预期的[0,2,4,6]。

这就是延迟绑定导致的结果。具体过程我们可以来分析下:
执行第三行时,会先执行multipliers函数,然后执行函数中的列表解析式。在每一次迭代的时候都会生成一个匿名函数(这里只是定义)作为元素。然后回到第三行,遍历返回的列表中的匿名函数,传入参数2并执行。此时函数类似于这样:

def noname(x):
return i * x

我们知道Python查找变量的作用域链的顺序依次为LEGB:

局部变量(L)->外部函数中的局部变量(E)->全局变量(G)->内置变量(B)

非常重要的一点我们需要知道:Python的作用域在编译时就已经形成了,而不是在运行时,函数的作用域与其被调用的位置无关。

那么在本例中,上面的noname函数体中的i从何而来呢?当然首先会到multipliers函数的局部变量中去寻找。此时i的值已经为3,所以出现这种让人”费解”的现象。

那么现在我们既然已经知道了原因,那么要怎样解决呢?

我们可以将迭代的i值直接注入到匿名函数的函数体中,这里给出两种方法

通过为参数设置默认值,这是因为在编译时就会计算确定默认值:

def multipliers_ch1():
return [lambda m,x=i : m * x for i in range(4)]

通过内置函数partial:

from functools import partial
def multipliers_ch2():
  return [partial(lambda m,x : m * x,i) for i in range(4)]

利用生成器的延迟计算:

def multipliers_ch3():
  for m in range(4):
    yield lambda x: m * x

partial及生成器的内容会在以后分享。

运行结果

print([m(2) for m in multipliers_ch1()]) # [0,2,4,6]
print([m(2) for m in multipliers_ch2()]) # [0,2,4,6]
print([m(2) for m in multipliers_ch3()]) # [0,2,4,6]

注:

自由变量:指未在本地作用域中绑定的变量,我们可通过访问函数的code属性进行查看:

fun.code.co_freevars

LEGB: 可看该部分解释

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍MySQL主从复制延迟原因以及解决方案,包括了MySQL主从复制延迟原因以及解决方案的使用技巧和注意事项,需要的朋友参考一下 来源:公众号「神谕的暗影长廊」 在异步或半同步的复制结构中,从库出现延迟是一件十分正常的事。 虽出现延迟正常,但是否需要关注,则一般是由业务来评估。 如:从库上有需要较高一致性的读业务,并且要求延迟小于某个值,那么则需要关注。 简单概述一下复制逻辑: 1、主库

  • 本文向大家介绍Android延迟实现的几种解决方法及原理分析,包括了Android延迟实现的几种解决方法及原理分析的使用技巧和注意事项,需要的朋友参考一下 前言 在Android开发中我们可能会有延时执行某个操作的需求,例如我们启动应用的时候,一开始呈现的是一个引导页面,过了两三秒后,会自动跳转到主界面。这就是一个延时操作。 而写这篇文章的目的,是看到群里有人在实现延迟的时候,用如下的第四种方法,

  • 我们正在尝试为Cassandra Datastax社区版和java驱动程序创建一个原型。我试图使用CassandraJava驱动程序(简单键空间)的示例来测量简单检索和更新的延迟。 我有两个数据中心,每个数据中心有一个机架。每个机架包含3个节点。我总共有6个节点(虚拟机)。 为了优化检索/更新操作,我将key_cache_size_in_mb配置为10。 总之,我们尝试调整示例操作,以获得读取/更

  • 我正面临着G1GC算法中GC停顿的持续增加。服务延迟随着时间的推移继续增长。一旦发生这种情况,我将重新启动服务,延迟时间将恢复正常。启动后,等待时间再次随着时间的推移而增加。

  • top看到单个CPU 100%时,就是垂直扩展的时候了。如果需要让CPU使用率最大化,可以配置Redis实例数对应CPU数, Redis实例数对应端口数(8核Cpu, 8个实例, 8个端口), 以提高并发。单机测试时, 单条数据在200字节, 测试的结果为8~9万tps。(未实测)。 另外,对于命令的复杂度一定要关注。

  • 本文向大家介绍javascript跨域方法、原理以及出现问题解决方法(详解),包括了javascript跨域方法、原理以及出现问题解决方法(详解)的使用技巧和注意事项,需要的朋友参考一下 javascript跨域访问是web开发者经常遇到的问题,什么是跨域,一个域上加载的脚本获取或操作另一个域上的文档属性,下面将列出三种实现javascript跨域方法: 1.基于iframe实现跨域      基

  • 本文向大家介绍IOS 解决UIButton 点击卡顿/延迟的问题,包括了IOS 解决UIButton 点击卡顿/延迟的问题的使用技巧和注意事项,需要的朋友参考一下 前言   一开始还以为代码写的有问题,点击事件里面有比较耗时卡主线程的代码,逐一删减代码发现并不是这么回事。 正文   和参考文章里说的情况不完全相同,UIButton 并没有放在 UIScrollView 或 UITableView

  • 不太会使用 Env 工具的请先看一遍 《Env 用户手册》(不长的,看完费不了几分钟) 提示 Env 工具和 源码 所处的目录都不能有中文或空格请先检查!! code 是一个命令 点 ‘.’ 是一个参数表示当前目录,中间有一个空格。 romfs ramfs 文件系统中的文件名和c的变量的命名一样,只能由英文字母开头且仅包含数字和下划线。 修改 qemu.bat 里面的参数时,要注意那是一行参数中间