前言
好久没写博客了,忙成狗的日子差不多过去了,现在回归本性,继续写。这次主要写的是python的学习,之前也有学习过,但是还是没有写点什么,学C/C++、JAVA等语言时根本没有写博客这个习惯,也感觉留下了些许遗憾,以后有想法了看看能不能把坑填上。
关于为什么要刷官网,这个主要是学了这么久的编程得到的一个心得吧:官方文档 > 大部头国外巨著 > 其他。官网的资料肯定是最齐全的,同时最新的特性也会在官网首先出现,因此有“最新”、“最全"的特点,就像学C/C++总往cppreference跑,学java总看api,学前端总莫名其妙跑到w3c一样。因此,得出了一个结论:官网之路必不可少。正好python官网也给了tutorial和reference,因此不如刷上一遍。这就是这么久的一点感悟吧。
正题
首先看下官网前四章的目录,得出一个总体的思路,得知道路是怎么走的,不能糊里糊涂的就上路,这不是老司机的做法(你根本不是老司机!刀子图自行脑补)。
- 1. Whetting Your Appetite
- 2. Using the Python Interpreter
- 3. An Informal Introduction to Python
- 4. More Control Flow Tools
可以看到前三章几乎都在说一件事情:介绍python,这在各种教科书上都是套路。
第一章
看第一章的名字:Whetting Your Appitite(开胃菜),从whet这个词来看,翻译插件直接说是“打磨”,顿时感觉不对,去百度翻译一看,原来是“刺激”的意思,然后把整个词连在一起,大概就是“刺激你的食欲”的意思,所以叫“开胃菜”。扯远了,继续,点进去看第一章,发现就是在说一件事情,python是干嘛的,为什么选择python,然后官网给了这么几个答案:
1. python简单易用,而且功能强大,能够用寥寥几行代码就做到你用C/C++/JAVA要几十行才能做到的事情。
2. python是解释型语言,不需要编译和连接,可以节约时间。
3. python允许代码模块化重用,可以战在巨人肩膀上,也可以减少代码重复与冗余。
4. python代码更具有可读性,原因是使用了缩进代表逻辑,强大的数据类型,变量无需申明直接定义使用
5. python具有可扩展性:可以通过编写C代码自定义模块、函数,给python添加新的功能。
这里总结一下,python可以看作是一种高度简洁、数据类型强大、集合了C/C++/JAVA等编程语言与Shell/Perl等脚本语言的长处而发展出来的一种语言,simple可以说是python的一大主题,simple意味着花费较少的精力与时间,同时能够快速获得可观的产出,强大的数据类型、模块、缩进的限制、解释型语言以及后面的一些切片、lambda等函数式编程的特性都在支持这一点。另一方面,simple意味着能够与人的思维相近,python代码能够尽可能一眼看出是在做什么,弱类型、风格规范以及前面提到的那些特性都在努力的做到这点。因此,python可以说成为一种脚本语言、编程语言的衔接体与过渡体,python有个别名叫“胶水语言”,说的也是这么个东西。当然,要做到这些是要付出代价的,代价就是性能上的,python按照解释器来分有cpython、jython、ironpython、pypy这些,其实说的就是解释器是用什么语言写的,为了解决性能上的问题,5提供了自定义的接口,如果觉得官方库或者外部库的东西不好,可以自己写,以达到性能的优化,这个在C++的STL中也有体现,譬如list的排序和vector的排序使用不同的算法。
这些大概就是对python的一个套路般的介绍,不过这个东西在学习中要逐渐领悟,学过一个东西了得对它有个定性的描述,知道干什么的、什么时候用、怎么做到的。
第二章
第二章介绍了python的解释器,python的解释器就叫python。这里实际上是以描述python这个命令的方式来介绍python解释器的。这里也回归一下之前的几篇博客的方式,来说一说python命令。
python [options] [param0] [param1] ...
1.缺省进入交互模式,这个是一直到第三章的内容。
2.options中有许多可选参数,如-m, -c等,这里主要说-m 和 -c。
-m module 调用某个模块,譬如说常见的python -m pip install xxx,就是调用的pip这个模块,此时如果通过sys.argv获取得到的是模块名
-c command 相当于将语句从python交互模式中移动到参数部分,省去了exit()之类的操作,此时如果通过sys.argc获得的是-c这个参数
3. 第一个参数往往是你要解释的.py文件名,为sys.argv[0],后面的参数为传递给.py脚本的内容,类似于shell中的$1、$2等
然后接着说交互模式(Interactive Mode)。
交互模式,大概就是你每次输入一个语句块,python立即解释这个语句块(如果是一个变量名,默认打印),通过这个可以很方便的熟悉一些函数、特性,不必每次在源文件中更改以后python xxx。这里由于写一块解释一块,所以屏幕会刷得很快,也不会保存,因此不适宜真正在里面写代码,有些逻辑上的语句块为了防止被解释打断可以用;分隔开写在一行。另外一个技巧就是help函数在这里可以大放异彩,首先import模块名然后help(模块),可以查看模块的文档信息,十分有用。
然后就是一个编码的说明,python源文件默认使用ascii编码,因此如果需要指定特定的编码,通过#coding:xxx即可,如果要写的文艺一些、友好一些,可以写成这样:
第三章
第三章则是介绍了几乎每个python的教程或者资料都会提到的把交互模式当科学计算器使用,的确这是个很不错的主意,尤其是无视数据范围的数值类型(python 2.4以后int溢出自动转long)赞到不行。这的确可以是python引以为豪的一个东西。因此放在官网上也十分恰当。
然后就是一些数据类型的基本介绍,这里顺带把python的几种基本数据类型整理一下。
1. Number: int, long, float, complex
int:Plain Integer, 一般是用C中的long来实现,平台相关,至少32位,不过由于python中的溢出自动转long设定使得对int数据范围的探讨失去了意义。
long: have unlimited precision,即无限长的整数,定义时用l/L literal来表示,如a = 3l或者 a = 3L。
float: 浮点数,一般是用C中的double来实现,数据范围十分庞大,所以几乎可以视为无限大。
complex:复数,可以用a = 1 + 2j 来定义一个复数,也可以使用a = complex('1+2j')来定义,注意字符串中间不能出现空格,通过a.imag和a.real可以获得虚部和实部(都为float类型)。
2. bool
python中的bool其实是int的一个subtype,与其他语言的布尔类型没什么差别,也可以强制转换为int,True为1,False为0。值的一提的是python的逻辑判断方式是与C类似的,以下情况与False等价:
1. None(对象为空)
2. False (废话)
3. 为0的数值,如0、0.0、0L、0l、0 + 0j
4. 为空的sequence, 如[]、''、()
5. 为空的mapping, 如{}
6. instances of user-defined classes, if the class defines a __nonzero__() or __len__() method, when that method returns the integer zero or bool value False.
即某个对象的__nonzero__()或者__len__()方法返回为整数0或者布尔False时
其他类型与True等价,可以看出,这是对C布尔特性的一种继承与发展。
2. string / unicode
本来这是两个不同的类型,但是这两个关系太过密切,因此有必要列在一起来谈。
string可以由单引号、双引号、三引号来定义,用三引号会包含一切特殊字符,所以适合于类似于html中quote的字符串(即源代码中写什么样子就是什么样子)的定义,实际上会被解释为单引号、双引号嵌套的形式,譬如说s = """[Tab]"[Tab]""",print s得到的是'\t"\t'。另一方面,字符串默认与源文件中的编码一致,因此如果字符串中出现了中文,前面的#coding不可缺。这里还有一个raw-string的概念,给string加上r literal,例如r"\\",得到的就是"\\\\",即转义被关闭,很适合在正则匹配时使用。
unicode作为一个单独的type列出来,可见其意义。字符串的本地化本身是件十分头疼的事情,而unicode被称为“万国码”,覆盖了各种语言,因此作为一个中间的桥梁进行各种编码之间的桥梁再好不过了,只要给string加上u literal即可转换为unicode,unicode与string之间的转换通过encode和decode来进行。
stirng与unicode都是一旦创建后即不可更改的(immutable)。
3. list / tuple
list有点类似于的数组,不过由于python弱类型的特点,这是一个十分强大的"列表“,具体表现在:长度可以自由改变,数据类型可以不同。通过a = []或者 a = list()来定义。
tuple则翻译为“元组“,在离散数学中有这样的概念,在C/C++/JAVA编程中经常会发现由于要将几个基本数据类型组合在一起而不得不自定义一个新的类型(注:C++11中引入了tuple类,),十分麻烦,而tuple的出现就是为了解决这样的问题,将问题变得简单起来,因此对tuple可以理解为将几个基本类型捆绑在一起,譬如说position,要两个浮点数表示x坐标、y坐标,直接使用(x, y)就可以完成这样的捆绑,通过t = X, Y, Z或者t = (X, Y, Z)来定义。tuple则是在实现unpacking的一个载体。
4. set / frozenset
set为集合,元素特点为一系列的hashable的对象,特点是元素不能出现重复,通过将其他类型转换为set可以实现漂亮的去重操作,由于setting type是unordered类型因此不支持index访问。set与frozenset的主要区别为set为可更改的(mutable),而frozenset为不可更改的(immutable)。这里再说一下hashable,一个immutable的一般都是hashable的,而mutable的都不是hashable的,这也就意味着可以将一个tuple、frozenset添加到set中,而其他如list,dict,set则不行。
5. dict
dict则是对应着C++/JAVA中的映射map,表示一个对应关系,由基本的key:value映射单元构成,其中key必须是hashable的,通过d = {}或者d = dict()来定义,通过keys()、values()、items()来获取key、value、(key, value)。
嗯,常用大致就是以上这些类型了,这里只是对其进行了基本的描述,关于后面的collections类型还要进行进一步深究。
然后还有一些运算符的内容,比较基础,相对于C没有做出多大改变,这里不做多说,或者在以后自定义运算时再提也未尝不可。
第四章
第四章首先是说的控制流程,控制流程相对与C而言,除了elif、else稍作更改,其他几乎没有变化。elif是else if的省略代替方式,符合python的brief的宗旨。而用在循环中else表示跳出循环执行的操作,这个目前没有发现有多么重大的意义。然后说一下pass关键字,这个关键字主要用来使空语句块合法而产生,表示什么都不做,在定义interface时十分有用。
然后就是函数的部分了,首先定义函数使用def关键字,def f(arg)来定义一个函数,通过return来返回值,如果没有return语句或者没有经过return语句其实也有返回值,为None,据官网的评价,这是一个十分“无聊”的返回值,也许吧,hhh。
函数的第二行可以添加一些“Document Strings",由lieteral string构成,以官网的例子来看:
其中对于Document Strings,第一行应当是对定义一个object的目的的简短的描述,同时,这一行不应该是对object的名称或者类型的重复说明,第一个字母应当大写并且应当以.结尾。如果有多行,那么第二行应该是空行,接下来的行应当是一段或者多段对于这个object的调用规则以及副作用等的描述,python解释器不会处理literal的缩进,因此提取文档的工具需要自行去除缩进。可以看到,Document Strings主要是起注释以及生成文档的作用。
接下来看一些函数的advanced的用法,首先是带默认值,这个继承自c++,每个函数的右边部分参数可以带有默认值,这个特性很不错,可以减少代码重复。现在有点诧异为什么java就不继承这个特性呢?
然后是keyword argument,keyword argument是函数参数的一种形式,什么是keyword argument呢?看这个例子:
即通过形参名=值的形式进行传参,同时,这里还涉及到一个叫unpacking的操作,所谓unpacking,即将一个容器中的东西释放出来,成为许多个单独的单元,这些单元可以用来传递参数、赋值操作,对于dict,通过**进行unpack,对于iteratble的对象,如list、tuple,通过*进行unpack,譬如说
这里将args unpack了以后,成为了单独的3和6,于是range(*[3, 6])等价于range(3 ,6),现在再来看这个: 这里实际上就是另一种unpacking操作。另外一种则是普通的positional argument,通过参数的位置来传参,即第一个参数复制给第一个形参……
接下来是任意参数的函数定义,这实际上是一种unpacking的逆过程,依然是一个例子:
实际上,这里的argument是tuple类型,而keywords是dict类型,因此,这里是将多余的参数按照tuple和dict进行了分配。通过这个途径,我们可以很方便的实现任意参数函数的构建。最后,来谈一谈lambda表达式,lambda表达式是个很有用的利器,lambda表达式本身十分简洁:lambda param: return_alue,通过这样来定义一个匿名函数,对于一些需要传入函数的方法,如sorted()我们可以使用lambda表达式快速构建出这样的函数来(lambda表达式类型为function),减少了不必要的代码以及“命名浪费”。这个特性在C++14中得到引进,在java8中也得到了引进。
讲到这里,有必要说明一下,在python中,函数本身就是一种object,不信试试isinstance(lambda a:-a, object)因此,在上文中是对object的描述,同样适用于对函数的描述。
总结
好久没有写博客了,重操旧业,感觉十分不错,今后也要继续写下去。哟西~