python 进阶知识

Outline

  • 对象-object
  • 自省-dir(), type(), id()
  • 可变对象、不可变对象 | 赋值
  • lambda表达式
  • Map, Filter, Reduce
  • collections
  • 枚举(enumerate)
  • 装饰器
  • with语句
  • zip()
  • sorted()
  • 编码问题

 

对象-object

在python中,万物皆对象(Everything in python is an object)

 

自省-dir(), type(), id()

dir(object)  返回由该对象(object)所用的属性和方法组成的一个列表。

type(object) 返回该对象的类型。

id(object) 返回一个跟这个对象对应的独一无二的id,生命周期没有重叠的两个对象可能拥有相同的id。

 

可变对象、不可变对象 | 赋值

在python中有一类sequences型的数据类型,包括string, unicode, tuple, list, byte array。

这些数据类型的共同特点就是都可以像list那样用索引访问元素a[i],可以进行切片a[i:j]。

但是sequences中分为两类:

一类不可变(immutable): string, unicode, tuple;

一类可变(mutable): list, byte array。

 

另外数值(number)型数据(int,float等)是不可变类型。set,dic是可变类型。

 

看一个例子:

 

y的值没有随x的改变而变化,而b的值却跟着a变了;而且x和y最后的id不同,a和b的id却一样。

这是因为x、y是不可变类型和a、b是可变类型。

 

说x是不可变类型有点奇怪,它明明从“1”变为了“2”,这就涉及到变量(variable)和赋值(assign)的概念。

Python中的变量是没有类型的,但Python对象是区分类型的:Python的所有变量其实都是指向内存中的对象的一个指针,都是值的引用,而其类型是跟着对象走的。总结来说:在Python中,类型是属于对象的,而不是变量, 变量和对象是分离的,对象是内存中储存数据的实体,变量则是指向对象的指针。在《Learning Python》一书中有一个观点:变量无类型,对象有类型,大概也是说的这个意思。下面是一张说明变量的图:

python_fuzhi

对于不可变类型的变量,如果要更改变量,则会创建一个新值,把变量绑定到新值上,而旧值如果没有被引用就等待垃圾回收。另外,不可变的类型可以计算hash值,作为字典的key。可变类型数据对对象操作的时候,不需要再在其他地方申请内存,只需要在此对象后面连续申请(+/-)即可,也就是它的内存地址会保持不变,但区域会变长或者变短。

回到那个例子,结合变量、赋值和类型是否可变就能明白它是什么原因了。

明白了这些,那么下面这个例子也就清楚了:

所以我们在函数传参时不应使用可变的默认参数,以免产生一些意想不到的错误。

另外,浅拷贝和深拷贝的问题也与这些内容有关,可以自行了解。

 

lambda表达式

lambda表达式是一行函数。

它们在其他语言中也被称为匿名函数。如果你不想在程序中对一个函数使用两次,你也许会想用lambda表达式,它们和普通的函数完全一样。

形式:“lambda 参数:操作(参数)”

 

Map, Filter, Reduce

map

Map会将一个函数映射到一个输入列表的所有元素上。这是它的规范:

大多数时候,我们要把列表中所有元素一个个地传递给一个函数,并收集输出。比方说:

Map可以让我们用一种简单而漂亮得多的方式来实现。就是这样:

大多数时候,我们使用匿名函数(lambdas)来配合map。

filter

顾名思义,filter过滤列表中的元素,并且返回一个由所有符合要求的元素所构成的列表,符合要求即函数映射到该元素时返回值为True. 这里是一个简短的例子:

这个filter类似于一个for循环,但它是一个内置函数,并且更快。

reduce

当需要对一个列表进行一些计算并返回结果时,Reduce 是个非常有用的函数。举个例子,当你需要计算一个整数列表的乘积时。

通常在 python 中你可能会使用基本的 for 循环来完成这个任务。

现在我们来试试 reduce:

 

 

collections

摘录自:http://www.liaoxuefeng.com

collections是Python内建的一个集合模块,提供了许多有用的集合类。

namedtuple

我们知道tuple可以表示不变集合,例如,一个点的二维坐标就可以表示成:

但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。

定义一个class又小题大做了,这时,namedtuple就派上了用场:

namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。

这样一来,我们用namedtuple可以很方便地定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便。

可以验证创建的Point对象是tuple的一种子类:

类似的,如果要用坐标和半径表示一个圆,也可以用namedtuple定义:

deque

使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。

deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:

deque除了实现list的append()pop()外,还支持appendleft()popleft(),这样就可以非常高效地往头部添加或删除元素。

defaultdict

使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict

注意默认值是调用函数返回的,而函数在创建defaultdict对象时传入。

除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的。

OrderedDict

使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。

如果要保持Key的顺序,可以用OrderedDict

注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:

OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key:

Counter

Counter是一个简单的计数器,例如,统计字符出现的个数:

Counter实际上也是dict的一个子类,上面的结果可以看出,字符'g''m''r'各出现了两次,其他字符各出现了一次。

 枚举(enumerate)

摘录自: https://eastlakeside.gitbooks.io/interpy-zh/content/Enumerate/Enumerate.html

枚举(enumerate)是Python内置函数。它的用处很难在简单的一行中说明,但是大多数的新人,甚至一些高级程序员都没有意识到它。

它允许我们遍历数据并自动计数,

下面是一个例子:

不只如此,enumerate也接受一些可选参数,这使它更有用。

上面这个可选参数允许我们定制从哪个数字开始枚举。
你还可以用来创建包含索引的元组列表, 例如:

 

装饰器

摘录自:http://www.liaoxuefeng.com

由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

函数对象有一个__name__属性,可以拿到函数的名字:

现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。

本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:

 

观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:

调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:

@log放到now()函数的定义处,相当于执行了语句:

由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

with语句

摘录自: http://blog.csdn.net/suwei19870312/article/details/23258495/
有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。

如果不用with语句,代码如下:

这里有两个问题。一是可能忘记关闭文件句柄;二是文件读取数据发生异常,没有进行任何处理。下面是处理异常的加强版本:

虽然这段代码运行良好,但是太冗长了。这时候就是with一展身手的时候了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。下面是with版本的代码:

zip()

定义:zip([seql, …])接受一系列可迭代对象作为参数,将对象中对应的元素打包成一个个tuple(元组),然后返回由这些tuples组成的list(列表)。若传入参数的长度不等,则返回list的长度和参数中长度最短的对象相同。

 

 

sorted()

sorted()可以对list进行排序,sorted()函数也是一个高阶函数,它还可以接收一个比较函数来实现自定义的排序。 也可以用lambda表达式来指定关键字(key)来排序。

编码问题

编码类型: https://docs.python.org/3/library/codecs.html#standard-encodings
查看和修改默认编码:sys.getdefaultencoding()  ,sys.setdefaultencoding(‘utf8’)
编码和解码: str.encode(),str.decode()
unicode和string的区别:略

 


References:

http://book.pythontips.com/en/latest/mutation.html

https://eastlakeside.gitbooks.io/interpy-zh/content/Enumerate/Enumerate.html

http://www.liaoxuefeng.com

https://docs.python.org/2/library/functions.html

http://blog.csdn.net/suwei19870312/article/details/23258495/

https://my.oschina.net/leejun2005/blog/145911

http://xianglong.me/article/python-variable-quote-copy-and-scope/

1 条评论

  • cxh 2016年11月9日 回复

    good

发表评论

电子邮件地址不会被公开。 必填项已用*标注