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

很多人学习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)
  4. ?

跳到解决方案

问题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. DVWA学习记录 PartⅠ

    DVWA介绍 DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供合法 ...

  2. node+express+static完成简单的文件下载

    不多说什么,直接上代码 var express = require('express'); var fs = require('fs') var path= require('path'); var ...

  3. Mysql and ORM

    本节内容 数据库介绍 mysql 数据库安装使用 mysql管理 mysql 数据类型 常用mysql命令 创建数据库 外键 增删改查表 权限 事务 索引 python 操作mysql ORM sql ...

  4. MySQL事物原理及事务隔离级别

    mysql事物 事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取.事务的正确执行使得数据库从一种状态转换为另一种状态. 事务必须服从ISO/IEC所制定的ACID原则.AC ...

  5. Spring常见问题大全

    Spring 概述 1. 什么是spring? Spring 是个java企业级应用的开源开发框架.Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用.Spring ...

  6. 【软件安装】CentOS7安装Tengine_2_3_2(Nginx 1_17_0)

    简单比较一下Tengine 和Nginx 背景 使用最新的软件,可以处理一些bug,文章对CentOS6不做介绍(不会用) 推荐使用Tengine,理由是淘宝再用,兼容 Nginx 可以随时切换 Te ...

  7. JavaScript经典实例(浏览器事件)

    跨浏览器事件 1.跨浏览器添加事件 function addEvent(obj,type,fn){ if(obj.addEventListener){ obj.addEventListener(typ ...

  8. PyQt5模型视图委托

    Model-View-Delegate 模型视图委托(MVD)是PyQt中特有的设计模式,类似MVC设计模式,将MVC设计模式中的Controller当做MVD中的Delegate,两者的概念基本相同 ...

  9. Makefile中的目标

    Makefile中的目标 一般目标 目标就是我们需要的最终文件,也是make的最终输出 Makefile的运行机制是:先将目标当成文件,查看文件是否存在,如果存在且是最新,那么直接结束,如果文件不存在 ...

  10. [jvm] -- 监控和调优常用命令工具篇

    jps:java版本的ps,查看进程的信息 jps -l 输出jar包路径,类全名 jps -m 输出main参数 jps -v 输出JVM参数 jinfo:是用来查看JVM参数和动态修改部分JVM参 ...