开发|Python核心知识A

A篇,主要介绍Python基础中列表,元祖,字典,集合,字符串,I/O,条件与循环,异常处理的底层知识与使用的注意事项。

希望大家对于Python会有新的收获,本篇不同于之前的浅谈Python基础知识,会更加的深入,但是在深入的同时,涉及更多内容,需要自行看源码,着重点我会标明。

前言

目前所有的文章思想格式都是:知识+情感。
知识:对于所有的知识点的描述。力求不含任何的自我感情色彩。
情感:用我自己的方式,解读知识点。力求通俗易懂,完美透析知识。

正文

由于本文不是基础篇,所以重要的名词与知识点,如果不懂,就一定要多google.

谈谈Jupyter Notebook

使用过jupyter的人都知道,我简短做一下jupyter的介绍。

**Jupyter Notebook 官网: **https://jupyter.org/

** Jupyter 创始人: ** Fernando Pérez

**Jupyter 单词的解释: **Ju (Julia)、Py (Python)和 R 三种科学运算语言的计算工具平台,所以将其命名为 Ju-Py-te-R。

Jupyter能干什么: 软件代码、计算输出、解释文档、多媒体资源整合在一起的多功能科学运算平台

建议: jupyter属于我定义的工具范畴,是加快学习的工具,所以需要掌握。

备注:关于jupyter在Python的安装与使用,我在IPython介绍里面已经写过。

谈谈列表(list)

列表内可以放置的内容: 任意数据类型。(有序)

特性: 列表是动态的,长度大小不固定,可以随意地增加、删减或者改变元素(mutable)。

list操作: 多使用append(),enumerate(),切片(注意步长的正负),使用[....]创建list(直接识别调用内置C函数),使用list()创建(使用函数方法,会创建stack,并进行操作的检验,expensive!)

时间复杂度:

增加 / 删除的时间复杂度均为 O(1)。

列表进行排序,然后使用二分查找,时间复杂度 O(logn) .

列表排序需要时间: O(nlogn)

遍历列表的时间复杂度是: O(n)

两层列表循环,在最差情况下,需要 O(n^2) 的时间复杂度。

list使用场景: 存储的数据和数量是不变

底层实现: 在cpython中,为了减小每次增加 / 删减操作时空间分配的开销,Python 每次分配空间给列表的时候,都会额外多分配一些,这样的机制(over-allocating)。

源码角度:

浏览器输入:

1)https://github.com/python/cpython/blob/949fe976d5c62ae63ed505ecf729f815d0baccfc/Include/listobject.h#L23

2)https://github.com/python/cpython/blob/3d75bd15ac82575967db367c517d7e6e703a6de3/Objects/listobject.c#L33

显示list源码关键内容如下:

#ifndef Py_LIMITED_API
typedef struct {
PyObject_VAR_HEAD
/* Vector of pointers to list elements. list[0] is ob_item[0], etc. */
PyObject **ob_item; /* ob_item contains space for 'allocated' elements. The number
* currently in use is ob_size.
* Invariants:
* 0 <= ob_size <= allocated
* len(list) == ob_size
* ob_item == NULL implies ob_size == allocated == 0
* list.sort() temporarily sets allocated to -1 to detect mutations.
*
* Items must normally not be NULL, except during construction when
* the list is not yet visible outside the function that builds it.
*/
Py_ssize_t allocated;
} PyListObject;
#endif

源码解读:

列表(list)本质是 over-allocate 的数组(array)。(注意,数组就是数组,列表就是列表,数组不是列表,列表不是数组,不是一个概念。)

ob_item是一个指针列表,里面的每一个指针都是指向列表的元素。(这就是为什么列表可变)

allocated 表示的是当前列表确实被分配的空间大小。

ob_size 是列表的实际大小,实际大小是len(list) 获得结果,表示当前列表共存储了多少个元素。

为优化存储结构,避免每一次更改元素都重新分配内存,列表的分配空间allocated 会大于 ob_size。即: allocated >= len(list) == ob_size。

当分配给列表的空间满了的时候,就是allocated == len(list) 的情况,此时会向操作系统申请更大的内存空间,并将已经存在的元素全部拷贝到新的内存中。

每一个向操作系统申请内存的大小变化是:0, 4, 8, 16, 25, 35, 46, 58, 72, 88....

谈谈元祖(tuple)

元祖内可以放置的内容: 任意数据类型。(有序)

特性: 元祖是静态的,长度固定,无法增加删减或改变。

注意:

  1. 只要对元祖修改,必然是开辟一块新的内存,将原有数据重新写入。

    2)虽然属于不可变数据类型,但是内部嵌套可变数据类型,可变数据类型仍属于动态。

tuple使用场景: 存储的数据和数量是变化的。

底层实现: ** Python内部对于静态资源 ,存在资源缓存(resource caching)

解释一下,资源缓存就是静态数据当不被使用并且占用内存空间不大的时候,Python会对这些 资源进行缓存处理,并不会由于
垃圾回收机制**而将数据返回给操作系统。当下次创建静态数据的时候,会直接使用已经缓存的内存空间,此时就节省了与操作系统交互的环节。

当tuple的大小不超过20,Python将其缓存子啊一个free list中,当下一次创建同样的tuple的时候,就直接去缓存中取出来,提高运行效率。

源码角度:

浏览器输入:

1)https://github.com/python/cpython/blob/3d75bd15ac82575967db367c517d7e6e703a6de3/Include/tupleobject.h#L25

2)https://github.com/python/cpython/blob/3d75bd15ac82575967db367c517d7e6e703a6de3/Objects/tupleobject.c#L16

显示tuple源码关键内容如下:

#ifndef Py_LIMITED_API
typedef struct {
PyObject_VAR_HEAD
PyObject *ob_item[1]; /* ob_item contains space for 'ob_size' elements.
* Items must normally not be NULL, except during construction when
* the tuple is not yet visible outside the function that builds it.
*/
} PyTupleObject;
#endif

源码解读:

tuple本质上也是一个数组(array),但是空间是固定的。并且tuple做了相应的优化(资源缓存),提升程序的效率。

谈谈字典(dict)

字典 :是一系列由键(key)和值(value)配对组成的元素的集合。

key必须是不可变数据类型。(只有不可变数据类型才可以hash)

字典变成有序的啦!!!

在 Python3.7+,字典被确定为有序。

在 3.6 中,字典有序是一个 implementation detail,在 3.7 才正式成为语言特性,因此 3.6 中无法 100% 确保其有序性。

而 3.6 之前是无序的,其长度大小可变,元素可以任意地删减和改变。

字典的操作:

多使用{....}创建,少使用dict() 创建。

多使用.get()获取值,少使用[...]获取值。(get不报错,并可以自己指定没找到的返回值)。

常使用pop(), items(), keys(), values()。

时间复杂度:

存储,删除,增加数据的时间复杂度是: O(1)

字典的存储结构:

此时,需要回忆数据库的表结构。

老版本 Python 的哈希表结构如下:(随着数据量的增加,表会变的稀疏,空间利用率低)

它是一个 over-allocate 的 array,根据元素键(key)的哈希值,来计算其应该被插入位置的索引。

--+-------------------------------+
| 哈希值 (hash) 键 (key) 值 (value)
--+-------------------------------+
0 | hash0 key0 value0
--+-------------------------------+
1 | hash1 key1 value1
--+-------------------------------+
2 | hash2 key2 value2
--+-------------------------------+
. | ...
__+_______________________________+

新版本哈希表,除了字典本身的结构,会把索引和哈希值、键、值单独分开,看下面:(提高空间利用率)

它把存储结构分成了 Indices 和 Entries 这两个 array,而’None‘代表这个位置分配了内存但没有元素。

Indices
----------------------------------------------------
None | index | None | None | index | None | index ...
---------------------------------------------------- Entries
--------------------
hash0 key0 value0
---------------------
hash1 key1 value1
---------------------
hash2 key2 value2
---------------------
...
---------------------

字典的工作原理:

1)计算key的哈希值,hash(key)

2)mask = PyDicMinSize - 1 和哈希值做与操作,计算这个元素应该插入哈希表的位置 index = hash(key) & mask。

3)如果哈希表此处是空的,那么这个元素就会被插入。

4)如果这个元素不是空的,分类讨论:

a:比较两个元素的哈希值和键是否相等,如果相等,表明这是同一个元素,如果值不同,增跟新字典的value,反之,啥都不错。

b:比较两个元素的哈希值和键是否相等,如果不相等,此时**哈希冲突(hash collision **意思是两个元素的键不相等,但是哈希值相等。)此时,需要一种解决冲突的策略。(最简单是线性查找,即从这个位置开始,挨个往后寻找空位,找到就插进去。但是Python不使用这个,因为线性效率不高)

注意:哈希冲突情况的发生,会降低字典的查找等操作速度。但是,哈希冲突概率极小,但是不代表不发生。

所以哈希表,通常会保证其至少留有** 1/3 的剩余空间。随着元素的不停插入,当剩余空间小于 1/3 时,Python 会重新申请得到更大的内存空间,扩充哈希表。此时,表内所有的元素位置都会被重新排放**。

谈谈集合(set)

集合: 没有键和值的配对,是一系列无序的、唯一的元素组合。

集合本质: 是一个 哈希表。(不能索引)

集合操作:

不要使用pop()。(集合无序,pop谁???)

时间复杂度:

添加与查找的时间复杂度是 O(1)

列表的哈希表:完全等同于字典的哈希表思路,只是没有value而已。

谈谈字符串(str)

字符串: 是由独立字符组成的一个序列,通常包含在单引号('')双引号("")或者三引号之中(''' '''或""" """,两者一样)。(不可变数据类型)

字符串操作:

字符串的算数运算: + 、*

多用 .join() 函数,实现字符串拼接

多使用 strip() ,split()

时间复杂度:

更改字符串的时间复杂度是O(n)

字符串的+操作:

从 Python2.5 开始,每次处理字符串的拼接操作时(str1 += str2),Python 首先会检测 str1 还有没有其他的引用。

如果没有的话,就会尝试原地扩充字符串 buffer 的大小,而不是重新分配一块内存来创建新的字符串并拷贝。

时间复杂度为 O(n) ,所以就可以直接使用+ 了吗??

字符串的格式化

官方推荐使用: ''.format() ,是最新的字符串格式函数与规范

可以使用之前的方法: % 进行格式化。%s 表示字符串型,%d 表示整型。

谈谈I/O

I/O表示的是输入输出,不知道大家会不会直接想到,input()与print(),文件操作

input() 函数暂停程序运行,同时等待键盘输入;直到回车被按下,函数的参数即为提示语,输入的类型永远是字符串型(str)

所以,针对输入的str一般需要进行强制转换为 int 用 int(),转为浮点数用 float()。

Python 对 int 类型没有最大限制,但是对 float 类型有精度限制。

注意:在生产环境中使用强制转换时,请记得加上 try .....except(即错误和异常处理)。

文件操作:

生产级别的 Python 代码,大部分 I/O 则来自于文件、网络、其他进程的消息等。

计算机内核(kernel)对文件的处理相对比较复杂,涉及到内核模式、虚拟文件系统、锁和指针等一系列概念。建议所有的 I/O 都应该进行错误处理。

文件操作概览:

1)open()函数

2)打开文件方式 r (默认),w, a .... (注意:只需要读取文件,就不要请求写入权限)

3)read() (注意:文件过大的处理方法,可以给 read 指定参数 size ,用来表示读取的最大长度。还可以通过 readline() 函数,每次读取一行)

4)write()

5)close()

with上下文管理:

自动判断关闭打开的文件,代码简洁,不需要close()的出现。

JSON序列化:

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它的设计意图是把所有事情都用设计的字符串来表示,这样既方便在互联网上传递信息,也方便人进行阅读(相比一些 binary 的协议)。

JSON操作

json.dumps() 这个函数,接受 Python 的基本数据类型,然后将其序列化为 string;

而 json.loads() 这个函数,接受一个合法字符串,然后将其反序列化为 Python 的基本数据类型。

注意: 进行异常捕获。

**JSON业务场景: **当开发一个第三方应用程序时,可以通过 JSON 将用户的个人配置输出到文件,方便下次程序启动时自动读取。

**扩展: **在 Google,有类似的JSON工具叫做 Protocol Buffer,已经开源。

它的优点是生成优化后的二进制文件,因此性能更好。但与此同时,生成的二进制序列,是不能直接阅读的。

谈谈条件与循环

条件: if 语句是可以单独使用的,但 elif、else 都必须和 if 成对使用

注意:除了 boolean 类型的数据,条件判断最好是显性的。

if num != 0:
print(num)

循环:

分为while循环和for循环。并且可以使用break与continue.

要尽量避免多层嵌套的情况

range函数:直接由 C 语言写的,调用它速度非常快。并且特是一个迭代器。

>>> d = range(10)
>>> d
range(0, 10)
>>> type(d)
<class 'range'>

三元运算

使用三元运算可以简洁明了,配合列表与字典的生成式,此时达到最高境界~(一行搞定千言万语)

谈谈异常处理

错误至少包括两种,一种是语法错误,另一种则是异常

语法错误: 就是各种Error.....

官方解释:https://docs.python.org/3/library/exceptions.html#bltin-exceptions

异常: try ... except ... finally.. 来解决异常。

注意:except block 只接受与它相匹配的异常类型并执行,如果程序抛出的异常并不匹配,那么程序照样会终止并退出。

万能异常爸爸,Exception。Exception 是其他所有非系统异常的基类,能够匹配任意非系统异常

finally 中,通常会放一些无论如何都要执行的语句。

自定义异常:

raise 主动抛出异常。

异常应用场景:

大型社交网站的后台,需要针对用户发送的请求返回相应记录。用户记录往往储存在 key-value 结构的数据库中,每次有请求过来后,我们拿到用户的 ID,并用 ID 查询数据库中此人的记录,就能返回相应的结果。

而数据库返回的原始数据,往往是 json string 的形式,在 json.loads() 函数中,输入的字符串如果不符合其规范,那么便无法解码,就会抛出异常,因此需要加上异常处理。

注意: 正常的 flow-control 逻辑,不要使用异常处理,直接用条件语句解决就可以了。

一般来说异常抛出,都会对其进行Log(一般每1000次log一次),输出到real time的table和dashboard里,这样有利于之后的分析和改进。

except之后的delete操作:

"When an exception has been assigned using as target, it is cleared at the end of the except clause."
# 在异常处理的 except block 中,把异常赋予了一个变量,那么这个变量会在 except block 执行结束时被删除
# 在平时写代码时,一定要保证 except 中异常赋予的变量,在之后的语句中不再被用到。 比如下面这个code block:
except E as N:
foo 就等于
except E as N:
try:
foo
finally:
del N

结束语

本文涵盖了我目前学习Python的基础知识的所有深度知识点。希望大家学习的时候,可以区分出什么是深度与浅度,对深度加以理解。大不了就是github源码来一下....

祝,大家阅读开心 C-:

开发技术--Python核心知识A的更多相关文章

  1. 零基础的学习者应该怎么开始学习呢?Python核心知识学习思维分享

    近几年,Python一路高歌猛进,成为最受欢迎的编程语言之一,受到无数编程工作者的青睐. 据悉,Python已经入驻部分小学生教材,可以预见学习Python将成为一项提高自身职业竞争力的必修课.那么零 ...

  2. 14 张思维导图构建 Python 核心知识体系

    ZOE是一名医学生,在自己博客分享了很多高质量的思维导图.本文中所列的 14 张思维导图(高清图见文末),是 17 年作者开始学习 Python 时所记录的,希望对大家有所帮助.原文:https:// ...

  3. 开发技术--Python核心技术B

    开发|Python核心技术B B篇,主要介绍Python的自定义函数,匿名函数,面向对象,模块化. 由于不涉及基础的知识,我会将重难点加以解释. 前言 目前所有的文章思想格式都是:知识+情感. 知识: ...

  4. 开发技术--浅谈python基础知识

    开发|浅谈python基础知识 最近复习一些基础内容,故将Python的基础进行了总结.注意:这篇文章只列出来我觉得重点,并且需要记忆的知识. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对 ...

  5. 适用于 PHP 开发人员的 Python 基础知识

    Thomas Myer, 负责人, Triple Dog Dare Media 简介: 您是一名经验丰富的 PHP 开发人员,并且希望学习 Python 吗?本文将从 PHP 开发人员的角度来探索 P ...

  6. Python开发技术详解PDF

    Python开发技术详解(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1F5J9mFfHKgwhkC5KuPd0Pw 提取码:xxy3 复制这段内容后打开百度网盘手 ...

  7. 《Python测试开发技术栈—巴哥职场进化记》—前言

    写在前面 今年从4月份开始写一本讲Python测试开发技术栈的书,主要有两个目的,第一是将自己掌握的一些内容分享给大家,第二是希望自己能系统的梳理和学习Python相关的技术栈.当时我本来打算以故事体 ...

  8. 《python开发技术详解》|百度网盘免费下载|Python开发入门篇

    <python开发技术详解>|百度网盘免费下载|Python开发入门篇 提取码:2sby  内容简介 Python是目前最流行的动态脚本语言之一.本书共27章,由浅入深.全面系统地介绍了利 ...

  9. 《Python测试开发技术栈—巴哥职场进化记》—软件测试工程师“兵器库”

    上文<Python测试开发技术栈-巴哥职场进化记>-初来乍到,请多关照 我们介绍了巴哥入职后见到了自己的导师华哥,第一次参加团队站会,认识了团队中的开发小哥哥和产品小姐姐以及吃到了公司的加 ...

随机推荐

  1. ABP进阶教程6 - 布局配置

    点这里进入ABP进阶教程目录 解读参数 l - length changing input control (左上,每页显示记录数) f - filtering input (右上,过滤条件) t - ...

  2. 【JavaWeb】实现二级联动菜单

    实现效果 频道信息 package demo; public class Channel { private String code; //频道编码 private String name; //频道 ...

  3. [b0020] python 归纳 (六)_模块变量作用域

    test_module2.py: # -*- coding: utf-8 -*-"""测试 模块变量的作用域 总结:1 其他模块的变量,在当前模块的任何地方,包括函数都可 ...

  4. REST API接口测试

    背景介绍 为什么要做借口测试? 很多系统关联都是基于接口来实现的,接口测试可以将复杂的系统关联进行简化. 接口功能比较单一,能够比较好的进行测试覆盖,也相对容易实现自动化持续集成. 接口相当于界面功能 ...

  5. 【树状数组】2019徐州网络赛 query

    (2)首先成倍数对的数量是nlogn级别的,考虑每一对[xL,xR](下标的位置,xL < xR)会对那些询问做出贡献,如果qL <= xL && qR >= xR, ...

  6. calcifications loss

    import keras import tensorflow as tf from keras.models import Model from keras import backend as K # ...

  7. ionic4 ion-picker用法

    ion-picker实际开发中肯定多处使用,所以封装成服务的形式调用 新建picker.service服务模块   ionic g service picker import { Injectable ...

  8. 第十 构建Web内容的技术

    第十章 构建Web内容的技术 一.HTML HTML(HyperText Markup Language,超文本标记语言)是为了发送Web 上的超文本(Hypertext)而开发的标记语言.超文本是一 ...

  9. 2019 SDN上机第二次作业

    2019 SDN上机第二次作业 1.利用mininet创建如下拓扑,要求拓扑支持OpenFlow 1.3协议,主机名.交换机名以及端口对应正确,请给出拓扑Mininet执行结果,展示端口连接情况 1. ...

  10. split task

    和印度的team合作的时候,他们经常有些要求,然后我们这边有时候需要改代码来满足他们的需求. 最近一次,他们要求在我们的一个工具中为他们加入2个asp.net的注册命令,不知道什么原因,system ...