Django开发从入门到实践(txt+pdf+epub+mobi电子书下载)


发布时间:2020-05-18 09:06:03

点击下载

作者:段艺,涂伟忠

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Django开发从入门到实践

Django开发从入门到实践试读:

前言

Python简单易学、上手快速,成为很多程序员喜爱的编程语言。使用Python进行Web应用开发,无疑能够加快需求实现的速度,快速迭代和验证产品的原型。有些人可能会有疑问:Python性能不够好,用来开发Web是不是不太合适?Python在性能上确实无法和C、Java等语言相比,但在大部分情况下使用Python开发是可以满足性能需求的,并且很多时候程序性能不够好,这不是语言本身的问题,而是架构设计、缓存设计、数据结构算法的选用以及开发人员编程水平等引起的问题。总之,使用Python语言进行Web开发有独特的优势,通常能满足大部分应用场景的需求。

本书面向想学习Python Web开发的读者,分5篇讲解基础知识和实战。

第1篇是基础知识,让读者对Python语言中各种常用的数据结构及其算法有一定的了解,同时介绍常见数据结构算法的时间复杂度,让读者从学习之初就有性能的意识,为将来编写出高质量的优秀代码打下基础。本篇还对开发过程中会用到的相关知识点(比如正则表达式、HTTP协议、字符串编码等)进行讲解,让读者对Python Web开发有一个全面的认识。特别是对容易让初学者困惑的知识,比如绝对路径和相对路径的区别、字符编码相关的内容,也进行了讲解。

第2篇和第3篇是实战部分,主要讲解“资源管理”和“个人博客系统”两个项目。从功能需求设计、模块划分,再到最终的编码实现,手把手教读者如何从零开始打造自己的项目。

第4篇是使用Django开发API,通过一个完整的教程,以逐步深入的方式,让读者享受使用Django Rest Framework进行API开发的乐趣。

第5篇是Django系统运维,让读者不仅能将服务部署好,而且还能明白各个组件的原理以及它们是如何在一起工作的,从而提高读者分析问题和解决问题的能力。最后讲解Django的一些常用功能,比如中间件、信号系统、缓存框架等,在讲解过程中会深入讲解它们的工作原理,以及使用中会遇到的一些“坑”。本书的读者

如果对Python有一定的了解,想学习Python Web开发,本书会是一个不错的选择。谁不适合读本书

不太适合一点Python基础都没有的人员。另外,如果你已经是Python Web开发方面的专家,那么这本书对你来说价值应该也不大。勘误与反馈

本书所有章节中的源代码放在https://github.com/djangobook-cn/book-code上,欢迎读者从GitHub下载并提出问题(issue),如果下载有问题,可以通过邮箱booksaga@126.com与编者联系。致谢

在编写本书时,笔者得到了各个方面非常多的建议、帮助和鼓励,在此深表感谢。

首先,特别感谢武汉大学的谭建扬同学认真细心地测试了书中的示例,指出了很多问题。

感谢研究生实验室中三位计算机专业的同学江超、张浩然和杨骁,这三位不仅仅是研究生期间的“战友”,也在我们编写本书期间给出了不少建议。

感谢赵军出色的核对工作,提出了非常多的改进意见。

最后,占用了大量周末时间来写作,这和妻子lotus的大力支持是分不开的。涂伟忠第1篇 基础知识

第1篇主要讲解Django Web开发需要的基础知识,共分为3章:

第1章将讲解Django的特点、发布情况、与主流框架的对比以及初学者开发环境的选择。

第2章将讲解初学者学习Web开发需要掌握的一些基础知识,比如Python常见的数据结构、HTTP协议等,同时也对初学者容易困惑的问题,比如绝对路径与相对路径、字符串编码问题等进行通俗易懂的讲解。

第3章将通过开发一个小实例,让读者对Django进行初步体验,尝试使用它进行一些简单的开发工作。第1章 Django简介

本章主要的内容包括:使用Django进行Python Web开发的一些基本知识,Django的特点和版本发布情况,开发者选择哪个版本以及新的Django版本是否需要升级等。本章的内容还包括Django框架和其他的主流的Python Web开发框架的简单比较,最后还介绍Django开发环境的选择。1.1 Django基本介绍

Django是用Python开发的一个免费开源的Web框架,几乎囊括了Web应用的方方面面,可以用于快速搭建高性能、优雅的网站。

Django提供了许多网站后台开发经常用到的模块,使开发者能够专注于业务部分。Django提供了通用Web开发模式的高度抽象,为频繁进行的编程作业提供了快速解决方法,并为“如何解决问题”提供了清晰明了的约定。Django通过DRY(Don't Repeat Yourself,不要重复自己)的理念来鼓励快速开发。

·自带管理后台:只需几行简单代码的设置,就可以让目标网站拥有一个强大的管理后台,轻松对内容进行增加、删除、修改与查找,并且能很方便地定制搜索、过滤等操作,因此特别适合用于内容管理平台。

·灵活的路由系统:可以定义优雅的访问地址,按需定义,毫无障碍。

·强大的数据库ORM:拥有强大的数据库操作接口(QuerySet API),可以轻松执行原生SQL。

·易用的模板系统:自带强大、易扩展的模板系统。当前后端分离开发时,可以只用Django开发API,不使用模板系统,也可以轻易替换成其他模板。

·缓存系统:与Memcached,Redis等缓存系统联合使用,获得更快的加载速度。

·国际化支持:支持多语言应用,允许定义翻译的文字,轻松翻译成不同国家/地区的语言。1.2 Django发布情况

功能版本(A.B,A.B+1,如2.0,2.1等)大约每8个月发布一次。这些版本将包含新功能以及对现有功能的改进等,也可能包含与上一个版本不兼容的功能,详细的说明在版本的发布日志(Release Notes)中可以查阅到。

补丁版本(A.B.C,如2.1.3)会根据需要发布,以修复错误和安全问题。这些版本将与相关的功能版本100%兼容,除非是出于安全原因或为了防止数据丢失而无法做到100%兼容。因此,“我应该升级到最新的补丁版本吗?”的答案永远都是“是的”。如果之前使用的是Django 2.1,现在最新的版本是Django 2.1.3,那么可以放心将2.1版本升级到2.1.3版本。

某些功能版本被指定为长期支持(LTS)版本,这种稳定版本通常自发布之日起3年以内,会持续发布安全和关键补丁,即所谓提供持续稳定的支持。

在Django官网的下载页面底部,有介绍各种版本的发布和支持生命周期,比较大的变化就是从Django 2.0开始,它不再支持Python 2。如图1-1所示,可以看到Django各版本的发布情况和支持计划等。图1-1 Django各版本的发布情况和支持计划

如果读者必须使用Python 2,那么最后一个可用的版本是1.11.x系列。新项目推荐使用最新的Django 2.x系列。1.3 Django的MVT架构简介

Django是一个Python Web框架。和大多数框架一样,Django支持MVC模式。首先来看看什么是MVC(Model-View-Controller)模式,然后了解Django MVT(Model-View-Template)的不同之处。1.3.1 MVC模式

MVC(Model-View-Controller)模式是开发Web应用程序的一种软件设计模式,其中各部分功能如下:

·模型(Model):位于模式底层,负责管理应用程序的数据。它处理来自视图的请求,并且响应来自控制器的指令以更新自身。

·视图(View):负责向用户以特定格式呈现全部或部分数据。

·控制器(Controller):控制模型和视图之间交互的代码。1.3.2 Django MVT模式

MVT(Model-View-Template)与MVC略有不同。主要区别在于Django本身已经实现了控制器(Controller)这部分的功能,暴露给开发者的是模板(Template)。我们可以简单认为Django中的模板是HTML文件,但其支持Django的模板语言。这种模板语言简单来说就是通过占位符、循环、逻辑判断等来控制页面上的内容展示,如图1-2所示。图1-2 Django中的MVT模式1.4 Django和主流Web框架对比

用于Python Web开发的框架有很多,比如Flask、Bottle、Pyramid、Webpy等,这里主要将Django同Flask与Tornado框架分别对比一下。

Flask是小而精的微框架(Micro Framework),它不像Django那样大而全。如果使用Flask开发,开发者需要自己决定使用哪个数据库ORM、模板系统、用户认证系统等,需要自己去组装这些系统。与采用Django开发相比,开发者在项目开始的时候可能需要花更多的时间去了解、挑选各个组件,正因为这样,Flask开发的灵活度更高,开发者可以根据自己的需要去选择合适的插件。由于是自己一步步地将整个系统组装起来的,因此也比较容易了解各个组件部分。当然,Flask历史相对更短,第三方App自然没有Django那么全面。

Tornado是一个Python Web框架和异步网络库,最初由FriendFeed开发。当初设计它的目的是为了解决10000个并发连接(C10K问题),传统的Apache服务器会为每个HTTP请求连接一个线程,而在大多数Linux发行版中默认线程堆(Heap)大小是8MB,当连接数量过多时,这种线程池的方式极易耗光服务器上的所有资源。Tornado会把等待资源的操作挂起,当数据准备好时,再回调相应的函数。通过使用非阻塞网络I/O,Tornado可以轻松应对数万个连接。因而Tornado也就成为长轮询,是WebSocket和其他需要与每个用户建立长期连接的应用程序的理想选择。和Django相比,使用Tornado编写异步代码对于开发者来说,没有Django或Flask编写同步代码那么简单、直接和高效。1.5 开发环境选择

本书基于Python 3.6和Django 2.1进行讲解,理论上使用Python 3.7和Django 2.2也是兼容的。

主流的操作系统有Windows,Linux,MacOS等,由于在Linux系统部署Django应用是主流方式,因此如果读者对Linux比较熟悉,推荐大家使用Linux进行Django开发。不过,因为Python是跨平台的,所以无论在哪个平台上进行Django开发都没有问题。1.5.1 Windows平台

对于Windows用户,推荐使用Anaconda来搭建开发环境。Anaconda是一个集成了Python和众多Python包的工具,比如Django、MySQL驱动、Matplotlib图像处理相关的包等,省去开发者需要逐个安装各个包的烦琐步骤。

Anaconda的官方下载地址为:https://www.anaconda.com/download/。

使用国内镜像源加速:比如使用清华大学开源软件镜像站,可以加速Python包的下载过程。conda config --add channels https://mirrors.tuna.tsinghua.edu.cn /anaconda/pkgs/free/conda config --add channels https://mirrors.tuna.tsinghua.edu.cn /anaconda/pkgs/main/conda config --set show_channel_urls yes

详见:https://mirror.tuna.tsinghua.edu.cn/help/anaconda/。1.5.2 Mac平台

可以从Python官网直接下载Python 3安装到Mac上,但笔者更推荐使用brew工具来安装,使用非常方便,从https://brew.sh网站上可以看到,直接运行下面的命令就可以安装这个工具。/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com /Homebrew/install/master/install)"

brew工具常用命令的示例如下:

·brew search mysql:查找名称中包含mysql关键词的软件包。

·brew cleanup:清除旧版本(使用这个命令时要注意,如果环境变量中设置了旧版本的路径,那么这个清除操作会导致无法使用旧版本)。

·brew info redis:查看redis的安装情况,显示相关的安装信息。如果安装了MySQL不知道如何启动,可以使用brew info mysql查看。

·brew list:查看目前电脑上安装了哪些软件。

下面使用brew来安装Python 3:$ brew install python3 或 brew install python@31.5.3 Linux平台

在Ubuntu/Debian系统下,如果没有自带Python 3,可以使用apt-get命令来安装。在RedHat/CentOS系统下可以使用yum来安装。第2章 掌握必要的基础知识

本章主要介绍Web开发需要的一些基础知识,同时也会介绍Python语言及其在开发过程中需要用到的基础知识,特别是对于初学者造成困惑的知识,比如绝对路径和相对路径的区别、字符编码相关的内容进行讲解。本章最后会介绍一下正则表达式的相关知识。2.1 Web开发需要什么基础知识

本节列出这么多内容不是为了打击初学者的信心,而是让大家在学习过程中有一个清晰的脉络。如果想在Web后端开发这条路上走得更远,需要修炼好自己的内功,这些基础知识是非常重要的。

·前端知识:最好能了解一些前端知识(HTML,CSS,JavaScript等)。但在一些分工非常明确的公司,有些开发人员只做后端开发,不懂前端的知识也是可以的,这时需要前后端的开发人员进行配合。毫无疑问,前端开发人员掌握一些后端的知识或者后端开发人员了解一些前端的知识,能使项目联调过程更顺畅、效率更高。

·Linux基础:由于在主流情况下项目部署都是使用的Linux系统,比如项目有一个Bug,在本地Windows上复现不了,就得ssh到部署的机器上想各种办法进行复现与分析。尽管Python是跨平台的,但各平台之间还是有不小的差异,因此掌握一些基础的Linux操作还是非常有必要的。

·数据库系统:Web应用一般离不开对数据库的增加、删除、修改和查询(本书简称为“增删改查”),一般都会用到数据库。读者除了掌握这些常见的操作外,最好能对数据库的原理有一些了解,虽然我们平时使用的是ORM,可能不会直接编写SQL语句,但归根结底,都是在数据库中执行SQL语句。只有理解了SQL语句,才能设计出更合理的表结构,写出更优秀的SQL语句,更好地使用ORM提供的各种功能。

·缓存系统:网站访问一般会出现热点内容,比如微博的热搜,将热点内容缓存到内存中,然后直接从内存中读取返回给查询的用户,这样无疑能极大地提高效率。有的开发人员可能觉得缓存系统比较简单,其实不然,如果深入了解各缓存系统的内存分配方式、Key淘汰算法、底层网络协议细节等,就要注意可能发生的比如缓存失效、缓存穿透、缓存雪崩等一系列问题。

·HTTP协议:由于Web开发就是遵循HTTP协议来进行的,比如可以通过Expires,Cache-Control,Last-Modified和Etag等字段来设定浏览器的缓存行为。再比如实现一个下载的功能,如果不知道HTTP协议中的Content-Disposition这个响应报头和一些约定,就可能不知道应该如何下手。

·网络协议(TCP/IP协议):常见的TCP“三次握手”“四次挥手”等过程,每一步的原理都要能够弄清楚。

·数据结构和算法:算法可以说是程序员的内功,只有更好地掌握了算法,才能编写出更高效的程序。如果编写程序时不考虑性能,觉得自己的程序能用就行了,那么这样的程序远远达不到商业使用的标准。例如,数据结构中最基础的比如队列、栈、树等以及操作它们的算法在编程过程中非常有用。

·操作系统原理:Web应用会运行在某个操作系统的一个或多个进程中。比如从日志中看到有一个接口访问时特别慢,应该怎么进行分析?影响的因素非常多,可能是网络缓慢、服务器当前负载过高、程序算法的复杂度高而效率低等。

上面列出的很多内容,初学者在刚开始时可能意识不到它们的影响力和重要性,但是随着在Web后端开发中的不断深入,就能体会出这些知识的必要性和重要程度。由于相关内容已超出了本书的范围,在此只是强调一下,有兴趣的读者可以去阅读相关的书籍,扎实地打好基础。2.2 Python语言入门

本节主要介绍Python语言中一些基础的语法知识,让读者了解Python语言中常见数据结构的操作以及常见的内置函数和模块的使用。由于本书不是一本专门讲解Python语言的书籍,想深入学习的读者需要另外花时间去“钻研”一下Python语言的相关知识。2.2.1 Python语言简介

在学习编程时,读者应该听说过C语言、C++语言等,这些语言运行前都需要进行编译,然后执行编译后的可执行文件。与这些编译型语言不同,Python语言是一种解释型的脚本语言,Python脚本文件是纯文本文件,它的文件扩展名一般是“.py”。运行所编写的Python代码时需要一个工具,它可以把脚本中的代码解释成计算机指令,同时让计算机立即执行这些指令,这个工具就是脚本解释器,解释执行的过程也就是解析执行的过程。

Python是面向对象的高级程序设计语言,它的代码简洁、简单易学,所以使用Python进行Web开发很受欢迎,有助于快速开发和实现需求。2.2.2 执行Python代码的方式1.进入Python的shell下逐行执行

在Windows中可以使用安装Python后自带的IDLE(Python图形界面的集成开发环境,如图2-1所示)或命令行工具cmd(快捷键Win+R,输入cmd即可启动命令行)。图2-1 在Windows上启动Python的方式

在Linux下可以在终端(Terminal)程序中键入“python”(小写,不含引号),即可启动Python解释器,进入Python语言的交互式的shell。随后就可以逐条输入Python语句以解释方式执行。

按Ctrl+D组合键可以退出Python的shell。2.直接执行Python脚本

在命令行使用cd命令进入相应目录,使用“python helloworld.py”命令来执行Python程序代码(即Python脚本文件)。

helloworld.py文件仅有一句,内容如下:print("hello world")

在Windows中的执行过程如图2-2所示(假设helloworld.py文件在D:\learn_python中)。图2-2 在Windows下切换工作目录并执行Python脚本文件

在Windows下还有一个比较简便的切换工作目录的方法,就是在文件管理器的地址栏输入cmd,这时cmd会自动切换到刚才的目录,如图2-3所示。图2-3 在Windows中切换工作目录的便捷方式

在Linux或MacOS中的执行过程如图2-4所示(假设helloworld.py文件在~/learn_python目录中)。图2-4 在Linux中进入相应目录执行Python脚本文件2.2.3 Python中的缩进格式

Python中的缩进格式非常重要,是与语法规则相关的,它决定了语句区块的起止和层次关系(类似C和Java等语言中用“{}”来表示语句区块的起止和层次一样)。同一层次的语句区块必须有相同的缩进格式,否则Python解释器会报错。Python函数没有明确的开始(begin)或者结束(end)关键字,也没有用大括号来标记函数从哪里开始到哪里结束,唯一的定界符就是一个冒号(:)和程序语句自身的缩进格式。正因为如此,特别是从Web页面上复制Python代码时,如果缩进格式存在问题,那么Python代码是无法运行的,如图2-5所示。图2-5 Python程序中缩进格式的说明2.2.4 常见的运算符

Python语言中常见的运算符包括布尔运算符和数学运算符。布尔运算符及其说明如表2-1所示。表2-1 布尔运算符

数学运算符及其说明如表2-2所示。表2-2 数学运算符2.2.5 数据类型

Python中一切皆对象,每种数据类型都被当作对象。虽然Python中值都有数据类型,但我们不需要声明变量的类型,Python中的变量名类似于一个标签,指向具体的数据。

Python有多种内置数据类型,常用的如下:

·布尔型(bool):值为True或False,逻辑上的真、假。用于循环语句或条件判断语句。

·整数(int):如3,-1,简称为整型。

·浮点数(float):如3.2,7.92,简称为浮点型。

·字符串(str/byte):如"hello python"。

·列表(list):是值的有序序列,如[3,2,5],其中列表中的元素可以是任何数据类型。

·元组(tuple):类似于列表,其中的值不可变,可以理解为不可变列表,如(1,3,5),(1,)。

·集合(set):是装满无序值的包,其特性为无序性、确定性、互异性。

·字典(dict):是键-值对(Key-Value Pair)的无序包。2.2.6 字符串

字符串(str)要用引号引起来,在Python中,单引号与双引号是等效的。如果想表示字符串是bytes类型,可以用b'string'。

三引号(三个单引号或三个双引号,即'''或""")可用来编写跨行的字符串,其中,单、双引号均可使用。

字符串与列表、元组类似,可以使用“索引”和“切片”,也就是可以取得字符串中的某一项或者某一部分。(1)索引:a="student",a[2]是a中第3个字母“u”(从0算起,2就是字符串中第3个字符)。(2)切片:"string"[start:end:[step=1]]中start和end必须有一个,和列表的切片功能相同,step不设置时默认为1。

"students"[1:5]是指取第2个到第5个字符,但不包括第6个(口诀:要前不要后)。

常见的操作如下:>>> my_str ='Jason' # 定义字符串my_str>>> my_str.startswith('Jas') # 若my_str以'Jas'开头,返回True, 否则返回False>>> my_str.endswith('son') # 若my_str以'son'结尾,返回True, 否则返回False备注:.startswith(), .endswith()均可以tuple为参数,满足其中之一即返回 TrueString.startswith(('a','b')) # 当String 以a或b开头时均返回True>>> my_str.count('a') # my_str中有几个 'a'>>> if 'a' in my_str: # 判断my_str中是否含有字符'a',有返回True, 否则返回False>>> my_str.find('a') # 返回'a'在my_str中的位置, 找不到则返 回-1(不是0,因为0是字符串中第一个字符,是找到了的意思)。-1在逻辑上是真,0 在逻辑上是假,所以查找字符串中是否包含指定字符,更推荐用in方法>>> my_str.index('a') # 与my_str.find('a')功能相同,但找不到时发生ValueError>>> ss = '***' # 定义字符串ss>>> my_list = ['a', 'b', 'c'] # 定义列表my_list>>> mylist_to_string = ss.join(my_list) # 使用ss来连接my_list 中各元素,返回组成的字符串给mylist_to_string,ss与my_list均未改变 mylist_to_string 值为 'a***b***c'>>> list_a = my_str.replace('a', 'b') # my_str中的'a'替换成 'b',并把替换后的字符串赋给list_a。注意my_str本身实际并未变。>>> a = u'中国' # 定义unicode字符串,如 果代码中有中文,则需要在文件开头加上#coding=utf-8

关于字符串的处理还有一个强大的工具就是正则表达式,详见后文。2.2.7 列表

列表(list)是一组有顺序的数据(属于数组,不是链表),它的元素(对象)个数是变化的(后面要介绍的元组则是固定的)。1.各种内置方法>>> list_a = [1, 2] # 定义list_a含有1,2这两个元素对象>>> list_a.append(2) # 添加一个对象到列表的末尾>>> list_a # 查看list_a中的内容[1, 2, 2] # shell中显示的结果>>> list_a.count(2) # 返回list_a中对象是2的个数2 # shell中显示有2个值为2的对象>>> list_b = [3, 4] # 定义list_b含有3,4两个对象>>> list_a.extend(list_b) # 在list_a末尾添加list_b>>> list_a # 查看list_a中的内容[1, 2, 2, 3, 4] # shell中显示的结果>>> list_a.index(3) # 返回第1个匹配的指定值在列表list_a中的位置, 列表中第1个对象的位置是0,第2个对象的位置是1,以此类推3 # shell中显示的结果>>> list_a.insert(2, 'ok') # 在list_a中位置是2的对象前添加字符串对象'ok',返回None>>> list_a # 查看list_a中的内容[1, 2, 'ok', 2, 3, 4]>>> list_a.pop() # 删除并返回列表list_a中的最后一个对象>>> list_a.remove(2) # 删除第1次出现的匹配指定值的对象,没有指定值 的话,则出现ValueError错误提示>>> list_a # 查看list_a中的内容,可以想想如何删除所有的2[1, 'ok', 2, 3, 4] # 删除列表list_a中所有的2可以用while 2 in list_a: list_a.remove(2)>>> list_a.reverse() # 将列表list_a中的所有对象的位置反转>>> list_a # 查看列表list_a中的内容[4, 3, 2, 'ok', 1]>>> List=[1, 5, 7, 1111, 2, 1.5]>>> sorted(List) # 有返回值,列表List本身不变[1, 1.5, 2, 5, 7, 1111]>>> List[1, 5, 7, 1111, 2, 1.5]>>> List.sort() # 就地操作,无返回值,结果保存到列表List本身>>> List[1, 1.5, 2, 5, 7, 1111]list_a.sort(key=None, reverse=False):对list_a排序key:指定“取值函数”。取值函数带有1个参数。sort方法从list_a中取出元素, 作为实参传递给取值函数,取值函数进行处理,再将处理后的返回值传递给比较函数reverse: 指定为True时,将排序后的顺序逆转过来,否则无任何操作list_a.sort()不指定任何参数时,对list_a按从小到大排序,返回值为None, sorted(list_a)排序时列表list_a不变,而是返回一个新的列表2.列表中元素的引用方式

通过下标方式并结合切片操作符“:”来引用列表中的元素。>>> list_a[2] = 'ok' # 给列表中某一项赋值>>> list_b = list_a[2:] # 把列表中元素从list_a[2]起到最后一个都赋 值给列表list_b>>> list_b = list_a[:3] # 相当于把list_a[0:3]中的元素(位置 0,1,2)赋给列表list_b,不包括list_a[3]>>> list_b = list_a[1:4] # 把列表中元素list_a[1]至list_a[3]赋值给 列表list_b,赋值的元素不包括list_a[4]>>> list_b = list_a[1:-1] # 将列表中元素list_a[1]到list_a中最后一项(但不包括最后一项)赋值给列表list_b。-1表示最后一项,-2表示倒数第2项,以此类推3.遍历列表中的数据for value in list_a: print(value) # 在循环中对 value 进行操作【临时变量value遍历列表list_a,循环取值,直到遍历完整个列表】

读者思考:出了for循环,value还存在么?如果list_a为空,value是什么呢?4.使用列表解析(List Comprehension)定义列表>>> my_list = [2*i for i in range(0, 5) if i > 2] # 形式为 [表达式,变量范围,条件](1)表达式:2*i,i是变量(2)变量范围:for i in range(0,5)(3)条件:if i>2

再举一例:>>> list_a = [2, 3, 4, 5, 6]>>> list_b = [3*i for i in list_a if i%2 == 0]>>> print(list_b) # 在终端显示出[6, 12, 18]5.序列相关的函数

这部分内容不仅仅适应于列表,一般来说其他的序列(比如元组、字典、集合等)也是可以使用的,读者可以自行尝试。(1)any(list):列表list中有一个元素为逻辑真,则返回True,全为假时则返回False。注意any([])返回的是False,在编程时要考虑序列为空的情况。(2)all(list):列表list中所有元素都为真时返回True,否则返回False。注意all([])返回的是True,在编程时要考虑序列为空的情况。(3)max(list)或min(list):返回列表list中的最大值或最小值。(4)enumerate():在列表中同时循环索引和元素,如:>>> List=["Weizhong", "Duanyi", "JiangChao"]>>> for index, entry in enumerate(List): print(index, entry)0 Weizhong1 Duanyi2 JiangChao(5)求和函数sum:如sum([1,2,3,4])用于求1+2+3+4之和。sum(range(1, 101)) # 可求1+2+3+4+...+100之和(6)筛选函数filter(function,sequence):对sequence进行筛选,满足条件的返回给迭代器,function的返回值只能是True或False。>>> def f(x): return x % 2 != 0 and x % 3 != 0 #函数中只有一条语 句,可写成一行,但不建议这么做,因为读起来费劲>>> list(filter(f, range(2, 25)))[5, 7, 11, 13, 17, 19, 23]>>> def f(x): return x != 'a'>>> filter(f, 'abcdef')>>> list(filter(f, 'abcdef'))['b', 'c', 'd', 'e', 'f']

例子:找出1~10之间的奇数。list(filter(lambda x: x%2 != 0, range(1, 11)))(7)map(function,sequence):把sequence中每一个元素执行function操作,将结果通过迭代器返回。>>> def cube(x): return x**3 # x**3 是x的三次方>>> list(map(cube, range(1, 11)))[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]>>> list(map(lambda s: s*2, "abcde"))['aa', 'bb', 'cc', 'dd', 'ee']

另外,map也支持多个sequence,这就要求function也支持相应数量的参数输入:>>> from operator import add>>> list(map(add, range(1, 10, 2), range(1, 5)))[2, 5, 8, 11] (8)reduce(function,list[,init]):如果提供了init参数,第一轮将init和list[0]用function函数处理,得到的结果和list[1]再经过function处理,以此类推,直到结束;如果不提供init参数,则第一轮处理直接从列表list中取出两个元素(即list[0]和list[1])用function函数进行处理。>>> from functools import reduce>>> from operator import add>>> reduce(add, range(1, 11))55 (注:1+2+3+4+5+6+7+8+9+10)>>> reduce(add, range(1, 11), 20)75 (注:20+1+2+3+4+5+6+7+8+9+10)利用reduce求阶乘方法def f(n):return reduce(lambda x, y: x*y , range(1, n+1))2.2.8 元组

元组(tuple)是一组有序且不可改变的数据,它的元素(对象)个数是固定的。可以使用强制转换my_tuple=tuple(list_a),由list_a得到一个元组my_tuple;或者使用list_a=list(my_tuple)由一个元组得到一个列表。关于元组中元素的引用方式,也是通过下标,与列表一样。

记住,元组中元素的值不能改变,因此不能给元组的元素赋值。

特殊情况(元组也不是完全不可变):(1)元组中的列表可以被改变,如:t=([2],3,7);t[0][0]=100运行后看看t的内容变成什么了。(2)t=("first","second");t=t+("third","fourth")运行后看看t的内容发生了什么变化。

思考:(1)中的t[0]能被改变吗?如果想改变的话,应该怎么做?

注意:只有一个元素的元组一定要小心,要在元素的后面加上逗号。tuple_a = ("Weizhong Tu",) # 注意后面的逗号,少了就成为string 类型了tuple_b = (999,) # 999后面的逗号,少了就成了整型数字了2.2.9 字典

字典(dict)就是“键名-数值对”(Key-Value Pair,简称“键-值对”)的无序集合。在键-值对中,键是唯一的,不可变的,值是可以改变的。{key1: value1, key2: value2}>>> my_dict = {'Jason':2011, 'Anson':2012} # 定义字典,包含2个键- 值对>>> my_dict["Wuhan"] = 120 # 增加一个新的键-值对,返回 {'Jason':2011, 'Anson':2012, "Wuhan":120}>>> my_dict["Wuhan"] = 2013 # 改变值,返回{'Jason':2011, 'Anson':2012, "Wuhan":2013}>>> my_dict["Wuhan"] # 得到2013,也就是取值,找不到时会 发生KeyError的错误>>> my_dict.get('Wuhan', None) # 和上面一样也是取值,没有对应键时不 会报错,而是返回None,其中None是默认值,可以省略,也可以传入其他默认值>>> my_dict.items() # 返回一个列表:列表中是元组(每个 键-值对组成一个二维元组)【for item in my_dict.items() 可用来在同时遍历字典中的key和value】>>> 'Jason' in my_dict # 判断my_dict中是否有键'Jason', 有则返回True,否则返回False, 相当于my_dict.has_key('Jason') >>> del my_dict['Jason'] # 删除键为'Jason'的键-值对>>> dict_a = my_dict.copy() # 将my_dict复制给新建字典dict_a>>> data = my_dict.get('Jason') # 从键为'Jason'的键-值对中取出值, 赋值给datadict.get(key,default=None) # default默认为None, 所以找不到时返回NoneNone # 屏幕显示的内容>>>my_dict.setdefault(key, value) # 当存在key时获取它对应的值,如果 不存在这key时,就加入这个key,并把它对应的值设为默认的value,并返回value>>>my_dict.keys() # 返回所有键组成的列表>>>my_dict.values() # 返回所有值组成的列表>>>my_dict.pop('Jason') # 删除键为'Jason'的键-值对,返回该键值对中 的值。若使得key不存在时报错,则要使用my_dict.pop('Jason', None)>>> my_dict.pop('Jason',None)>>> a = my_dict.pop('Jason',None)>>> print(a)None>>>my_dict.popitem() # 随时删除一个键-值对,返回二维元组(key, value)>>>my_dict.clear() # 清除所有键-值对>>> dict_a = {'Wuhan':125}>>> dict_b = {'Guilin':100}>>> my_dict.update(dict_a, **dict_b) # 在my_dict中添加dict_a, dict_b中的各个键-值对。可以只用第一个参数,即一次只添加一个字典>>> my_dict{'Wuhan': 125, 'Guilin': 100} >>> for key in my_dict: # 直接在my_dict.keys()遍历 print(key, my_dict[key])

字典排序:sorted(my_dict)相当于sorted(mydict.keys()),没有my_dict.sort()这种用法。1.有顺序的字典collections.OrderedDict>>> from collections import OrderedDict>>> dct = OrderedDict() # dct是一个有顺序的字典2.有默认值的字典

一般字典中当key不存在时使用DICT[key]时会引发KeyError错误,如果希望key不存在时返回一个默认值,除了使用DICT.get(key,default)之外,还可以用collections.defaultdict。>>> from collections import defaultdict>>> dct = defaultdict(lambda: 'No')>>> dct["key_not_exist"] # 当访问不存在的key时会返回'No'2.2.10 集合

集合(set)就是数学上集合的概念,它具有互异性、确定性、无序性。>>> set_a = {1, 2} # 定义集合,或用set_a=set()定义空集合>>> set_a.add(4) # 向set_a中添加元素4>>> set_a.remove(2) # 从集合set_a中删除2,没有的话会引发KeyError 错误>>> set_a.discard(2) # 删除集合set_a中的元素2,remove的友好版本>>> set_a.pop() # 从集合set_a中随机删除一个值,并返回该值。从空 集合中pop会引发KeyError错误,集合的pop()无参数,不同于字典>>> set_a.clear() # 清空集合>>> set_b = set_a.copy() # 将set_a内容复制给set_b(浅复制)【"set_b = set_a" 表示“引用”关系,并非是复制,也可用 set_b=set_a[:] 来 复制】>>> set_a.update([5,9,2]) # 将5,9,2(可以是任意多个值)加入集合,根 据数字中集合的概念,相同的值不会重复加入>>> set_c = set_a | set_b # 并集set_c为set_a和set_b的并集>>> set_c = set_a & set_b # 交集set_c为set_a和set_b的交集>>> set_c = set_a - set_b # 差集set_c为set_a去掉其与set_b公共的部 分>>> set_c = set_b ^ set_a # 异或set_c为set_b并set_a,再去掉二者公 共的部分s |= t 并,s与t并集,结果存到s中,相当于s=s.union(t)或s.update(t)s &= t 交,s与t交集,结果存到s中,相当于s=s.intersection(t)或 s.intersection_update(t)s -= t 差,s与t差集,结果存到s中,相当于s=s.difference(t)或 s.difference_update(t)s ^= t 异或,s与t不同的部分并到一起 (即s和t的并集去掉s和t的交集),结果 存到s中,相当于s = s.symmetric_difference(t) 或 s.symmetric_difference_update(t)>>> 3 in set_a # 判断set_a中是否有元素3,有则返回True,否则返回False>>> set_a <= set_b # 判断set_a是否为set_b的子集,返回True 或False,相当于set_a.issubset(set_b)>>> set_a >= set_b # 判断set_a是否为set_b的超集(父集),返 回True 或False,相当于set_a.issupset(set_b)【if 语句中,空集合为False,任何非空集合为真值】

思考:字典和集合都是用{},那么如何定义一个空的集合?>>> a = {} # 定义一个空字典,也可用a = dict()>>> type(a) # >>> a = set() # 定义一个空集合>>> type(a) # 2.2.11 数据类型的转换

使用关键字可以很容易地实现数据类型之间的转换,比如int、str、list、tuple、set等。(1)利用集合的互异性对列表去重,即去掉列表中的重复元素:list_a=list(set(list_a))把list_a变成集合,再变成列表。(2)字典转换为集合和列表,可以轻松得到类似于集合的键-值对dict_a.items(),键dict_a.keys(),值dict_a.values(),这些值可以和集合求交集、并集。

使用list(dict_a)获取key列表,结果等价于list(dict_a.keys())。(3)字符串与整型转换:字符串转换成整型int("2013"),整型转换成字符串str(120)。(4)整型与浮点型互相转换:整型转换成浮点型float(2),浮点型转换成整型,int(2.9)的结果为2,其中的小数部分被舍去。如果想向上取整,可以用math模块的math.ceil(2.1),它的结果为3。(5)元组、列表、集合转换为字符串:使用"".join(sequence);而把字符串转换为列表,则使用string.split()。2.2.12 常见数据结构操作的时间复杂度

本节将讲述当前CPython中常见数据结构各种操作的时间复杂性。其他的Python实现(旧的或仍在开发中的CPython版本)可能会稍微不同,通常我们关注“平均情况”的时间复杂度就可以了。

下文中,n是容器中当前元素的数量,k是参数的值或参数中的元素个数。1.列表

在CPython内部,列表被表示为一个数组;如果向列表中新增元素使得需要的内存空间的大小超出了当前分配内存空间的大小,则会导致所有元素都要移动,代价会很高。

在表2-3中,假设s是一个列表对象,其中“平均情况”是指参数随机均匀生成(而非某些特例)。表2-3 列表常见操作的时间复杂度平均情况

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载