元编程python
1. 怎么理解元编程
1.一种语言本来做不到的事情,通过你编程来修改它,使得它可以做到了,这就是元编程。
2.就是用代码生成(操纵)代码。
3.常见的开发语言均能做到元编程,Lisp这货就不用多说了,C的Marco,C++的Template,Java的Annotation,C#的Attribute、Reflection、CodeDom和IL Emitter,各种脚本语言(如js、python)的eval,甚至连Unix/Linux的shell脚本也能。
4.元编程常见的应用场景很多,扩展(重构)语法、开发DSL、生成代码、根据特定场景自动选择代码优化、解决一些正交的架构设计问题、AOP等等。
5.所以元编程存在的目的,就是多提供了一个抽象层次。
6.至于元编程有什么优缺点,争议还是比较大的。比如以重构语法的应用为例,很多元编程的反对者就认为这样会导致代码的可读性、可维护性降低,分化社区,影响交流,因为每个开发人员都能搞一个自己的方言。
总的来说,元编程玩得转的话会让你日子好过一些,玩不转会让你日子不好过一些。
2. 如下代码中违反了哪项编码规范
如下代码中违反了第四项编码规范,代码中是违反了第四项他的一个编码规定的他的一个编码规范的这一个第四项的话,他们内容是指的是不能够在不开机的时候就对他的一个电脑进行一个随便的一个键盘的一个按键。
3. python就业方向
python就业方向:python开发工程师、人工智能工程师、大数据分析工程师、爬虫开发工程师、搜索引擎工程师、游戏开发工程师、系统运维工程师。
Python具除了易读易写更兼具面向对象和函数式风格,还有不错元编程能力已经成为IT运维、科学计算、数据处理等领域的主要编译语言。
通过系统化的将各种管理工具结合,对各类工具进行二次开发,形成统一的服务器管理系统。
4. 怎么理解元编程
Meta- 这个前缀在希腊语中的本意是“在…后,越过…的”,类似于拉丁语的 post-,比如 metaphysics 就是“在物理学之后”,这个词最开始指一些亚里士多德的着作,因为它们通常排序在《物理学》之后。
但西方哲学界在几千年中渐渐赋予该词缀一种全新的意义:关于某事自身的某事。比如 meta-knowledge 就是“关于知识本身的知识”,meta-data 就是“关于数据的数据”,meta-language 就是“关于语言的语言”,而 meta-programming 也是由此而来,是“关于编程的编程”。
弄清了词源和字面意思,可知大陆将 meta- 这个前缀译为“元”并不恰当。台湾译为“后设”,稍微好一点点,但仍旧无法望文生义。也许“自相关”是个不错的选择,“自相关数据”、“自相关语言”、“自相关编程”——但是好像又太罗嗦了。
Anyway。先看看 meta-data:“我的电话是 +86 123 4567 8910”——这是一条数据;“+86 123 4567 8910 有十三个数字和一个字符,前两位是国家代码,后面是一个移动电话号码”是关于前面那条数据的数据。那么照猫画虎,怎样才算 meta-programming 呢?泛泛来说,只要是与编程相关的编程就算是 meta-programming 了——比如,若编程甲可以输出 A - Z,那么写程序甲算“编程”;而程序乙可以生成程序甲(也许还会连带着运行它输出 A - Z),那么编写程序乙的活动,就可以算作 meta-programming,“元编程”。注意,程序甲和程序乙并不一定是同一种语言:
('A'..'Z').each do |char|
system("python -c 'print \"#{char}\"'")
end
如此说来,inline SQL 甚至动态生成 HTML 也是元编程了?抠定义的话是这样吧。
不过 metaprogramming 更狭义的意思应该是指“编写能改变语言语法特性或者运行时特性的程序”。换言之,一种语言本来做不到的事情,通过你编程来修改它,使得它可以做到了,这就是元编程。本版同文提及 method_missing,那么 Wat — Destroy All Software Talks 之中给出了运行时元编程的经典范例:
>> ruby has no bare words
NameError: undefined local variable or method `words' for main:Object
from (irb) 1
>> def method_missing(*args); args.join(" "); end
=> nil
>> ruby has bare words
=> "ruby has bare words"
>> bare words can even have bangs!
=> "bare words can even have bangs!"
C、C++、Python、JavaScript…… 多数流行的语言或多或少都有元编程能力;Lisp 诸方言更是以元编程为基本。而 Ruby 更是因为元编程易用又强大,被许多人拿来写 DSL,因为元编程可以捏出“本不存在的语法特性”来让书写 DSL 变得简单。
5. Python 有什么缺点
python的整个系统,我其实有非常多的不满。但是用任何一门语言都是取舍问题,如果有一门语言,库够多,已读,易用,性能高,我毫不犹豫立刻转过去。python的强处在于庞大的库,还有非常好的易读和易用性。但是相比来说,性能一直是个问题。python的实现性能大约和C相差五倍上下。如果是大规模计算问题,大约能差10倍以上。当然,我们可以写C扩展,但是这就不是使用python了。我们也可以说,很多时候我们不需要这么快的速度。这是个事实,但是不改变python性能差的事实。 python不但性能差,还有GIL这个玩意。以至于我现在对高并发计算都采取多进程的模式。多进程模式的通讯效率肯定比多线程低,而且麻烦。
另外,python在底层设计上,也表现出很强的实用主义倾向。这是比较外交术语的词汇,更加直白的说法应当是,混乱,不知所谓。在闭包设计上采用free variable设计,而不是lisp中的environs设计。区别?你试试看在外层闭包中from lib import *。由于引入不定个数名称,free variable无法处理。类似的问题还有LEGB规则,新手往往要花很长时间研究这个例子究竟是怎么错的: a = 1 def f(): print a a = 2 我勒个去,这种反直观反人类的事情都有,还敢说自己易读。
6. 如何用 Python 实现一个图数据库(Graph Database)
本文章是 重写 500 Lines or Less 系列的其中一篇,目标是重写 500 Lines or Less 系列的原有项目:Dagoba: an in-memory graph database。
Dagoba 是作者设计用来展示如何从零开始自己实现一个图数据库( Graph Database )。该名字似乎来源于作者喜欢的一个乐队,另一个原因是它的前缀 DAG 也正好是有向无环图 ( Directed Acyclic Graph ) 的缩写。本文也沿用了该名称。
图是一种常见的数据结构,它将信息描述为若干独立的节点( vertex ,为了和下文的边更加对称,本文中称为 node ),以及把节点关联起来的边( edge )。我们熟悉的链表以及多种树结构可以看作是符合特定规则的图。图在路径选择、推荐算法以及神经网络等方面都是重要的核心数据结构。
既然图的用途如此广泛,一个重要的问题就是如何存储它。如果在传统的关系数据库中存储图,很自然的做法就是为节点和边各自创建一张表,并用外键把它们关联起来。这样的话,要查找某人所有的子女,就可以写下类似下面的查询:
还好,不算太复杂。但是如果要查找孙辈呢?那恐怕就要使用子查询或者 CTE(Common Table Expression) 等特殊构造了。再往下想,曾孙辈又该怎么查询?孙媳妇呢?
这样我们会意识到,SQL 作为查询语言,它只是对二维数据表这种结构而设计的,用它去查询图的话非常笨拙,很快会变得极其复杂,也难以扩展。针对图而言,我们希望有一种更为自然和直观的查询语法,类似这样:
为了高效地存储和查询图这种数据结构,图数据库( Graph Database )应运而生。因为和传统的关系型数据库存在极大的差异,所以它属于新型数据库也就是 NoSql 的一个分支(其他分支包括文档数据库、列数据库等)。图数据库的主要代表包括 Neo4J 等。本文介绍的 Dagoba 则是具备图数据库核心功能、主要用于教学和演示的一个简单的图数据库。
原文代码是使用 JavaScript 编写的,在定义调用接口时大量使用了原型( prototype )这种特有的语言构造。对于其他主流语言的用户来说,原型的用法多少显得有些别扭和不自然。
考虑到本系列其他数据库示例大多是用 Python 实现的,本文也按照传统,用 Python 重写了原文的代码。同样延续之前的惯例,为了让读者更好地理解程序是如何逐步完善的,我们用迭代式的方法完成程序的各个组成部分。
原文在 500lines 系列的 Github 仓库中只包含了实现代码,并未包含测试。按照代码注释说明,测试程序位于作者的另一个代码库中,不过和 500lines 版本的实现似乎略有不同。
本文实现的代码参考了原作者的测试内容,但跳过了北欧神话这个例子——我承认确实不熟悉这些神祇之间的亲缘关系,相信中文背景的读者们多数也未必了解,虽然作者很喜欢这个例子,想了想还是不要徒增困惑吧。因此本文在编写测试用例时只参考了原文关于家族亲属的例子,放弃了神话相关的部分,尽管会减少一些趣味性,相信对于入门级的代码来说这样也够用了。
本文实现程序位于代码库的 dagoba 目录下。按照本系列程序的同意规则,要想直接执行各个已完成的步骤,读者可以在根目录下的 main.py 找到相应的代码位置,取消注释并运行即可。
本程序的所有步骤只需要 Python3 ,测试则使用内置的 unittest , 不需要额外的第三方库。原则上 Python3.6 以上版本应该都可运行,但我只在 Python3.8.3 环境下完整测试过。
本文实现的程序从最简单的案例开始,通过每个步骤逐步扩展,最终形成一个完整的程序。这些步骤包括:
接下来依次介绍各个步骤。
回想一下,图数据库就是一些点( node )和边( edge )的集合。现在我们要做出的一个重大决策是如何对节点/边进行建模。对于边来说,必须指定它的关联关系,也就是从哪个节点指向哪个节点。大多数情况下边是有方向的——父子关系不指明方向可是要乱套的!
考虑到扩展性及通用性问题,我们可以把数据保存为字典( dict ),这样可以方便地添加用户需要的任何数据。某些数据是为数据库内部管理而保留的,为了明确区分,可以这样约定:以下划线开头的特殊字段由数据库内部维护,类似于私有成员,用户不应该自己去修改它们。这也是 Python 社区普遍遵循的约定。
此外,节点和边存在互相引用的关系。目前我们知道边会引用到两端的节点,后面还会看到,为了提高效率,节点也会引用到边。如果仅仅在内存中维护它们的关系,那么使用指针访问是很直观的,但数据库必须考虑到序列化到磁盘的问题,这时指针就不再好用了。
为此,最好按照数据库的一般要求,为每个节点维护一个主键( _id ),用主键来描述它们之间的关联关系。
我们第一步要把数据库的模型建立起来。为了测试目的,我们使用一个最简单的数据库模型,它只包含两个节点和一条边,如下所示:
按照 TDD 的原则,首先编写测试:
与原文一样,我们把数据库管理接口命名为 Dagoba 。目前,能够想到的最简单的测试是确认节点和边是否已经添加到数据库中:
assert_item 是一个辅助方法,用于检查字典是否包含预期的字段。相信大家都能想到该如何实现,这里就不再列出了,读者可参考 Github 上的完整源码。
现在,测试是失败的。用最简单的办法实现数据库:
需要注意的是,不管添加节点还是查询,程序都使用了拷贝后的数据副本,而不是直接使用原始数据。为什么要这样做?因为字典是可变的,用户可以在任何时候修改其中的内容,如果数据库不知道数据已经变化,就很容易发生难以追踪的一致性问题,最糟糕的情况下会使得数据内容彻底混乱。
拷贝数据可以避免上述问题,代价则是需要占用更多内存和处理时间。对于数据库来说,通常查询次数要远远多于修改,所以这个代价是可以接受的。
现在测试应该正常通过了。为了让它更加完善,我们可以再测试一些边缘情况,看看数据库能否正确处理异常数据,比如:
例如,如果用户尝试添加重复主键,我们预期应抛出 ValueError 异常。因此编写测试如下:
为了满足以上测试,代码需要稍作修改。特别是按照 id 查找主键是个常用操作,通过遍历的方法效率太低了,最好是能够通过主键直接访问。因此在数据库中再增加一个字典:
完整代码请参考 Github 仓库。
在上个步骤,我们在初始化数据库时为节点明确指定了主键。按照数据库设计的一般原则,主键最好是不具有业务含义的代理主键( Surrogate key ),用户不应该关心它具体的值是什么,因此让数据库去管理主键通常是更为合理的。当然,在部分场景下——比如导入外部数据——明确指定主键仍然是有用的。
为了同时支持这些要求,我们这样约定:字段 _id 表示节点的主键,如果用户指定了该字段,则使用用户设置的值(当然,用户有责任保证它们不会重复);否则,由数据库自动为它分配一个主键。
如果主键是数据库生成的,事先无法预知它的值是什么,而边( edge )必须指定它所指向的节点,因此必须在主键生成后才能添加。由于这个原因,在动态生成主键的情况下,数据库的初始化会略微复杂一些。还是先写一个测试:
为支持此功能,我们在数据库中添加一个内部字段 _next_id 用于生成主键,并让 add_node 方法返回新生成的主键:
接下来,再确认一下边是否可以正常访问:
运行测试,一切正常。这个步骤很轻松地完成了,不过两个测试( DbModelTest 和 PrimaryKeyTest )出现了一些重复代码,比如 get_item 。我们可以把这些公用代码提取出来。由于 get_item 内部调用了 TestCase.assertXXX 等方法,看起来应该使用继承,但从 TestCase 派生基类容易引起一些潜在的问题,所以我转而使用另一个技巧 Mixin :
实现数据库模型之后,接下来就要考虑如何查询它了。
在设计查询时要考虑几个问题。对于图的访问来说,几乎总是由某个节点(或符合条件的某一类节点)开始,从与它相邻的边跳转到其他节点,依次类推。所以链式调用对查询来说是一种很自然的风格。举例来说,要知道 Tom 的孙子养了几只猫,可以使用类似这样的查询:
可以想象,以上每个方法都应该返回符合条件的节点集合。这种实现是很直观的,不过存在一个潜在的问题:很多时候用户只需要一小部分结果,如果它总是不计代价地给我们一个巨大的集合,会造成极大的浪费。比如以下查询:
为了避免不必要的浪费,我们需要另外一种机制,也就是通常所称的“懒式查询”或“延迟查询”。它的基本思想是,当我们调用查询方法时,它只是把查询条件记录下来,而并不立即返回结果,直到明确调用某些方法时才真正去查询数据库。
如果读者比较熟悉流行的 Python ORM,比如 SqlAlchemy 或者 Django ORM 的话,会知道它们几乎都是懒式查询的,要调用 list(result) 或者 result[0:10] 这样的方法才能得到具体的查询结果。
在 Dagoba 中把触发查询的方法定义为 run 。也就是说,以下查询执行到 run 时才真正去查找数据:
和懒式查询( Lazy Query )相对应的,直接返回结果的方法一般称作主动查询( Eager Query )。主动查询和懒式查询的内在查找逻辑基本上是相同的,区别只在于触发机制不同。由于主动查询实现起来更加简单,出错也更容易排查,因此我们先从主动查询开始实现。
还是从测试开始。前面测试所用的简单数据库数据太少,难以满足查询要求,所以这一步先来创建一个更复杂的数据模型:
此关系的复杂之处之一在于反向关联:如果 A 是 B 的哥哥,那么 B 就是 A 的弟弟/妹妹,为了查询到他们彼此之间的关系,正向关联和反向关联都需要存在,因此在初始化数据库时需要定义的边数量会很多。
当然,父子之间也存在反向关联的问题,为了让问题稍微简化一些,我们目前只需要向下(子孙辈)查找,可以稍微减少一些关联数量。
因此,我们定义数据模型如下。为了减少重复工作,我们通过 _backward 字段定义反向关联,而数据库内部为了查询方便,需要把它维护成两条边:
然后,测试一个最简单的查询,比如查找某人的所有孙辈:
这里 outcome/income 分别表示从某个节点出发、或到达它的节点集合。在原作者的代码中把上述方法称为 out/in 。当然这样看起来更加简洁,可惜的是 in 在 Python 中是个关键字,无法作为函数名。我也考虑过加个下划线比如 out_.in_ 这种形式,但看起来也有点怪异,权衡之后还是使用了稍微啰嗦一点的名称。
现在我们可以开始定义查询接口了。在前面已经说过,我们计划分别实现两种查询,包括主动查询( Eager Query )以及延迟查询( Lazy Query )。
它们的内在查询逻辑是相通的,看起来似乎可以使用继承。不过遵循 YAGNI 原则,目前先不这样做,而是只定义两个新类,在满足测试的基础上不断扩展。以后我们会看到,与继承相比,把共同的逻辑放到数据库本身其实是更为合理的。
接下来实现访问节点的方法。由于 EagerQuery 调用查询方法会立即返回结果,我们把结果记录在 _result 内部字段中。虽然 node 方法只返回单个结果,但考虑到其他查询方法几乎都是返回集合,为统一起见,让它也返回集合,这样可以避免同时支持集合与单结果的分支处理,让代码更加简洁、不容易出错。此外,如果查询对象不存在的话,我们只返回空集合,并不视为一个错误。
查询输入/输出节点的方法实现类似这样:
查找节点的核心逻辑在数据库本身定义:
以上使用了内部定义的一些辅助查询方法。用类似的逻辑再定义 income ,它们的实现都很简单,读者可以直接参考源码,此处不再赘述。
在此步骤的最后,我们再实现一个优化。当多次调用查询方法后,结果可能会返回重复的数据,很多时候这是不必要的。就像关系数据库通常支持 unique/distinct 一样,我们也希望 Dagoba 能够过滤重复的数据。
假设我们要查询某人所有孩子的祖父,显然不管有多少孩子,他们的祖父应该是同一个人。因此编写测试如下:
现在来实现 unique 。我们只要按照主键把重复数据去掉即可:
在上个步骤,初始化数据库指定了双向关联,但并未测试它们。因为我们还没有编写代码去支持它们,现在增加一个测试,它应该是失败的:
运行测试,的确失败了。我们看看要如何支持它。回想一下,当从边查找节点时,使用的是以下方法:
这里也有一个潜在的问题:调用 self.edges 意味着遍历所有边,当数据库内容较多时,这是巨大的浪费。为了提高性能,我们可以把与节点相关的边记录在节点本身,这样要查找边只要看节点本身即可。在初始化时定义出入边的集合:
在添加边时,我们要同时把它们对应的关系同时更新到节点,此外还要维护反向关联。这涉及对字典内容的部分复制,先编写一个辅助方法:
然后,将添加边的实现修改如下:
这里的代码同时添加正向关联和反向关联。有的朋友可能会注意到代码略有重复,是的,但是重复仅出现在该函数内部,本着“三则重构”的原则,暂时不去提取代码。
实现之后,前面的测试就可以正常通过了。
在这个步骤中,我们来实现延迟查询( Lazy Query )。
延迟查询的要求是,当调用查询方法时并不立即执行,而是推迟到调用特定方法,比如 run 时才执行整个查询,返回结果。
延迟查询的实现要比主动查询复杂一些。为了实现延迟查询,查询方法的实现不能直接返回结果,而是记录要执行的动作以及传入的参数,到调用 run 时再依次执行前面记录下来的内容。
如果你去看作者的实现,会发现他是用一个数据结构记录执行操作和参数,此外还有一部分逻辑用来分派对每种结构要执行的动作。这样当然是可行的,但数据处理和分派部分的实现会比较复杂,也容易出错。
本文的实现则选择了另外一种不同的方法:使用 Python 的内部函数机制,把一连串查询变换成一组函数,每个函数取上个函数的执行结果作为输入,最后一个函数的输出就是整个查询的结果。由于内部函数同时也是闭包,尽管每个查询的参数形式各不相同,但是它们都可以被闭包“捕获”而成为内部变量,所以这些内部函数可以采用统一的形式,无需再针对每种查询设计额外的数据结构,因而执行过程得到了很大程度的简化。
首先还是来编写测试。 LazyQueryTest 和 EagerQueryTest 测试用例几乎是完全相同的(是的,两种查询只在于内部实现机制不同,它们的调用接口几乎是完全一致的)。
因此我们可以把 EagerQueryTest 的测试原样不变拷贝到 LazyQueryTest 中。当然拷贝粘贴不是个好注意,对于比较冗长而固定的初始化部分,我们可以把它提取出来作为两个测试共享的公共函数。读者可参考代码中的 step04_lazy_query/tests/test_lazy_query.py 部分。
程序把查询函数的串行执行称为管道( pipeline ),用一个变量来记录它:
然后依次实现各个调用接口。每种接口的实现都是类似的:用内部函数执行真正的查询逻辑,再把这个函数添加到 pipeline 调用链中。比如 node 的实现类似下面:
其他接口的实现也与此类似。最后, run 函数负责执行所有查询,返回最终结果;
完成上述实现后执行测试,确保我们的实现是正确的。
在前面我们说过,延迟查询与主动查询相比,最大的优势是对于许多查询可以按需要访问,不需要每个步骤都返回完整结果,从而提高性能,节约查询时间。比如说,对于下面的查询:
以上查询的意思是从孙辈中找到一个符合条件的节点即可。对该查询而言,主动查询会在调用 outcome('son') 时就遍历所有节点,哪怕最后一步只需要第一个结果。而延迟查询为了提高效率,应在找到符合条件的结果后立即停止。
目前我们尚未实现 take 方法。老规矩,先添加测试:
主动查询的 take 实现比较简单,我们只要从结果中返回前 n 条记录:
延迟查询的实现要复杂一些。为了避免不必要的查找,返回结果不应该是完整的列表( list ),而应该是个按需返回的可迭代对象,我们用内置函数 next 来依次返回前 n 个结果:
写完后运行测试,确保它们是正确的。
从外部接口看,主动查询和延迟查询几乎是完全相同的,所以用单纯的数据测试很难确认后者的效率一定比前者高,用访问时间来测试也并不可靠。为了测试效率,我们引入一个节点访问次数的概念,如果延迟查询效率更高的话,那么它应该比主动查询访问节点的次数更少。
为此,编写如下测试:
我们为 Dagoba 类添加一个成员来记录总的节点访问次数,以及两个辅助方法,分别用于获取和重置访问次数:
然后浏览代码,查找修改点。增加计数主要在从边查找节点的时候,因此修改部分如下:
此外还有 income/outcome 方法,修改都很简单,这里就不再列出。
实现后再次运行测试。测试通过,表明延迟查询确实在效率上优于主动查询。
不像关系数据库的结构那样固定,图的形式可以千变万化,查询机制也必须足够灵活。从原理上讲,所有查询无非是从某个节点出发按照特定方向搜索,因此用 node/income/outcome 这三个方法几乎可以组合出任意所需的查询。
但对于复杂查询,写出的代码有时会显得较为琐碎和冗长,对于特定领域来说,往往存在更为简洁的名称,例如:母亲的兄弟可简称为舅舅。对于这些场景,如果能够类似 DSL (领域特定语言)那样允许用户根据专业要求自行扩展,从而简化查询,方便阅读,无疑会更为友好。
如果读者去看原作者的实现,会发现他是用一种特殊语法 addAlias 来定义自己想要的查询,调用方法时再进行查询以确定要执行的内容,其接口和内部实现都是相当复杂的。
而我希望有更简单的方法来实现这一点。所幸 Python 是一种高度动态的语言,允许在运行时向类中增加新的成员,因此做到这一点可能比预想的还要简单。
为了验证这一点,编写测试如下:
无需 Dagoba 的实现做任何改动,测试就可以通过了!其实我们要做的就是动态添加一个自定义的成员函数,按照 Python 对象机制的要求,成员函数的第一个成员应该是名为 self 的参数,但这里已经是在 UnitTest 的内部,为了和测试类本身的 self 相区分,新函数的参数增加了一个下划线。
此外,函数应返回其所属的对象,这是为了链式调用所要求的。我们看到,动态语言的灵活性使得添加新语法变得非常简单。
到此,一个初具规模的图数据库就形成了。
和原文相比,本文还缺少一些内容,比如如何将数据库序列化到磁盘。不过相信读者都看到了,我们的数据库内部结构基本上是简单的原生数据结构(列表+字典),因此序列化无论用 pickle 或是 JSON 之类方法都应该是相当简单的。有兴趣的读者可以自行完成它们。
我们的图数据库实现为了提高查询性能,在节点内部存储了边的指针(或者说引用)。这样做的好处是,无论数据库有多大,从一个节点到相邻节点的访问是常数时间,因此数据访问的效率非常高。
但一个潜在的问题是,如果数据库规模非常大,已经无法整个放在内存中,或者出于安全性等原因要实现分布式访问的话,那么指针就无法使用了,必须要考虑其他机制来解决这个问题。分布式数据库无论采用何种数据模型都是一个棘手的问题,在本文中我们没有涉及。有兴趣的读者也可以考虑 500lines 系列中关于分布式和集群算法的其他一些文章。
本文的实现和系列中其他数据库类似,采用 Python 作为实现语言,而原作者使用的是 JavaScript ,这应该和作者的背景有关。我相信对于大多数开发者来说, Python 的对象机制比 JavaScript 基于原型的语法应该是更容易阅读和理解的。
当然,原作者的版本比本文版本在实现上其实是更为完善的,灵活性也更好。如果想要更为优雅的实现,我们可以考虑使用 Python 元编程,那样会更接近于作者的实现,但也会让程序的复杂性大为增加。如果读者有兴趣,不妨对照着去读读原作者的版本。
7. 最受大家推崇的 Python 书籍有哪些
严正提醒! 想提升学习效率,请务必先找准基准线,提高自己对学习材料的品位。
要知道,这个时代,获取信息的路径虽短,获取优质知识的隐性成本却很高。选错学习的“姿势”,白花钱不说,流失了宝贵时间和学习热情才坑!
选一本 有专业人士背书 、 久经读者考验 的技术教程,你便找到了这个领域的基准线。以此来构建自己的知识体系,相信我,绝对能少走很多弯路。
那么,哪些Python学习书称得上是“基准”担当呢?不妨继续往下看:
文末有惊喜
文末有惊喜
GitHub上有一位叫皮埃尔·德·沃尔夫(Pierre de Wulf)的童鞋,通过以下方法,检索到了25本网上引用最多的 Python 书籍。
一起看看都有哪些经典 Python 书吧~
希望这些经典的 Python 书籍能够让题主的 Python 学习之路更高效,更踏实!
作者: [美] Mark Lutz
——内容简介——
这本书全面、深入地介绍了 Python 语言,不管你是编程新手还是 Python 初学者,它将帮助你快速实现使用 Python 编写高质量,且易于与其他语言和工具集成的代码。本书每一章都是关于Python语言独立的内容,并且带有练习和测试,简单易学,适合入门。
作者:[美]David Beazley, Brian K. Jones
——内容简介——
这本独特的“食谱”介绍了 Python 语言应用在各个领域中的使用技巧和方法,其主题涵盖了数据结构和算法,字符串和文本,迭代器和生成器,数据编码与处理,模块和包,网络和Web编程,并发,实用脚本和系统管理,测试、调试以及异常,C语言扩展等等内容。
每个“配方”均包含可立即在项目中使用的代码示例,以及Python应用中常见的问题和通用的解决方案。非常适合具有一定编程基础的Python程序员阅读。
Python Cookbook(第3版)中文版
作者: [巴西] Luciano Ramalho
——内容简介——
Python的简单性可以使你快速提高生产力,但这通常意味着你没有使用它所提供的一切。
本书致力于帮助Python开发人员挖掘这门语言及相关程序库的优秀特性,避免重复劳动,同时写出简洁、流畅、易读、易维护,并且具有地道Python风格的代码。本书尤其深入探讨了Python语言的 高级用法 ,涵盖数据结构、Python风格的对象、并行与并发,以及元编程等不同的方面。通过本书,Python程序员将全面学习如何精通Python 3。
作者: [美] Eric Matthes
——内容简介——
本书是一本针对所有层次的 Python 读者而作的 Python 入门书。
全书分两部分:第一部分介绍用Python 编程所必须了解的 基本概念 ,包括matplotlib、NumPy 和Pygal 等强大的Python 库和工具介绍,以及列表、字典、if 语句、类、文件与异常、代码测试等内容;第二部分将理论付诸 实践 ,讲解如何开发三个项目,包括简单的 Python 2D 游戏 开发,如何利用数据生成交互式的信息图,以及创建和定制简单的 Web 应用,并帮读者解决常见编程问题和困惑。
作者:Paul Barry
——内容简介——
你是否想学习 Python 而不用费心地看手册?
本书通过一种独特的超越语法手册的方式来帮助你学习Python。你将能够快速掌握 Python 的基础知识,然后扩展到持久化、异常处理、Web开发、SQLite、数据处理和Google应用引擎中去。你也将学会如何为 Android 编写移动应用,这要感谢Python带给你的强大能力。本书融合了完备的学习经验,它将帮助你快速成为一名真正的 Python 程序员。
作者: [美]Albert Sweigart
——内容简介——
如果你花了数小时重命名文件或更新了数百个电子表格单元格,你就会知道像这样的任务多么繁琐。 但是,如果可以让你的计算机为你做这些事情呢?可能只用几分钟吧。
本书是一本面向实践的Python编程实用指南。你将学习 Python 的基础知识,并 探索 用 Python 丰富的模块库来执行任务,例如从网站上抓取数据,阅读PDF和Word文档以及自动执行单击和键入任务等。
通过阅读本书,读者将学会利用强大的 Python 语言和工具,并且会体会到 Python 编程的快乐。
作者: [美] Zed A.Shaw
——内容简介——
本书是一本 Python 入门书籍。作者 Zed Shaw 完善了这个堪称世上最好的 Python 学习系统。只要跟着学习,你就会和迄今为止数十万 Zed 教过的初学者一样获得成功。
这本书以习题的方式引导读者一步一步学习编程,从简单的打印一直讲到完整项目的实现,让初学者从基础的编程技术入手,最终体验到软件开发的基本过程。你将学会怎样阅读、编写、思考代码,以及如何用专业程序员的技巧来找出并修正错误。
作者:Wes McKinney
——内容简介——
本书由 Python pandas 项目创始人 Wes McKinney 亲笔撰写,详细介绍利用 Python 进行操作、处理、清洗和规整数据等方面的具体细节和基本要点。虽然“数据分析”是本书的标题,但重点是Python编程,库和工具,而不是数据分析方法。这是数据分析所需的 Python 编程。
作者: [美]布雷特·斯拉特金(Brett Slatkin)
——内容简介——
用 Python 编写程序是相当容易的,所以这门语言非常流行。但若想掌握 Python 所特有的优势、魅力和表达能力,则相当困难,而且语言中还有很多隐藏的陷阱,容易令开发者犯错。本书可以帮你掌握真正的 Pythonic 编程方式,令你能够完全发挥出 Python 语言的强大功能,并写出健壮而高效的代码。
作者: [美] 艾伦 B. 唐尼
——内容简介——
本书以培养读者 以计算机科学家一样的思维方式 来理解Python语言编程。贯穿全书的主体是如何思考、设计,以及开发的方法。
全书详细介绍了 Python 编程语言的方方面面,从基本的编程概念到函数,递归,数据结构和面向对象编程等等。每一章都配有术语表和练习题,方便读者巩固所学的知识和技巧。此外,作者针对每章所专注的语言特性,或者相关的开发问题,总结了调试的方方面面。
作者:[德]达恩·巴德尔(Dan Bader)
——内容简介——
这本书将通过简单的示例和分步说明来介绍 Python 的最佳实践以及 Python 代码的强大魅力。借助本书,你将专注于真正重要的实践技能,在 Python 的标准库中发现“隐藏的金子”,距离精通 Python 更近一步!
作者:[美]Sebastian Raschka, Vahid Mirjalili
——内容简介——
本书是关于使用 Python 进行机器学习和深度学习的综合指南。 它既是分步教程,又是构建机器学习系统时不断翻阅的参考书。
本书包含清晰的注释,可视化效果和工作示例,深入介绍了基本上所有的机器学习技术。 虽然有些书只教您遵循说明,但在本书中,作者讲授了机器学习的原理,这使你可以自己构建模型和应用程序。
作者: Mark Pilgrim
——内容简介——
有很多 python 开发人员需要学习将代码移植到python 3,而本书是为他们提供最新版本 python 介绍的最佳书籍。它独特的风格是先提供大量代码然后将其分解,非常适合希望快速了解新版本语言的现有开发人员。
作者: [美] David M.Beazley
——内容简介——
本书是 Python 编程语言的权威参考指南,内容涉及核心 Python 语言和 Python 库的最重要部分,内容简洁扼要、可读性强。书中还包括了一些没有在 Python 官方文档或其他资料中出现过的一些高级主题的详细信息。
这一版在内容上进行了全面更新,介绍了 Python 2.6 和 Python 3 新引入的编程语言特性和库模块,同时还分析了Python程序员面临的如下难题:是应继续使用现有的 Python 代码,还是应制定计划将其移植到Python 3?
作者: 卢茨 (Mark Lutz)
——内容简介——
当掌握 Python 的基础知识后,你要如何使用 Python?本书为这门语言的主要应用领域提供了深度教程,譬如系统管理、GUI 和 Web,并 探索 了其在数据库、网络、前端脚本、文本处理等方面的应用。你将学到清晰、简洁明了的语法和编程技巧,并伴随大量的示例来展示正确的用法和惯例。
作者: [德]安德里亚斯·穆勒,[美]莎拉·吉多
——内容简介——
本书是机器学习入门书,以 Python 语言介绍。
书中重点讨论机器学习算法的实践而不是背后的数学,全面涵盖在实践中实现机器学习算法的所有重要内容,帮助读者使用 Python 和 scikit-learn 库一步一步构建一个有效的机器学习应用。
本书将向所有对机器学习技术感兴趣的初学者展示,自己动手构建机器学习解决方案并非难事!
作者: [美] Alex Martelli,Anna Ravenscroft,Steve Holden
——内容简介——
本书适合具有一定 Python 编程经验或者有其他语言编程基础的程序员阅读,它涵盖了广泛的应用领域,包括 Web和网络编程,XML处理,数据库交互以及高速数值计算。该实用手册的第三版提供了对该语言的快速参考(包括Python 3.5、2.7和3.6的亮点)。
作者: [美] Al Sweigart
——内容简介——
本书通过编写一个个小巧、有趣的 游戏 来教授Python编程,并且采用直接展示 游戏 的源代码并通过实例来解释编程的原理的方式。首先构建 猜数字 和 Tic Tac Toe 这样的经典 游戏 ,然后逐步开发更高级的 游戏 ,在此过程中,你将学习关键的编程和数学概念,这将帮助你在轻松有趣的过程中,掌握 Python 游戏 编程的基本技能。
全书共21章,12个 游戏 程序和示例贯穿其中,介绍了Python基础知识、数据类型、函数、流程控制、程序调试、流程图设计、字符串操作、列表和字典、笛卡尔坐标系、密码学基础、 游戏 AI模拟、动画图形、碰撞检测、声音和图像等方方面面的程序设计知识。
作者:Mark Lutz
——内容简介——
对于新的Python 3.4 和 2.7 而言,这款便捷的袖珍指南是完美的实战快速参考书。你将会从中学习有关Python类型和语句,特殊方法名,内建函数与异常,常用的标准库模块及其他卓越的Python工具。
作者:[美] Kenneth Reitz,Tanya Schlusser
——内容简介——
本书是 Python 用户的一本网络式学习指南,本书由 Python 社区的大神 Kenneth Reitz 发起并组织编写,由社区数百名开发者集体奉献。其特色在于,近乎完整地总结了在 Python 编程中会用到的各种实践技巧和经验,涵盖众多主流的应用场景,并告诉你如何提高效率、避免踩坑、编写高质量的代码。
本书着重于可重用的代码,重于设计理念,将读者引向已存在的优秀资源,适合有一定Python基础的人员学习,帮助你迅速从小工修炼成专家,编写出高质量的代码!
========
以上python书籍我已整理电子版本
获取方式:
转发+私信“1”获取,
私信方式:第一步:点击头像
旁边有个私信按钮,点击回复“1”即可!
8. 学习python编程小白要看哪些书
1、《父与子编程:与小卡特一起学python》
这本书是零基础看的书籍,对于很多刚接触编程的小白来说,对于很多名词是很难理解的,本书把知识点拆的很细,更难得的是那些难理解的技术名词,这本书都是用场景对话、动画的形式展现,让初学者更容易学会;看了它,你就会发现python是多么容易。
2、《python cookbook》
本书介绍了应用在各个领域的技巧和方法,涵盖了很多高级主题:元编程、网络、web编程、实用脚本、系统管理、C语言拓展等。本书还覆盖了许多python日常开发中的问题以及解决方案,在实际开发中的编程技巧,告诉你python如何工作并且为什么工作。
3、《python高手之路》
众所周知,项目经验以及底层知识拓展对于一个程序员的进阶来说是非常重要的!《python高手之路》它是从一个项目的第一步开始,从整个项目的架构设计、对模块和库的处理来构建一个完整的项目。
9. python是面向什么的高级语言
面相对象、解释型。
Python支持多种编程范型,包括函数式、指令式、反射式、结构化和面向对象编程。它拥有动态类型系统和垃圾回收功能,能够自动管理内存使用,并且其本身拥有一个巨大而广泛的标准库。它的语言结构以及面向对象的方法旨在帮助程序员为小型的和大型的项目编写清晰的、合乎逻辑的代码。
吉多·范罗苏姆于1980年代后期开始研发Python,它是作为ABC语言的后继者,也可以视之为使用叫做的M-表达式的一种传统中缀表示法的LISP方言。
吉多·范罗苏姆于1991年首次发布 Python 0.9.0。Python2.0于2000 年发布并引入了新功能。Python3.0于2008年发布,是该语言的主要修订版,并非完全向后兼容。 Python2于2020年随2.7.18版停止使用。
Python的设计哲学强调代码的可读性和简洁的语法,尤其是使用空格缩进划分代码块。相比于C或Java,Python让开发者能够用更少的代码表达想法。
Python解释器本身几乎可以在所有的操作系统中运行。Python的官方解释器CPython是用C语言编写的,它是一个由社群驱动的自由软件,目前由Python软件基金会管理。
特征
Python是多范型编程语言。它完全支持结构化编程和面向对象编程,还有很多特征支持函数式编程和元编程比如元对象协议(元类和魔术方法)。
通过扩展还可以支持很多范型,包括面向切面编程、契约式设计和逻辑编程。
Python使用动态类型,在内存管理上采用引用计数和环检测相结合的垃圾收集器。它的特征还有动态名字解析(后期绑定),即在程序执行期间绑定方法和变量的名字。
Python对遵循LISP传统的函数式编程提供了有限的支持,它提供了map、filter和rece函数;列表推导式、字典、集合和生成器表达式。
10. python3.5与python3.10区别
Python3.5和Python3.10的主要区别在于新增的功能和更新。Python3.5新增了一些新的特性,如元编程、新的语法元素、正则表达式的压缩模式、高级索引,以及新的类型和模块,而Python3.10新增了新的语言功能,如模块声明及标志、 Python类型检查、更好的编程模型、改进的调试功能等。