用生命谱写代码的赞歌

0%

Python 相关

Python学习

进了一家新公司,后端代码是用 Python 写的,就自己带着学习了一下 Python 语言,总结一些用法,不定时更新……

Python2 和 Python3分别安装pip

  • python -m pip install
  • python3 -m pip install

Python虚拟环境virtualenv

安装

pip install virtualenv

使用

选择一个目录,比如我们把这个工程放在 /path/to/project/spider/ 目录下,我们在这个目录下建立一个虚拟环境

virtualenv /path/to/project/spider

虚拟环境就建立好了。此时可以看到,在这个目录下面会有三个目录被建立:

  • bin
  • include
  • lib

激活虚拟环境

在上述目录中

  • bin 目录中包含一些在这个虚拟环境中可用的命令,以及开启虚拟环境的脚本 activate;
  • include 中包含虚拟环境中的头文件,包括 Python 的头文件;
  • lib 中就是一些依赖库啦~~

source /path/to/project/spider/bin/activate

接下来就可以使用

安装工程需要的 requests

pip install requests

退出虚拟环境

deactivate

补充一句,如果想要删除虚拟环境,只要把这个目录下的 bin、include 和 lib 三个目录删掉就好了。

Python简单操作

if __name__ == "__main__"

  • 表示当.py文件作为主程序时,调用相应的函数

如果.py文件被其他文件引入,不执行对应的函数

Python判断数据类型与提示用户输入

判断数据类型

type(a)type(a) is strisinstance(a, int)

1
2
3
4
temp = '18'
print(type(temp))
print(type(temp) is str)
print(isinstance(temp, int))

结果如下:

1
2
3
<class 'str'>
True
False

提示用户输入

提示用户输入: input('请输入密码:'),用户输入内容均为字符串

1
2
3
4
>>> a = input('请输入密码:')
请输入密码:222222
>>> print('你的密码是%s'%a)
你的密码是222222

运算符

//: 取整(地板除)

% : 取余

and: 相当于js的&&

or: 相当于js的||

not: 表示取非

列表操作

列表推导式[x for x in args]

1
2
3
4
>>> y = [1,3,5,7,9]
>>> a = [x for x in y]
>>> a
[1, 3, 5, 7, 9]
  • append
    • 直接在list列表后面追加
    • 只能追加一个元素
      1
      2
      member = ['舞蹈', '陆远', '剑无尘']
      member.append('云峰') # ['舞蹈', '陆远', '剑无尘', '云峰']
  • extend
    • 追加list列表
      1
      member.extend(['沧海', '傲雪']) # ['舞蹈', '陆远', '剑无尘', '云峰', '沧海', '傲雪']
  • insert
    • 在列表指定索引位置添加
      1
      member.insert(1, '瞻园') # ['舞蹈', '瞻园', '陆远', '剑无尘', '云峰', '沧海', '傲雪']
  • remove
    • 删除元素(知道元素名称就行),找不到报错
      1
      member.remove('剑无尘') # ['舞蹈', '瞻园', '陆远', '云峰', '沧海', '傲雪']
  • del
    • del(member[1])等价于del member[1]
    • del member删除整个列表
  • pop
    • 不加参数表示从后面删除一个元素
    • 参数表示从指定索引位置删除元素
      1
      member.pop(2) # 删除陆远
  • 列表切片(分片)
    • 使用冒号获取列表指定位置元素拷贝,原列表不变
      1
      2
      3
      4
      member[1:3] # ['瞻园', '云峰']
      member[:3] # ['舞蹈', '瞻园', '云峰']
      member[1:] # ['瞻园', '云峰', '沧海', '傲雪']
      member[:] # ['舞蹈', '瞻园', '云峰', '沧海', '傲雪']
  • 列表比较
    • 比较列表中的第一个元素,第一个赢了,整个列表就赢了
  • 列表相加
    • 只有数据类型相同才能相加
    • 原列表不变
      1
      2
      member + '比利' # 报错
      member + ['比利'] # ['舞蹈', '瞻园', '云峰', '沧海', '傲雪', '比利']
  • 列表翻倍
    • 原列表不变
    • member * 3
    • member *= 2
  • 成员操作符 in & not in
    • 适用于一元列表,二元列表里的元素需要list[n]
      1
      2
      '云峰' in member # True
      '陆云' not in member # True
  • 列表元素数目统计=>list.count('123')
  • 列表元素出现索引位置
    • list.index(xxx)=>表示从列表起始位置查找,显示第一次找到的索引
    • list.index(xxx, 3, 7)=>表示从指定位置开始查找
    • 找不到会报错
  • 列表排序
    • list.sort()=>从小到大排序
    • list.sort(reverse=True)=>从大到小排序
  • 列表翻转=>list.reverse()

元组操作

元组类似于列表,但是其内元素不可改变

  • 创建元组(逗号是关键)
    • tuple=(1, 3, 5, 7, 9)
    • tuple=()=>空元组
    • tuple=(1)=>整数1
    • tuple=1, || tuple=(1,)=>元组(1)
  • 元组的元素几乎不可以直接删除,可以像列表那样采用切片删除
  • 删除元组
    • del tuple
    • del(tuple)

字符串操作

  • 大写与小写–> 字符串方法参考网址
    • capitalize() & casefold()
  • center(width)=>字符串居中,使用空格填充至长度width的新字符串
  • count(sub[,start[,end]])=>返回sub在字符串里出现的次数
  • encode(encoding='utf-8', errors='strict')
  • endswith(sub[,start[,end]])
  • expandtabs([tabsize=8])=>将字符串中的tab符号(\t)转换为空格,默认8个空格
  • find(sub[,start[,end]])=>返回sub在字符串里的索引值,找不到返回-1
  • index(sub[,start[,end]])=>同find,找不到报异常
  • isalnum()
  • isalpha()
  • isdecimal()=>十进制
  • isdigital()=>数字
  • islower()
  • isnumeric()
  • isspace()
  • istitle()
  • isupper()
  • join(sub)=>以sub为分隔符插入到字符串中
  • split()=>找到空格就切
  • strip([chars])
  • swapcase()=>翻转大小写
  • translate(str.maketrans('a', 'b'))

格式化输出(字符串格式化符号%)

  • format –> 字符串格式化符号含义
    1
    2
    3
    4
    5
    6
    "{0} love {1}.{2}".format("I", "FishC", "com") # 'I love FishC.com'
    "{a} love {b}.{c}".format(a="I", b="FishC", c="com") # 'I love FishC.com'
    "{0} love {b}.{c}".format("I", b="FishC", c="com") # 'I love FishC.com'
    "{a} love {b}.{0}".format(a="I", b="FishC", "com") # 报错
    "{0:.1f}{1}".format(27.699, "GB") # '27.7GB' # 冒号后面表示格式化的格式
    "{{0}}".format("不打印") # '{0}'
  • %c (格式化字符及ASCII码)
    1
    >>> '%a %c %c'%(97, 98, 99) # '97 b c'
  • 打印整数(%d)和百分号(%%)
    1
    2
    >>> print("his score is %d%%"%24)
    his score is 24%
  • 打印字符串(%s)
    1
    2
    3
    >>> a = 'xiaoming'
    >>> print("his name is %s"%a)
    his name is xiaoming
  • 打印浮点数(%f)
    1
    2
    >>> print("his height is %f m"%1.83)
    his height is 1.830000 m
  • 打印浮点数,指定保留小数点位数(%.2f)
    1
    2
    >>> print("his height is %.2f m"%1.83)
    his height is 1.83 m
  • 指定占位符宽度
    1
    2
    >>> print("Name:%10s Age:%8d Height:%8.2f"%("Aviad",25,1.83))
    Name: Aviad Age: 25 Height: 1.83
  • 指定占位符宽度(左对齐)
    1
    2
    >>> print("Name:%-10s Age:%-8d Height:%-8.2f"%("Aviad", 25, 1.83))
    Name:Aviad Age:25 Height:1.83
  • 指定占位符(只能用0当占位符?),且字符串无法使用0占位
    1
    2
    >>> print ("Name:%-10s Age:%08d Height:%08.2f"%("Aviad",25,1.83))
    Name:Aviad Age:00000025 Height:00001.83
  • 科学计数法(保留小数点位数科学计数法)
    1
    2
    >>> format(0.0015,'.5e')
    '1.50000e-03'

列表、元组和字符串共同点(可统称为序列)

三者统称为序列,下面介绍几个内置函数:

  • list([iterable])=>把一个可迭代对象转化为列表
  • tuple([iterable])=>转化为元组
  • str(object)=>把obj对象转化为字符串
  • len() => 返回序列长度
  • max() => 返回序列或者参数集合中最大值,同理还有min()
  • sum(iterable[,start])
  • sorted()
  • reversed() => 返回一个迭代器对象,可使用list转化
  • enumerate() => 返回一个迭代器对象,可使用list转化
  • zip(a, b) => 将a与b中元素一一对应拼接为tuple类型,例如list(zip('123456789', '56789'))

字典(dict)

  • 类似于js的对象,设置本来不存在的键会自动创建
  • dict(mapping) –> a mapping object’s (key, value) pairs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    >>> dict1 = dict((('a', 1), ('b', 2), ('c', 3)))
    # dict接收一个参数,可以将映射转化为字典
    >>> dict1
    {'a': 1, 'b': 2, 'c': 3}
    >>> dict2 = dict((['d',4], ['e',5], ['f',6]))
    >>> dict2
    {'d': 4, 'e': 5, 'f': 6}
    # 以可迭代对象方式构造字典
    >>> dict3 = dict([['g',7],['h',8]])
    >>> dict3
    {'g': 7, 'h': 8}
    # 以函数的可变参数形式(键值对)构造字典
    >>> dict4 = dict(one = 'hello', two = 'man' , three = 'how are you')
    >>> dict4
    {'one': 'hello', 'two': 'man', 'three': 'how are you'}
    # 以映射函数方式构造字典
    >>> dict(zip(['one', 'two', 'three'], [1, 2, 3, 4]))
    {'one': 1, 'two': 2, 'three': 3}
  • json字符串转化为字典
    • eval() 或 exec()
      1
      2
      3
      4
      5
      6
      7
      8
      >>> user
      "{'name' : 'jim', 'sex' : 'male', 'age': 18}"
      >>> b=eval(user)
      >>> b
      {'age': 18, 'name': 'jim', 'sex': 'male'}
      >>> exec("c="+user)
      >>> c
      {'age': 18, 'name': 'jim', 'sex': 'male'}
    • json.loads() –> json字符串转python字典
    • json.dumps() –> python对象转json字符串

字典常用方法

  • fromkeys
  • keys/values/items
  • get
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# fromkeys(iterable, value=None)
>>> dict.fromkeys(('a','b','c'))
{'a': None, 'b': None, 'c': None}

>>> dict.fromkeys(('one','two','three'), 'school')
{'one': 'school', 'two': 'school', 'three': 'school'}

>>> dict1 = dict.fromkeys(range(10), '赞')
>>> dict1
{0: '赞', 1: '赞', 2: '赞', 3: '赞', 4: '赞', 5: '赞', 6: '赞', 7: '赞', 8: '赞', 9: '赞'}

# fromkeys修改字典会返回新的字典,不影响原有字典
>>> dict1.fromkeys((1, 3), '不攒')
{1: '不攒', 3: '不攒'}

>>> for key in dict1.keys():
... print(key)
>>> for value in dict1.values():
... print(value)
>>> for item in dict1.items():
... print(item)
...
(0, '赞')
(1, '赞')
(2, '赞')
(3, '赞')
(4, '赞')
(5, '赞')
(6, '赞')
(7, '赞')
(8, '赞')
(9, '赞')
>>> dict1[9]
'赞'
>>> dict1[10] # 报错keyError
>>> dict1.get(9)
'赞'
>>> print(dict1.get(10)) # 找不到索引是返回None
None
>>> dict1.get(10, '找不到') # 也可以自己设置'找不到'作为返回值
'找不到'
  • 清空字典 clear
  • 浅拷贝 copy
  • 弹出指定值 pop(key)
  • 弹出最后一个值 popitem
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    >>> dict1 = {'one': 1, 'two': 2, 'three': 3}
    >>> dict1.clear()
    >>> dict1
    {}

    # 浅拷贝内存地址发生了变化,a与c相同,指向同一内存地址,b不同于a和c
    >>> a = {'one': 1, 'two': 2, 'three': 3}
    >>> b = a.copy()
    >>> c = a
    >>> c
    {'one': 1, 'two': 2, 'three': 3}
    >>> b
    {'one': 1, 'two': 2, 'three': 3}
    >>> a
    {'one': 1, 'two': 2, 'three': 3}
    >>> id(a)
    4329539984
    >>> id(b)
    4329538328
    >>> id(c)

    # 修改c,a会跟着变化,b不变
    >>> c["four"] = 4
    >>> c
    {'one': 1, 'two': 2, 'three': 3, 'four': 4}
    >>> a
    {'one': 1, 'two': 2, 'three': 3, 'four': 4}
    >>> b
    {'one': 1, 'two': 2, 'three': 3}

    # 弹出指定值
    >>> a.pop('three')
    3
    >>> a
    {'one': 1, 'two': 2, 'four': 4}
    # 弹出最后一项
    >>> c.popitem()
    ('four', 4)
    >>> c
    {'one': 1, 'two': 2}
  • setdefault –> 设置默认值
  • update(dict) –> 更新字典值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> a
    {'one': 1, 'two': 2}
    >>> a.setdefault('小白', 6)
    >>> a
    {'one': 1, 'two': 2, '小白': 6}
    >>> c.setdefault('红豆')
    >>> c
    {'one': 1, 'two': 2, '小白': 6, '红豆': None}
    >>> a.update({'小白': '够'})
    >>> a
    {'one': 1, 'two': 2, '小白': '够', '红豆': None}

集合(set)

  • 集合内元素唯一,利用该性质可以给list(列表)去重
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 利用集合唯一性去重
    >>> num = [1,2,3,4,5,5,3,1,0]
    >>> new_num = list(set(num))
    >>> new_num
    [0, 1, 2, 3, 4, 5]

    # 普通方法去重
    >>> temp = []
    >>> for item in num:
    ... if item not in temp:
    ... temp.append(item)
    ...
    >>> temp
    [1, 2, 3, 4, 5, 0]
  • 集合类型内建方法–> 参考网址
    • add
    • remove(如果删除对象不存在,报错)
    • discard(删除对象不存在没事)
    • pop, clear
  • 不可变集合
    1
    2
    3
    4
    5
    6
    >>> alpha = {1, 3, 5, 7}
    >>> alpha.add(9)
    >>> alpha
    {1, 3, 5, 7, 9}
    >>> beta = frozenset({2, 4, 6, 8})
    >>> beta.add(10) # 报错,frozenset没有add方法

循环

for xx in aaa:: 遍历aaa

range([start,] stop[, step=1]): 内置函数,range[2,5]表示从2到5的整数,不包括5

1
list(range(5)) # [0, 1, 2, 3, 4]

Python导入模块与包

导入模块

  1. import 模块名
  2. form 模块名 import 函数名
  3. import 模块名 as 新名字

搜索路径

原始python包搜索路径如下:

1
2
3
4
5
6
>>> import sys
>>> sys.path
['', '/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python36.zip',
'/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6',
'/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload',
'/usr/local/lib/python3.6/site-packages']

搜索包的路径可以增加, 例如

1
sys.path.append('/usr/local/add')

导入包

.代表当前目录,..代表上一层目录,…代表上上层目录。

例如:在模块A.B.C中的代码:

1
2
3
from . import D     # 导入A.B.D
from .. import E # 导入A.E
from ..F import G # 导入A.F.G,.. 和 F是连着的,中间没有空格

Python内建函数(BIF: build in function)与模块

  • range(1, 10)
    • for i in range(1, 10):表示i从1循环到9, 不包括10
  • issubclass(B, A) –> B是否是A的子类 ==> 自身是自身的子类issubclass(B, B) –>True
    • 第二个参数可以接收元组
  • isinstance(B, A) –> B是否是A的实例对象
    • 第二个参数可以接收元组
  • hasattr(object, attr) –> 第二个参数用字符串
  • getattr(object, attr[, default]) –> 第三个参数可以设置不存在属性的默认值
  • setattr(object, attr[, value]) –> 设置属性
  • delattr(object, attr) –> 删除属性
  • property(getattr, setattr, delattr)
  • random模块
1
2
3
4
import random

for i in range(1, 50):
print(random.randint(1, 10), i) # 返回1, 10之间的随机整数, 包括1, 10
  • os模块
  • os.path模块
    • python路径操作模块
    • os.path.basename
    • os.path.dirname
  • pickle模块
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import pickle

    my_list = ['xyz', 123, 'bbc', ['hello', 'lady']]
    pkl_file = open('my_list.pkl', 'wb') # 以二进制方式打开文件
    pickle.dump(my_list, pkl_file) # 将数据转化为二进制存入
    pkl_file.close
    pkl_file = open('my_list.pkl', 'rb') # 以只读方式打开二进制文件
    my_list2 = pickle.load(pkl_file) # 将二进制文件转换为原始数据
    print(my_list2)

Python普通函数

函数返回值

如果python函数没有return语句,默认返回None对象
不要在函数中试图定义或修改全局变量的值,否则python会新建一个与全局变量名字相同的局部变量代替(屏蔽保护全局变量)
在函数内部使用global关键字修饰需要修改的全局变量,调用函数,全局变量发生改变

1
2
3
4
5
6
7
8
9
10
11
>>> def display():
... global count
... count = 99
... print(count)
...
>>> print(count)
5
>>> display()
99
>>> print(count)
99
  • lambda表达式

lambda x : 2 * x + 1相当于定义了函数,冒号前面是参数,后面是返回值

1
2
3
4
5
6
7
8
>>> def ds(x):
... return 2 * x + 1
...
>>> ds(5)
11
>>> g = lambda x : 2 * x + 1
>>> g(5)
11
  • 默认参数
    1
    2
    3
    4
    5
    6
    7
    >>> def eat(a="apple", b="banana"):
    ... print("正在吃" + a, b)
    ...
    >>> eat("pear", "peach")
    正在吃pear peach
    >>> eat()
    正在吃apple banana
  • 关键字参数
    1
    2
    3
    4
    5
    6
    7
    >>> def write(name, address):
    ... print(name + "在" + address)
    ...
    >>> write("小明", "杭州")
    小明在杭州
    >>> write(address = "武汉", name = "小萌")
    小萌在武汉
  • 可变参数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    >>> def test(*params):
    ... print("参数长度是:", len(params))
    ... print("第三个参数是:", params[2])
    ...
    >>> test("今天", "明天", "后天", "大后天", "大大后天")
    参数长度是: 5
    第三个参数是: 后天
    # 可变参数后面如果有其他函数,建议设置成默认函数,否则需要使用关键字参数获得
    >>> def hello(*params, extra="萨瓦迪卡"):
    ... print("参数长度是:", len(params))
    ... print("其他参数是:", extra)
    ...
    >>> hello("hi", "hello", "你好")
    参数长度是: 3
    其他参数是: 萨瓦迪
    >>> def hello(*params, extra):
    ... print("参数长度是:", len(params))
    ... print("其他参数是:", extra)
    ...
    >>> hello("hi", "hello", "你好", "萨瓦迪卡", extra="阿妮哈赛呦")
    参数长度是: 4
    其他参数是: 阿妮哈赛呦
  • 内嵌函数和闭包
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> def f1():
    ... x = 5
    ... def f2():
    ... x *= x
    ... return x
    ... return f2()
    ...
    >>> f1() # 报错,局部变量x未定义
    # UnboundLocalError: local variable 'x' referenced before assignment
    解决办法1(Python2.0):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> def f1():
    ... x = [5]
    ... def f2():
    ... x[0] *= x[0]
    ... return x[0]
    ... return f2()
    ...
    >>> f1()
    25
    解决方法2(Python3.0) –> nonlocal关键字:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> def f1():
    ... x = 5
    ... def f2():
    ... nonlocal x
    ... x *= x
    ... return x
    ... return f2()
    ...
    >>> f1()
    25
  • 两个牛逼的BIF(内置函数 build in function)
    • filter(function or None, iterable) –> filter object
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      # 第一个参数为None,过滤结果为false的值
      >>> list(filter(None, (1, 0, False, True)))
      [1, True]
      # 第一个参数为函数,过滤返回结果为false的数
      >>> def odd(x):
      ... return x % 2
      ...
      >>> temp = range(10)
      >>> show = filter(odd, temp)
      >>> list(show)
      [1, 3, 5, 7, 9]
      # 上述函数简便写法
      >>> list(filter(lambda x : x % 2, range(10)))
      [1, 3, 5, 7, 9]
    • map(func, *iterables) –> map object
      1
      2
      >>> list(map(lambda x : x * 2, range(10)))
      [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
  • 递归调用
    • 设置递归深度
      1
      2
      import sys
      sys.setrecursionlimit(100000)
    • 阶乘的非递归版本实现:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      def factorial(n):
      result = n
      for i in range(1, n):
      result *= i
      return result

      num = int(input("请输入一个正整数:"))
      result = factorial(num)
      print("%d 的阶乘是: %d" % (num, result))
    • 阶乘的递归实现
      1
      2
      3
      4
      5
      6
      7
      8
      9
      def factorial(n):
      if n == 1:
      return 1
      else:
      return n * factorial(n - 1)

      num = int(input("请输入一个正整数:"))
      result = factorial(num)
      print("%d 的阶乘是: %d" % (num, result))
    • 斐波那契数列非递归实现:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      def fibonacci(n):
      n1 = 1
      n2 = 1
      n3 = 1

      if n < 1:
      print("输入有误!")
      return -1

      while (n - 2) > 0:
      n3 = n2 + n1
      n1 = n2
      n2 = n3
      n -= 1

      return n3

      result = fibonacci(20)
      if result != -1:
      print("总共有%d对兔子诞生~" % result)
    • 斐波那契数列递归实现:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      def fibonacci(n):
      if n < 1:
      print("输入有误!")
      return -1

      if n == 1 or n == 2:
      return 1
      else:
      return fibonacci(n - 1) + fibonacci(n - 2)

      result = fibonacci(20)
      if result != -1:
      print("总共有%d对兔子诞生~" % result)
    • 汉诺塔递归实现
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      def hanoi(n, x, y, z):
      if n < 1:
      return -1
      if n == 1:
      print(x, '-->', z)
      else:
      hanoi(n - 1, x, z, y) # 将前n-1个盘子从x移动到y上
      print(x, '-->', z) # 将最底下的最后一个盘子从x移动到z上
      hanoi(n - 1, y, x, z)# 将y上的n-1个盘子移动到z上

      n = int(input("请输入汉诺塔的层数:"))
      hanoi(n, 'X', 'Y', 'Z')

Python文件读写

  • 读取文件–> 参考网址
    • 打开模式
      • 'r' –> 只读方式(默认)
      • 'w' –> 写入方式打开,会覆盖已存在的文件(用于写入文件)
      • 'a' –> 写入模式打开文件,如果文件存在,则在末尾追加
        1
        2
        3
        >>> f = open('test.txt') # 以只读方式打开文件
        >>> list(f) # 打开的文件流可以序列化
        ['hello my name is liming\n', 'where are you from\n', 'i am from america\n']
  • 文件对象方法
    • f.close() –> 关闭文件流
    • f.read([size=-1]) –> 从文件流中读取size个字符, 当未给定size或给定负值, 读取剩余的所有字符
    • f.readline([size=-1]) –> 读取一行(遇到\nEOF结束), 如果定义了size,有可能返回的只是一行的一部分
    • f.readlines([size=-1]) –> 把文件每一行作为一个list的一个成员,并返回这个list, 它的内部是通过循环调用readline()来实现的. 如果提供size参数,size是表示读取内容的总长,也就是说可能只读到文件的一部分
    • f.write(str) –> 将字符串写入文件, write()并不会在str后加上一个换行符
    • f.writelines(seq) –> 向文件中写入字符串序列seq(list, tuple, str), seq应该是一个返回字符串的可迭代对象. 这个函数也只是忠实地写入,不会在每行后面加上任何东西
    • f.seek(offset, from) –> 在文件中移动文件指针, 从from(0代表文件起始位置, 1代表当前位置, 2代表文件末尾)偏移offset个字节
    • f.tell() –> 返回当前在文件中的位置
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      f = open('test.txt')
      for line in f:
      print(line) # 直接读取文件流

      f.seek(10, 0) # 定位文件指针
      print(f) # 打印File文本对象

      # lines = f.readline(100)
      # print(lines)

      lines = list(f) # 将文件流(iterable)转化为list
      print(lines)
      count = 0
      for line in lines:
      count += 1
      print('第%d行:' % count, line)

      f.close() # 关闭文件流
  • 一个Python文件读写任务
    • 文本文件molest.txt(调戏), 任务是将其中小甲鱼和小客服的三次对话分别读出来, 每次对话分为boy*.txt和girl*.txt
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      小客服: 小甲鱼, 今天有客服问你有没有女朋友?
      小甲鱼: 咦??
      小客服: 我跟她说了你已经有女朋友了!
      小甲鱼: ......
      ==========
      小客服: 小甲鱼, 有个好评很好笑哈.
      小甲鱼: 哦?
      小客服: "有了小甲鱼, 妈妈再也不用担心我的学习了~"
      小甲鱼: 哈哈哈.
      ==========
      小客服: 小甲鱼, 今天一个会员想找你.
      小甲鱼: 哦? 什么事?
      小客服: 他说他妈喊他回家吃饭.
      小甲鱼: 滚!
    • 代码如下
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      def save_file(boy, girl, count):
      file_name_boy = 'boy_%d.txt' % count
      file_name_girl = 'girl_%d.txt' % count

      boy_file = open(file_name_boy, 'w')
      girl_file = open(file_name_girl, 'w')

      boy_file.writelines(boy)
      girl_file.writelines(girl)

      # 以'====='分割对话
      def split_file(file_name):
      f = open(file_name)

      boy = []
      girl = []
      count = 1

      for each_line in f:
      if each_line[:5] != '=====':
      (role, line_say) = each_line.split(':', 1) # 每一行按照冒号分割说话人和说话内容, 一次即可
      if role == '小甲鱼':
      boy.append(line_say.lstrip())
      if role == '小客服':
      girl.append(line_say.lstrip())
      else:
      save_file(boy, girl, count) # 存储说话内容

      boy = []
      girl = []
      count += 1

      save_file(boy, girl, count)

      f.close()

      split_file('molest.txt') # 调用分割文件函数

Python异常处理

  • try ---> except --> except --> finally
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
try:
# int('abc')
f = open('boy_1.txt', 'w')
print(f.write('好冷啊'))
print(f.read())
sum = 1 + '1'
f.close()
except OSError as reason:
print('文件出错啦T_T\n错误原因是:' + str(reason), '==' * 10, type(reason))
except TypeError as reason:
print('类型出错啦T_T\n错误原因是:' + str(reason), '==' * 10, type(reason))
else:
print('没有异常') # else可以和try except连用, 没异常时起作用
finally:
f.close()
print('这里收个尾')
# f.close() # 写在这里也可行
print('来来来,见面分一半')
raise ZeroDivisionError('除数不能为0') # 直接手写产生异常

结果如下:

1
2
3
4
5
6
7
8
9
3
文件出错啦T_T
错误原因是:not readable ==================== <class 'io.UnsupportedOperation'>
这里收个尾
来来来,见面分一半
Traceback (most recent call last):
File "/Users/hushiking/hu/python/littleTurtle/exception.py", line 17, in <module>
raise ZeroDivisionError('除数不能为0') # 直接手写产生异常
ZeroDivisionError: 除数不能为0

with用法

  • 用在文件读写中, 不用手动关闭文件流, with自动搞定. 例如:
1
2
3
4
5
6
7
8
9
try:
with open('data.txt', 'w') as f:
f.write('with处理文件读写不用手动关闭文件流')
for each_line in f:
print(each_line)
except OSError as reason:
print('出错啦' + str(reason))
# finally:
# f.close() # 不需要了
  • with可用于异常追踪
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Sample:
def __enter__(self):
return self

def __exit__(self, type, value, trace):
print("type:", type)
print("value:", value)
print("trace:", trace)

def do_something(self):
bar = 1 / 0
return bar + 10


with Sample() as sample:
sample.do_something() # 可答应出来异常的类型,值和追踪位置

Python面向对象

类似js的构造方法

  • __init__(self, name, ...)
  • __init__()函数必须返回None, 否则报错
1
2
3
4
5
6
7
8
9
class Person:
def __init__(self, name):
self.name = name
def kick(self):
print("我叫%s, shit, 谁踢我..." % self.name)

>>> p = Person("李世民")
>>> p.kick()
我叫李世民, shit, 谁踢我...

设置私有变量

  • __name = "xxx"
  • 可使用p._Person__name访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person:
__name = '小甲鱼'
def getName(self):
return self.__name

>>> p = Person()
>>> p.__name
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__name'
>>> p.getName()
'小甲鱼'
>>> p._Person__name
'小甲鱼'

通过property绑定属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class C:
def __init__(self, size=10):
self.size = size

def getSize(self):
return self.size

def setSize(self, value):
self.size = value

def delSize(self):
del self.size
# 绑定属性x与属性size
x = property(getSize, setSize, delSize)


c = C()
print(c.size) # 10
c.x = 28
print(c.size) # 28
c.size = 30
print(c.x) # 30
del c.x
print(c.size) # size属性已删除,报错
  • property绑定属性原理, 自定义property类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class MyProperty:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel

def __get__(self, instance, owner):
return self.fget(instance)

def __set__(self, instance, value):
self.fset(instance, value)

def __delete__(self, instance):
self.fdel(instance)


class C:
def __init__(self):
self._x = None

def getX(self):
return self._x

def setX(self, value):
self._x = value

def delX(self):
del self._x

x = MyProperty(getX, setX, delX)


c = C()
c.x = 'xxx'
print(c._x) # xxx
del c.x
print(c._x) # 报错, AttributeError: 'C' object has no attribute '_x'

继承(用于纵向关系的类)

  • 其中pass是占位符, 表示不做任何处理
  • 自己创建的MyList类继承系统的list类
1
2
3
4
5
6
7
8
9
10
11
12
class MyList(list):
pass

>>> list1 = MyList()
>>> list1.append(5)
>>> list1.append(3)
>>> list1.append(7)
>>> list1
[5, 3, 7]
>>> list1.sort()
>>> list1
[3, 5, 7]
  • 子类中定义的方法会覆盖父类定义的方法, 包括__init__(self)方法
  • 所以子类的__init__(self)需要先调用父类的__init__(self)方法
    1. 调用未绑定的父类方法
    2. super().__init__()
  • Python支持多继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import random as r

class Fish:
def __init__(self):
self.x = r.randint(0, 10)
self.y = r.randint(0, 10)

def move(self):
self.x -= 1
print('我的位置是:', self.x, self.y)

class Shark(Fish):
def __init__(self):
# Fish.__init__(self) # 调用未绑定的父类方法
super().__init__()
self.hungry = True

类组合(用于横向关系的类, 类之间没有继承关系或者其他关联)

  • 把要组合的类的实例化写入新类的__init__函数中, 例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Turtle:
def __init__(self, x):
self.num = x


class Fish:
def __init__(self, x):
self.num = x


class Pool:
def __init__(self, x, y):
self.turtle = Turtle(x)
self.fish = Fish(y)

def print_num(self):
print("水池里总共有乌龟 %d 只和小鱼 %d 条!" % (self.turtle.num, self.fish.num))


pool = Pool(2, 11)
pool.print_num()

# 水池里总共有乌龟 2 只和小鱼 11 条!
  • 类、类对象、实例对象
    • 类属性(静态属性/成员), 所有实例对象共用
    • 实例属性(实例属性/成员), 与类属性同名的实例属性会覆盖类属性
  • 属性名与方法名相同, 属性会覆盖方法(导致方法无法调用)
  • 类的方法需要绑定self, 是为了实例对象调用该方法

Python魔法方法

解构与析构

  • 在定义类时, 第一个调用的方法是__new__方法, 一般采用Python自带即可, 不需要重写, 当继承一个不可变的类时才可能需要重写. 例如:
1
2
3
4
5
6
7
8
class CapitalStr(str):
def __new__(cls, string):
string = string.upper()
return str.__new__(cls, string)

>>> s = CapitalStr('Good morning, everyone!')
>>> s
'GOOD MORNING, EVERYONE!'
  • 定义类时, 还有一个隐式的__del__方法, 当对象不再被其它变量引用时会被Python垃圾回收机制回收, 触发__del__方法

__str____repr__

  • str()函数得到的字符串可读性好, 所以被print调用, 对应__str__函数返回值
  • repr()函数得到字符串通常可以用来重新获得该对象, obj==eval(repr(obj). 对应__repr__函数返回值
  • str()则不同,它生成一个对象的可读性好的字符串表示,结果通常无法用eval()求值,但适合print输出。
  • str()出来的值是给人看的。repr()出来的值是给python看的,可以通过eval()重新变回一个Python对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> class A:
... def __str__(self):
... return 'a__str__'
... def __repr__(self):
... return 'a__repr__'
...
>>> a = A()
>>> a
a__repr__
>>> print(a)
a__str__
>>> '%s' % a
'a__str__'
>>> '%r' % a
'a__repr__'

定制定时器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 定制定时器
import time as t


class MyTimer():
def __init__(self):
self.unit = ['年', '月', '日', '时', '分', '秒']
self.prompt = '未开始计时!'
self.lasted = []
self.begin = 0
self.end = 0

# 表示直接输出对象的值或者print(对象)的值
def __str__(self):
return self.prompt

__repr__ = __str__

def __add__(self, other):
prompt = '总共运行了'
result = []
for index in range(6):
result.append(self.lasted[index] + other.lasted[index])
if result[index]:
prompt += (str(result[index]) + self.unit[index])
return prompt

# 开始计时
def start(self):
self.begin = t.localtime()
self.prompt = '提示: 请先调研stop()停止计时!'
print('计时开始...')

# 停止计时
def stop(self):
if not self.begin:
print('提示: 请先调用start()进行计时!')
else:
self.end = t.localtime()
self._calc()
print('计时结束!')

# 内部方法,计算运行时间
def _calc(self):
self.lasted = []
self.prompt = '总共运行了'
for index in range(6):
self.lasted.append(self.end[index] - self.begin[index])
if self.lasted[index]:
self.prompt += (str(self.lasted[index]) + self.unit[index])
# 为下一轮计时初始化
self.begin = 0
self.end = 0
# print(self.prompt)

__add____sub__

内置加法与内置减法, 当两个对象相加或相减是触发

属性访问(定制)

  • __getattr__(self, name) –> 定义当用户试图获取一个不存在的属性时的行为
  • __getattribute__(self, name) –> 定义当该类的属性被访问时的行为
  • __setattr__(self, name, value) –> 定义当一个属性被设置时的行为
  • __delattr__(self, name) –> 定义当一个属性被删除时的行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Rectangle:
def __init__(self, width=0, height=0):
self.width = width
self.height = height

def __setattr__(self, name, value):
if name == 'square':
self.width = value
self.height = value
else:
# self.name = value # 报错,__setattr__自己调用自己,死循环
# super().__setattr__(name, value) # 可使用基类的__setattr__方法
self.__dict__[name] = value

def getArea(self):
return self.width * self.height


r = Rectangle(4, 5)
print(r.getArea()) # 10
r.square = 10
print(r.getArea()) # 100
  • 自定义温度函数转换(类似property)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Celsius:
def __init__(self, value=26):
self.value = float(value)

def __get__(self, instance, owner):
return self.value

def __set__(self, instance, value):
self.value = float(value)


class Fahrenheit:
def __get__(self, instance, owner):
return instance.cel * 1.8 + 32

def __set__(self, instance, value):
instance.cel = float(value) - 32 / 1.8


class Temperature:
def __init__(self, value=26):
self.value = float(value)
cel = Celsius()
fah = Fahrenheit()


temp = Temperature()
print(temp.value) # 26.0
print(temp.cel) # 26.0
temp.cel = 30
print(temp.fah) # 86.0
temp.fah = 88
print(temp.cel) # 70.22222222223

定制序列(容器)

  1. __len__(self)
  2. __getitem__(self, key)
  3. __setitem__(self, key, value)
  4. __delitem__(self, key)

定义元组或者字符串等不可变容器, 只需定义前两个方法即可
如果定义可变容器, 以上四个方法都需要定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class CountList:
def __init__(self, *args):
self.values = [x for x in args]
self.count = dict.fromkeys(range(len(self.values)), 0)

def __len__(self):
return len(self.values)

def __getitem__(self, key):
self.count[key] += 1
return self.values[key]


list1 = CountList(1, 3, 5, 7, 9)
list2 = CountList(2, 4, 6, 8, 10)
print(list1[1]) # 3
print(list2[1]) # 4
print(list1[1] + list2[2]) # 3 + 6 = 9
list1.count # 不代表获取list1容器中的元素
print(list1.count) # {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(list2.count) # {0: 0, 1: 1, 2: 1, 3: 0, 4: 0}

定制迭代器

  • iter() –> 返回可迭代对象的迭代器
  • next() –> 得到迭代器的下一个迭代值, 如果没有下一个迭代值, 报StopIteration异常
1
2
3
4
5
6
7
8
9
10
11
>>> it = iter('abc')
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
File "<console>", line 1, in <module>
StopIteration
  • 自己定制迭代器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Fibs:
def __init__(self, n=10):
self.a = 0
self.b = 1
self.n = n

def __iter__(self):
return self

def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > self.n:
raise StopIteration
return self.a


fibs = Fibs(100)
for each in fibs:
print(each, end=' ')

以上代码, Fibs被定义为一个可迭代的斐波那契类容器, 迭代结果如下:

1
1 1 2 3 5 8 13 21 34 55 89

生成器函数

  • 关键词yield, 相当于return, 函数运行到此处会暂停或挂起, 并在需要的时候(next())从程序离开的地方继续或者重新开始
  • 生成器推导式
1
2
3
4
5
6
7
8
9
10
11
12
13
>>> d = (i for i in range(10))
>>> d
<generator object <genexpr> at 0x10b9588e0>
>>> next(d)
0
>>> next(d)
1
>>> next(d)
2
for each in d:
print(each, end=' ')

3 4 5 6 7 8 9
  • 生成器推导式作为函数参数时可以省略括号
1
2
3
4
>>> sum((i for i in range(100) if i % 2))
2500
>>> sum(i for i in range(100) if i % 2)
2500

列表推导式

1
2
3
>>> a = [i for i in range(100) if i % 2 and not(i % 3)]
>>> a # 显示0, 99之间不能被2整除但能被3整除的数字
[3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93, 99]

字典推导式

1
2
3
>>> b = {i: i % 2 == 0 for i in range(10)}
>>> b # 0, 9之间的数字是否为偶数
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}

集合推导式

1
2
3
>>> c = {i for i in [23, 4, 5, 9, 6, 3, 1, 4, 5, 6, 7]}
>>> c # 排除列表中重复的数字
{1, 3, 4, 5, 6, 7, 9, 23}