尝试解决以下问题,然后检查以下答案。

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:1097524789

提示:所有问题都有共同点,因此在解决其余问题之前检查第一个问题的解决方案可以减轻挑战。

问题1

假设我们有几个变量:

  1. x = 1
  2. y = 2
  3. l = [x, y]
  4. x += 5
  5. a = [1]
  6. b = [2]
  7. s = [a, b]
  8. a.append(5)

l和s的打印结果是什么?

跳到解决方案

问题2

让我们定义一个简单的函数:

  1. def f(x, s=set()):
  2. s.add(x) print(s)

如果您决定,将会发生什么:

  1. >>f(7)
  2. >>f(6, {4, 5})
  3. >>f(2)

跳到解决方案

问题3

让我们定义两个简单的函数:

  1. def f():
  2. l = [1]
  3. def inner(x):
  4. l.append(x)
  5. return l
  6. return inner
  7. def g():
  8. y = 1
  9. def inner(x):
  10. y += x
  11. return y
  12. return inner

以下命令将产生什么结果?

  1. >>ff_inner = f()
  2. >>print(f_inner(2))
  3. >>gg_inner = g()
  4. >>print(g_inner(2))

跳到解决方案

您对自己的回答有多自信? 让我们看看您是否正确。

解决问题1

  1. >>print(l)
  2. [1, 2]
  3. >>print(s)
  4. [[1, 5], [2]]

为什么第二个列表对第一个元素a.append(5)的更改有反应,但是第一个列表完全忽略x + = 5的类似变化?

解决问题2

让我们看看发生了什么:

  1. >>f(7){7}
  2. >>f(6, {4, 5}){4, 5, 6}
  3. >>f(2){2, 7}

等待,最后输出不是{2}吗?

解决问题3

输出将是以下内容:

  1. >>ff_inner = f()
  2. >>print(f_inner(2))[1, 2]
  3. >>gg_inner = g()
  4. >>print(g_inner(2))
  5. UnboundLocalError: local variable 'y' referenced before assignment

为什么g_inner(2)不输出3? f()的内部函数如何记住其外部范围,而g()的内部函数却不记得呢? 它们实际上是相同的!

说明

如果我告诉您这些怪异的行为与Python中可变对象和不可变对象之间的区别有关怎么办?

诸如列表,集合或字典之类的可变对象可以在适当位置进行更改(变异)。 不变的对象(如整数,字符串和元组)不能—此类对象的"更改"会导致创建新对象。

问题1的说明

  1. x = 1
  2. y = 2
  3. l = [x, y]
  4. x += 5
  5. a = [1]
  6. b = [2]
  7. s = [a, b]
  8. a.append(5)
  9. >>print(l)
  10. [1, 2]
  11. >>print(s)
  12. [[1, 5], [2]]

由于x是不可变的,因此操作x + = 5不会更改原始对象,而是创建一个新对象。 列表的第一个元素仍指向原始对象,因此其值保持不变。

对于可变对象a,a.append(5)更改原始对象,因此list s"看到"更改。

问题2的解释

  1. def f(x, s=set()):
  2. s.add(x)
  3. print(s)
  4. >>f(7)
  5. {7}
  6. >>f(6, {4, 5})
  7. {4, 5, 6}
  8. >>f(2)
  9. {2, 7}

前两个输出完全有意义:首先将值7添加到默认空集中,得到{7},然后将值6添加到一组{4,5}中,得到{4,5,6 }。

但是随后发生了一件奇怪的事情:将值2添加到默认的空集而不是添加到{7}的集。 为什么? 可选参数s的默认值仅被评估一次-仅在第一次调用s期间将被初始化为空集。 由于s在调用f(7)之后是可变的,因此就地进行了修改。 第二个调用f(6,{4,5})不会影响默认参数-提供的集合{4,5}将其遮蔽,换句话说,{4,5}是一个不同的变量。 第三次调用f(2)使用的是与第一次调用相同的s变量,但是s未作为空集重新初始化-使用了其先前的值{7}。

这就是为什么您不应该使用可变的默认参数的原因。 在这种情况下,应按以下方式修改功能:

  1. def f(x, s=None):
  2. if s is None:
  3. s = set()
  4. s.add(x)
  5. print(s)

问题3的解释

  1. def f():
  2. l = [1]
  3. def inner(x):
  4. l.append(x)
  5. return l
  6. return inner
  7. def g():
  8. y = 1
  9. def inner(x):
  10. y += x
  11. return y
  12. return inner
  13. >>ff_inner = f()
  14. >>print(f_inner(2))
  15. [1, 2]
  16. >>gg_inner = g()
  17. >>print(g_inner(2))
  18. UnboundLocalError: local variable ‘y’ referenced before assignment

在这个问题中,我们处理闭包-内部函数记住定义时它们的封闭名称空间的外观。 或至少应该如此-第二个功能保持扑克面孔,就像从未听说过其外部作用域一样。

这是为什么? 当我们执行l.append(x)时,在定义时创建的可变对象被修改,但是变量l仍然指向内存中的相同地址。 但是,尝试更改第二个函数y + = x中的不可变变量会导致y指向内存中与以前不同的地址-原始y将不再被记住,因此导致UnboundLocalError。

结论

Python中可变对象与不可变对象之间的区别非常重要。 请注意这一点,以避免出现本文所述的奇怪行为。 特别是:

  • 不要使用可变的默认参数。
  • 不要尝试在内部函数中更改不可变的闭包变量。
  • 请随意分享其他示例,这些示例可能是由于您在响应中误用了可变的和不变的对象而导致的潜在问题。

您能解决这3个(看似)简单的Python问题吗?的更多相关文章

  1. 解决:layUI数据表格+简单查询

    解决:layUI数据表格+简单查询 最近在用layui写项目,在做到用户查询时,发现在layui框架里只有数据表格,不能增加查询.于是自己摸索了一下,写个笔记记录一下. 我想要的效果: 1.定义查询栏 ...

  2. 带你简单了解python协程和异步

    带你简单了解python的协程和异步 前言 对于学习异步的出发点,是写爬虫.从简单爬虫到学会了使用多线程爬虫之后,在翻看别人的博客文章时偶尔会看到异步这一说法.而对于异步的了解实在困扰了我好久好久,看 ...

  3. 【转】简单谈谈python的反射机制

    [转]简单谈谈python的反射机制 对编程语言比较熟悉的朋友,应该知道“反射”这个机制.Python作为一门动态语言,当然不会缺少这一重要功能.然而,在网络上却很少见到有详细或者深刻的剖析论文.下面 ...

  4. Tkinter制作简单的python编辑器

    想要制作简单的python脚本编辑器,其中文字输入代码部分使用Tkinter中的Text控件即可实现. 但是问题是,如何实现高亮呢?参考python自带的编辑器:python27/vidle文件夹中的 ...

  5. 简单的Python GUI界面框架

    Python开发GUI界面, 可以使用pyQT或者wxpython. 不过不论pyQT还是wxpython都需要比较多的学习成本.Python工程往往是用于快速开发的,有些时候引入pyQT,wxpyt ...

  6. 完成一段简单的Python程序,使用函数实现用来判断输入数是偶数还是奇数

    #!/bin/usr/env python#coding=utf-8'''完成一段简单的Python程序,使用函数实现用来判断偶数和奇数'''def number_deal(a): if a%2==0 ...

  7. 完成一段简单的Python程序,用于实现一个简单的加减乘除计算器功能

    #!/bin/usr/env python#coding=utf-8'''完成一段简单的Python程序,用于实现一个简单的加减乘除计算器功能'''try: a=int(raw_input(" ...

  8. 简单的python http接口自动化脚本

    今天给大家分享一个简单的Python脚本,使用python进行http的接口测试,脚本很简单,逻辑是:读取excel写好的测试用例,然后根据excel中的用例内容进行调用,判断预期结果中的返回值是否和 ...

  9. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...

  10. 简单的python购物车

                 这几天,一直在学python,跟着视频老师做了一个比较简单的python购物车,感觉不错,分享一下 products = [['Iphone8',6888],['MacPro ...

随机推荐

  1. 机器学习实战基础(十六):sklearn中的数据预处理和特征工程(九)特征选择 之 Filter过滤法(三) 总结

    过滤法总结 到这里我们学习了常用的基于过滤法的特征选择,包括方差过滤,基于卡方,F检验和互信息的相关性过滤,讲解了各个过滤的原理和面临的问题,以及怎样调这些过滤类的超参数.通常来说,我会建议,先使用方 ...

  2. maven自动创建项目目录骨架

    方法一: 1:打开命令窗口 在要创建项目的路径下按住H2SIT ,然后点击右键  ,在弹出菜单中选择 在此处打开命令窗口(W) 2:目录创建 方法二:

  3. Go Pentester - HTTP Servers(1)

    HTTP Server Basics Use net/http package and useful third-party packages by building simple servers. ...

  4. UVA 10653.Prince and Princess

    题目 In an n * n chessboard, Prince and Princess plays a game. The squares in the chessboard are numbe ...

  5. Fastjson到了说再见的时候了

    生命太短暂,不要去做一些根本没有人想要的东西.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习 ...

  6. 有关 Session 的那些事儿

    原文链接: https://blog.by24.cn/archives/about-session.html Web 开发中,Session 是经常用到的概念,但是在日常交流中,似乎又经常引起误解. ...

  7. 题解 洛谷 P6640 【[BJOI2020] 封印】

    设\(lenth_i\)为\(s\)在\(i\)位置的前缀的后缀为\(t\)的一个子串的最长长度,即为从\(i\)位置开始往前和\(t\)的最长公共子串长度.其可以通过对\(t\)建后缀自动机,然后让 ...

  8. 题解 洛谷 P3726 【[AH2017/HNOI2017]抛硬币】

    可以分别枚举两人正面朝上的次数来统计答案,所求即为 \[\sum_{i=0}^{a}\sum_{j=0}^{b} \binom{a}{i} \binom{b}{j} [i>j] \] 将\(i\ ...

  9. 解决android studio Gradle无法同步问题

    打开根目录build.gradle buildscript { repositories { // 添加阿里云 maven 地址 maven { url 'http://maven.aliyun.co ...

  10. chrome浏览器hover时文字抖动bug

    今天发现一个奇怪的bug,chrome浏览器里面  当父标签定位为fixed时,hover里面子标签时,文本会发生抖动,百思不得其解,经过多方查证,发现解决办法 -webkit-transform:  ...