一、 构造方法、特性、迭代器

1.构造函数

本节介绍Python中的2个重要方法 一个是__init__ 一个是__del__  。

 __init__是用来定义类的构造函数的。

__del__,也称作析构函数(destructor),这个方法在对象被销毁(作为垃圾被收集)前被调用。鉴于你无法知道准确的调用时间,建议尽可能不要使用__del__。

构造方法的定义非常简单:下边是2个例子和测试方法:

python 重写__eq__ python中重写构造方法_Python

python 重写__eq__ python中重写构造方法_python 重写__eq___02

1 class Rectangle(object):
 2     """
 3         无参构造函数的类实例
 4     """
 5     def __init__(self):
 6         self.height = 12
 7         self.width = 20
 8 
 9 
10 class Rectangle1(object):
11     def __init__(self, height, width):
12         self.height = height
13         self.width = width
14 
15 
16 if __name__ == '__main__':
17     rec1 = Rectangle()
18     print rec1.height
19     rec2 = Rectangle1(16, 21)
20     print rec2.width

View Code

 在继承一个类时,也可以重写父类的构造方法,重写构造函数时,必须调用超类(继承的类)的构造函数,否则可能无法正确地初始化对象。请看下边的问题代码:

python 重写__eq__ python中重写构造方法_Python

python 重写__eq__ python中重写构造方法_python 重写__eq___02

1 class Bird(object):
 2     def __init__(self):
 3         self.hungry = True
 4 
 5     def eat(self):
 6         if self.hungry:
 7             print "Eat A lot!"
 8         else:
 9             print "Already good!"
10 
11 
12 class lark(Bird):
13     def __init__(self):
14         self.sing = "bowl"
15 
16     def sing(self):
17         print "bird sing:" + " bowl!"
18 
19 
20 if __name__ == '__main__':
21     la = lark()
22     bd = Bird()
23     la.eat()

View Code

lark类继承了Bird类,但是lark重写了构造方法,并设置了自己的属性未初始化父类的属性,而导致了错误。 

有两种方法解决上边的问题:调用未关联的超类构造函数,以及使用函数super。可以修改类lark为如下方式:

python 重写__eq__ python中重写构造方法_Python

python 重写__eq__ python中重写构造方法_python 重写__eq___02

1 class lark(Bird):
 2     def __init__(self):
 3         # 调用未关联的超类构造函数
 4         Bird.__init__(self)
 5         # 使用super()方法
 6         # super(lark, self)
 7         self.sound = "bowl"
 8 
 9     def sing(self):
10         print self.sound

View Code

对实例调用方法时,方法的参数self将自动关联到实例,这也称为关联方法
如果你通过类调用方法,例如:Bird.__init__(self) ,就没有实例与其相关联。在这种情况下,可以随便设置参数self,这样的方法称为未关联方法

通过将这个未关联方法的self参数设置为当前实例,将使用超类的构造函数来初始化SongBird对象。

super()方法的使用经测试,在2.7版本还存在一些问题。

 

2.构造函数

 

二、 模块

本部分介绍如何创建自己的module并引用,并列举常见常用的一些模块和方法。

1.自建module

任何Python程序都可作为模块导入。下面写一个最简单的程序,并作为模块导入。

python 重写__eq__ python中重写构造方法_Python

python 重写__eq__ python中重写构造方法_python 重写__eq___02

1 #!/bin/bash
 2 
 3 print "Module Testing!"
 4 
 5 
 6 def fib(n):
 7   fibs = [0, 1]
 8   for i in range(n-2):
 9     fibs.append(fibs[i] + fibs[i+1])
10   return fibs
11 
12 
13 if __name__ == '__main__':
14   p = fib(7)
15   print p

moduleTest.py

假如把该文件放到文件目录:/Users/natty/Develop/Python/modules  下。

那么,想将该module import进来使用,可以如下操作。

python 重写__eq__ python中重写构造方法_Python

python 重写__eq__ python中重写构造方法_python 重写__eq___02

1 >>> import sys
2 >>> sys.path.append('/Users/natty/Develop/Python/modules')
3 >>> import moduleTest
4 Module Testing!
5 >>> import moduleTest

View Code

上边的执行结果,第2次import时,不再打印结果,原因是:模块并不是用来执行操作(如打印文本)的,而是用于定义变量、函数、类等。鉴于定义只需做一次,因此导入模块多次和导入一次的效果相同。

 上边使用sys.path.append的方法太过笨拙,一般不使用这种方式。一般使用下边2种方式:

1.将模块放在正确的位置;2.告诉解释器到哪里去查找。

 首先,考虑下将py文件放在哪里直接识别成模块,打印变量sys.path,下边例子使用pprint打印(唯一区别是按格式打印):

>>> import sys,pprint
>>> pprint.pprint(sys.path)
['',
 '/Users/natty/anaconda2/lib/python27.zip',
 '/Users/natty/anaconda2/lib/python2.7',
 '/Users/natty/anaconda2/lib/python2.7/plat-darwin',
 '/Users/natty/anaconda2/lib/python2.7/plat-mac',
 '/Users/natty/anaconda2/lib/python2.7/plat-mac/lib-scriptpackages',
 '/Users/natty/anaconda2/lib/python2.7/lib-tk',
 '/Users/natty/anaconda2/lib/python2.7/lib-old',
 '/Users/natty/anaconda2/lib/python2.7/lib-dynload',
 '/Users/natty/anaconda2/lib/python2.7/site-packages',
 '/Users/natty/anaconda2/lib/python2.7/site-packages/aeosa',
 '/Users/natty/anaconda2/lib/python2.7/site-packages/pyspark-2.4.0-py2.7.egg',
 '/Users/natty/anaconda2/lib/python2.7/site-packages/py4j-0.10.7-py2.7.egg',
 '/Users/natty/anaconda2/lib/python2.7/site-packages']

 上边目录中site-packages是专门来放模块文件的目录,把文件放在这个目录可以直接import。

例如:cp ~/Develop/Python/modules/moduleTest.py /Users/natty/anaconda2/lib/python2.7/site-packages

之后moduleTest.py可以直接引入了,下边的代码可以使用:

>>> import moduleTest
Module Testing!
>>> p = moduleTest.fib(12)
>>> print p
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

 如果不想把很多模块都放入该目录,而是希望把模块文件统一放到另一个目录中,可以 在PYTHONPATH环境变量中包含模块所在的目录。

假如,我定义将所有模块文件放入目录:/Users/natty/Develop/Python/module_path 。

可以直接修改环境变量。 

修改文件: ~/.bash_profile   增加下边环境变量:

export PYTHONPATH=${PYTHONPATH}:/Users/natty/Develop/Python/module_path

 

另环境变量立刻生效:source ~/.bash_profile

 

check下环境变量值:echo $PYTHONPATH

 

至此,已经可以在该文件夹下增加py文件来作为module来import了。

2.包

python中,包实际就是模块所在的目录,为了让Python将该目录作为包来对待,它必须包含一个名为__init__.py的文件。

下面实验中,在上边配置的module_path目录新建一个包constans(为了表明constans目录是个包,新建了__init__.py文件),并在该包新建一个hello.py模块,执行结果如下:

$ pwd
/Users/natty/Develop/Python/module_path
$ ls -R
constans	moduleTest.py	moduleTest.pyc

./constans:
__init__.py	__init__.pyc	hello.py	hello.pyc

#python实验结果,模块已经可以引入。
>>> import constans.hello
hello world!

  

3.学习新模块的使用

本小节内容介绍了如何快速熟悉一个新的module,主要包括下面的一些工具:
dir() :介绍模块的所有特性(一些名字以下划线开头,表明其不是为在模块外部使用而准备的)。
__all__变量: 定义了模块的公共接口,我们经常使用 from copy import * ,这其中的*引入的就是__all__变量的所有内容。
help()
__doc__ :关于函数/属性的文档介绍,help其实打印的也是这个。
__file__: 列出该模块源代码的文件位置。

>>> import copy
>>> dir(copy)
['Error', 'PyStringMap', '_EmptyClass', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_copy_dispatch', '_copy_immutable', '_copy_inst', '_copy_with_constructor', '_copy_with_copy_method', '_deepcopy_atomic', '_deepcopy_dict', '_deepcopy_dispatch', '_deepcopy_inst', '_deepcopy_list', '_deepcopy_method', '_deepcopy_tuple', '_keep_alive', '_reconstruct', '_test', 'copy', 'deepcopy', 'dispatch_table', 'error', 'name', 't', 'weakref']
>>> copy.__all__
['Error', 'copy', 'deepcopy']
>>> help(copy)
>>> copy.copy.__doc__
"Shallow copy operation on arbitrary Python objects.\n\n    See the module's __doc__ string for more info.\n    "
>>> print copy.__file__
/Users/natty/anaconda2/lib/python2.7/copy.pyc

 

4.常用模块和方法

这一节介绍常用的一些模块及其中的方法属性。

其中sys、os模块比较常用,可以自己实验下,不再赘述。下面只列举常用方法的介绍:

1.sys模块:

python 重写__eq__ python中重写构造方法_Python_11

2.os模块:

python 重写__eq__ python中重写构造方法_python_12

3. fileinput模块:

模块fileinput让你能够轻松地迭代一系列文本文件中的所有行。

python 重写__eq__ python中重写构造方法_python 重写__eq___13

 下边一个例程使用fileinput模块,给文件增加行号。在给fileinput.input设置参数inplace=True要十分小心,因为会直接修改原来的文件。

关于print的格式化打印的参数,可以参考这篇文章:https://www.runoob.com/python/att-string-format.html 

python 重写__eq__ python中重写构造方法_Python

python 重写__eq__ python中重写构造方法_python 重写__eq___02

1 # encoding: utf-8
 2 # 20190830 fileinput模块读取多个文件
 3 import fileinput
 4 
 5 
 6 if __name__ == '__main__':
 7     for line in fileinput.input(inplace=True):
 8         line = line.rstrip()
 9         line_no = fileinput.lineno()
10         # {0}表示第一个元素, {1}表示第二个元素, {2}表示第三个元素,以此类推。。
11         print "{line:<40s}  #{line_no}".format(line=line, line_no=line_no)

file_numbers.py

 4.常用集合:

首先,介绍Set,

目前,可直接创建集合,而无需导入模块sets。使用set()来创建Set时,需要传参一个列表。

需要明确的是,Set是可变的,但是集合只能包含不可变的值,这时,我们直接合并2个集合时就会出错。可以使用frozenset将一个集合转变为不可变的,之后再合并(add)两个集合。

 其次,介绍堆,

堆是优先队列的一种,它的最大优势是能快速找到最大/小值,效率比max/min函数要高的多。python没有堆类型,需要引用heapq模块的方法来实现堆数据结构的应用。

python 重写__eq__ python中重写构造方法_Python_16

最后,介绍双端队列。在模块collections中的deque对象。相比列表,其优势是可以在首部添加和删除对象。

python 重写__eq__ python中重写构造方法_Python

python 重写__eq__ python中重写构造方法_python 重写__eq___02

1 # encoding: utf-8
 2 # 20190830 演示Set、堆、双端队列 这些常见的数据结构
 3 from random import shuffle
 4 from heapq import *
 5 from collections import deque
 6 
 7 def set_demo():
 8     a = set([1, 12, 18, 1, 23, 12, 9])
 9     b = set([2, 12, 145, 17, 22, 17])
10     print "Set a:{0} Set b:{1}".format(a, b)
11     #print a.add(b)    #集合是可变类型,但只能包含不可变值
12     a.add(frozenset(b))
13     print list(a)
14 
15 
16 def heap_demo():
17     b = range(10)
18     shuffle(range(10))
19     print b
20     heap = []
21     for bi in b:
22         heappush(heap, bi)
23     print heap
24     a = heappop(heap)
25     print a
26 
27 
28 if __name__ == '__main__':
29     # set_demo()
30     heap_demo()

collection_demo.py

5. time模块:

python 重写__eq__ python中重写构造方法_python_19

 6.random模块: