一、 构造方法、特性、迭代器
1.构造函数
本节介绍Python中的2个重要方法 一个是__init__ 一个是__del__ 。
__init__是用来定义类的构造函数的。
__del__,也称作析构函数(destructor),这个方法在对象被销毁(作为垃圾被收集)前被调用。鉴于你无法知道准确的调用时间,建议尽可能不要使用__del__。
构造方法的定义非常简单:下边是2个例子和测试方法:
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
在继承一个类时,也可以重写父类的构造方法,重写构造函数时,必须调用超类(继承的类)的构造函数,否则可能无法正确地初始化对象。请看下边的问题代码:
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为如下方式:
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程序都可作为模块导入。下面写一个最简单的程序,并作为模块导入。
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进来使用,可以如下操作。
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模块:
2.os模块:
3. fileinput模块:
模块fileinput让你能够轻松地迭代一系列文本文件中的所有行。
下边一个例程使用fileinput模块,给文件增加行号。在给fileinput.input设置参数inplace=True要十分小心,因为会直接修改原来的文件。
关于print的格式化打印的参数,可以参考这篇文章:https://www.runoob.com/python/att-string-format.html
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模块的方法来实现堆数据结构的应用。
最后,介绍双端队列。在模块collections中的deque对象。相比列表,其优势是可以在首部添加和删除对象。
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模块:
6.random模块: