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

很多人学习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. STM32H743 | FDCAN 波特率问题

    直奔主题,最近项目上接触了FDCAN,主控为STM32H743.在开发过程中存在了几点疑惑,特此记录. 波特率设置问题 CAN通讯的波特率计算方式为: BaudRate = Tq *(SYNC_SEG ...

  2. 【笔记】Java语法

    Java语法 兜兜转转,又绕回到Java了. 最近在学习Java,其实以前也学过,但是技术发展太快了,Java都出到14了..是时候该更新一下知识体系了. 然后看的是网上好评如潮的<Java核心 ...

  3. java 面向对象(三十四):泛型三 自定义泛型类、泛型接口、泛型方法

    1.举例: [Order.java] public class Order<T> { String orderName; int orderId; //类的内部结构就可以使用类的泛型 T ...

  4. python生成器原理剖析

    python生成器原理剖析 函数的调用满足"后进先出"的原则,也就是说,最后被调用的函数应该第一个返回,函数的递归调用就是一个经典的例子.显然,内存中以"后进先出&quo ...

  5. vue 集成html5 plus

    首先要安装一个包 vue-html5plus npm i vue-html5plus -S 然后配置这个文件 在main.js添加一串代码 var onPlusReady = function (ca ...

  6. [Qt2D绘图]-04绘制文字&&绘制路径

    注:学习自<Qt Creator 快速入门>第三版.   文档中的示例参考 Qt Example推荐:Painter Paths Example和Vector Deformation   ...

  7. CocosCreator之分层管理的ListView

    前言 进入公众号回复listview即可获得demo的git地址. 之前写的一篇文章<Creator之ScrollView那些事>中提到了官方Demo中提供的ListViewCtl,只是实 ...

  8. 《python编程从入门到实践》2.3字符串

    书籍<python编程从入门到实践> 2.3字符串 知识模块 print()函数,函数名称突出为蓝色,输出括号内的变量或者字符创. 变量名的命名:尽量小写字母加下划线并且具有良好的描述性, ...

  9. Ubuntu Server 19.04配置静态IP

    这个/etc/netplan下默认有个文件50-cloud-init.yaml,直接修改它就行了 sudo vim /etc/netplan/50-cloud-init.yaml 网口名字enp0s3 ...

  10. 【Unity3D】简单常用的功能实现2——视角的跟随、旋转、缩放

    [视角的跟随.旋转.缩放实现] 首先,在实现这些功能之前,我们给Hierarchy面板中的主摄像机额外包装几层Empty Object,形成一个新的摄像机结构,如下图(当然这些空物体的命名大家按自己方 ...