0%

Python 学习备忘

Python 学习备忘

学习:廖雪峰Python教程

基础

输入输出

1
2
3
4
5
6
7
a = input();
print('hello world')
print(100 + 200)
a = 'zhang'
print('hello', a)
print('hello %s' % zhang)
print('hello %s %s' %(a,'zhang'))

数据类型

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
# list
classmates = ['Michael', 'Bob', 'Tracy']
len(classmates)
classmates[1]
classmates[-1] # last one, -1 -2 ...
classmates.append('zhang')
classmates.insert(0, 'time')
classmates.pop()
classmates.pop(1)
classmates[1] = 123

a = ['c', 'b', 'a']
a.sort()

# tuple, likely const list
classmates = ('a', 'b', 'c')

# dict likely map in C++
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
d['Jack'] = 90
if 'Thomas' in d :
...
d.get('Thomas') # if not exist, return None and print nothing
d.get('Thomas', -1) # if not exist, set -1

#set
s = set([1, 1, 2, 2, 3, 3])
s.add(4)
s.remove(4)
s1 = set([1, 2, 3])
s2 = set([2, 3, 4])
print(s1 & s2, s1 | s2)

流程控制

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
# if else
a = input()
if a > 10:
print('good')
elif a > 0:
print('boy')
else:
print('!')

# for and while
names = ['a', 'b', 'c']
for name in names:
print('hello', name)

sum = 0
for x in range(10):
sum = sum + x
print(sum)

sum = 0
n = 99
while n > 0:
sum = sum + n
n = n - 2
print(sum)

类型转换

int(), float(), str(), bool()
list(), tuple(), set()

函数

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
def my_abs(x):
if x >= 0:
return x
else:
return -x

# return as return None
# if function in file test.py
from test import my_abs

# do nothing
def nothing():
pass

# Judge
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')


# return multiply data as tuple
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
x, y = move(...)
r = move(...)

# something about defalut parameter, need const
# test 1
def add_end(L=[]): # L = [], object is a var when define the function
L.append('END')
return L
# test 2
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L

# variable parameter
# test 1, numbers as a tuple or list
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
calc([1, 2, 3])
# test 2, numbers as a tuple
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
calc(1, 2, 3)
nums = [1, 2, 3]
calc(*nums)

# keyword parameter
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
person('Michael', 30)
person('Bob', 35, city='Beijing')
person('Adam', 45, gender='M', job='Engineer')
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra)
# only accept city and job
def person(name, age, *, city, job):
print(name, age, city, job)
person('Jack', 24, city='Beijing', job='Engineer')

# mix used
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
f1(1, 2, 3, 4, 'a', d = 1)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
f2(1, 2, d=99, ext=None)
args = (1, 2, 3, 4)
f1(*args, **kw)
args = (1, 2, 3)
kw = {'d': 99, 'x': '#'}
f2(*args, **kw)

# recursion function
def fact(n):
if n == 1:
return 1
return n * fact(n - 1)
fact(5)

# tail recursion
def fact(n, temp):
if n == 1:
return temp
return fact(n - 1, n * temp)

高级特性

  • 代码越少越好,越简单越好,开发效率越高
  • 1行代码能实现,决不写5行代码

切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Slice
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
S = L[0:3]
S = L[:3]
S = L[-2:]

L = list(range(100))
S = L[:10:2]
S = L[::5]
S = L[:]

(0, 1, 2, 3, 4, 5)[:3]
'ABCDEFG'[::2]
'ABCDEFG'[:3]

迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for ch in 'ABC':
...
for key in d = {'a': 1, 'b': 2, 'c': 3}:
...

# can it iterable
from collections import Iterable
isinstance('abc', Iterable)
isinstance([1, 2, 3], Iterable)
isinstance(123, Iterable)

for i, value in enumerate(['A', 'B', 'C']):
print(i, value)
for x, y in [(1, 1), (2, 4), (3, 9)]:
print(x, y)

列表生成式

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
# 1
list(range(1, 11))
# 2
L = []
for x in range(1, 11)
L.append(x * x)
# 3
[x * x for x in range(1, 11)]
[x * x for x in range(1, 11) if x % 2== 0]
[m + n for m in 'ABC' for n in 'XYZ']

# 4
import os
[d for d in os.listdir('.')]

# 5
d = {'x': 'A', 'y': 'B', 'z': 'C'}
for k, v in d.items():
print(k, '=', v)
# 6
d = {'x': 'A', 'y': 'B', 'z': 'C'}
[k + '=' + v for km v in d.items()]

# 7
L = ['Hello', 'World', 'IBM', 'Apple']
[s.lower() for s in L]

生成器

列表元素可以动态推算,不用完整的list

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
55
# 1
L = [x * x for x in range(10)]
g = (x * x for x in range(10))
next(g)
for n in g:
print(n)

# 2
def flb(max)
n, a, b = 0, 0, 1
while n < max
print(b)
a, b = b, a + b
n = n + 1
return 'done'
f = fib(6)
# 3
def flb(max)
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
f = fib(6)

# 4
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
o = odd()
next(o)
next(o)
next(o)

# call generator manually:
g = fib(6)
while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break

# 杨辉三角
def triangles():
l = [1]
while True:
yield l
l = [l[i + 1] + l[i] for i in range(len(l) - 1)]

迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from collections import Iterable

# Iterable
isinstance([], Iterable)
isinstance({}, Iterable)
isinstance('abc', Iterable)
isinstance((x for x in range(10)), Iterable)
isinstance(100, Iterable) # False

# Iterator, which can called by next()
isinstance((x for x in range(10)), Iterator)
'''
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
'''
  • 凡是可作用于for循环的对象都是Iterable类型
  • 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列
  • 集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
  • Python的for循环本质上就是通过不断调用next()函数实现的

函数式变成

高阶函数

1
2
3
4
5
6
7
8
#变量可以指向函数,函数名也是变量
f = abs
f(-10)

#传入函数
def add(x, y, f)
return f(x) + f(y)
add(-4, 5, abs)

map/reduce

  • map()接受两个参数,一个是函数,一个是Iterable,map将传入函数作用到序列的每一个元素,并把结果作为新的Iterator返回
    1
    2
    3
    4
    5
    6
    def f(x):
    return x*x
    r = map(f, range(10))
    print(list(r))
    # integer to str
    list(map(str, range(10)))
  • reduce()也是两个参数,第一个参数是一个函数,这个函数也有两个参数,reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
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
# 1
from functools import reduce
def add(x, y):
return x + y
reduce(add, range(10))
# 2
def fn(x, y):
return x * 10 + y
reduce(fn, range(10))
# 3
def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
return reduce(fn, map(char2num, s))

# lambda
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
def str2int(s)
return reduce(lambda x, y: x * 10 + y, map(char2num, s))

# test 1
def normalize(name):
return name[0].upper() + name[1:].lower()
L1 = ['adam', 'LISA', 'barT']
L2 = list(map(normalize, L1))
print(L2)
# test 2
def prod(L):
return reduce(lambda x, y: x * y, L)
print('3 * 5 * 7 * 9 =', prod([3, 5, 7, 9]))
# test 3
from functools import reduce
def str2float(s):
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
return reduce(lambda x, y: x * 10 + y, map(char2num, s.split('.')[0])) + reduce(lambda x, y: x / 10 + y, map(char2num, reversed(s.split('.')[1])))/10

filter

map()类似,filter()把函数作用于每个元素,根据返回值True还是false决定保留或丢弃此元素

1
2
3
def not_empty(s):
return s and s.strip()
list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))

sorted

1
2
3
4
5
6
7
8
9
10
11
12
13
sorted([36, 5, -12, 9, -21])
sorted([36, 5, -12, 9, -21], key = abs)
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)

# test 1
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return t[0]
def by_score(t):
return t[1]
L2 = sorted(L, key = by_score, reverse = True)
L2 = sorted(L, key=by_name)

返回函数

  • 高阶函数除了可以接受函数作为参数,还可以作为结果返回函数
1
2
3
4
5
6
7
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum

匿名函数

  • lambda x: x * x 匿名函数有个限制,就是只能有一个表达式,不用写return
1
2
3
4
f = lambda x: x*x
f(5)
def build(x, y):
return lambda: x*x + y*y

装饰器

  • 函数对象有一个__name__属性,可以拿到函数的名字foo.__name__
  • 在函数代码运行期间动态增加功能的方式,成为装饰器Decorator
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
import functools
def log(func)
@functools.wraps(func)
def wrapper(*args, **kw)
print('call %s():' %func.__name__)
return func(*args, **kw)
return wrapper

@log # top of function, same as now = log(now)
def now():
print('hello world')
now()
# decorator need parameter
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
# now = log('execute')(now)
def now():
print('2015-3-25')

偏函数

  • functools.partial的作用就是,把一个函数的某些参数给固定住,返回一个新的函数。
  • 创建偏函数时,可以接受函数对象、args**kw这三个参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1
int('12345', base = 2)
def int2(x, base = 2):
return int(x, base)

# 2
import functools
int2 = functools.partial(int , base = 2)
int2('100000')
'''
kw = { 'base': 2 }
int('10010', **kw)
'''
max2 = functools.partial(max, 10)
max2(5, 6, 7)
'''
args = (10, 5, 6, 7)
max(*args)
'''
# 3

模块

  • 包 -> 模块 -> 函数
  • 文件名www.py的模块名是mycompany.web.wwwutils.py两个文件的模块名分别是mycompany.utilsmycompany.web.utils
  • 自己的模块不要和系统自带的冲突即可

    使用模块

  • 任何模块代码的第一个字符串都被视为模块的文档注释
1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# -*- coding: uft-8 -*-
def main():
# list:
argv

if __name__ == '__main__'
main()
  • 安装第三方模块,用pip或pip3(python3), pip3 install Pillow
  • import mymodule 会搜索sys.path下的目录,
1
2
3
4
>>> import sys
>>> sys.path
['', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/zz_zigzag/.local/lib/python3.4/site-packages', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']
>>>
  • 或者使用环境变量PYTHONPATH自定义

面向对象编程

类和实例

1
2
3
4
5
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
bart = Student('Bart', 100)

访问限制

  • __开头的变量为私有变量,如果要访问通过_类名__name
  • _name,“虽然我可以被访问你,但请把我视为私有变量

    继承和多态

  • 对扩展开放:允许新增Animal子类
  • 对修改封闭:不需要修改Animal类型的函数,也可以覆盖

获取对象信息

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
# 1 type
type(123) == type (456)
type(123) == int
# 2 type
import types
def fn():
pass
type(fn).types.FunctionType
type(abs)==types.BuiltinFunctionType
type(lambda x: x)==types.LambdaType
type((x for x in range(10)))==types.GeneratorType'

# 3 type
# object -> Animal -> Dog
a = Dog()
isinstance(h, Dog)
isinstance(h, Animal)
isinstance('a', str)
isinstance(123, int)
isinstance(b'a', bytes)

isinstance([1, 2, 3], (list, tuple))
isinstance((1, 2, 3), (list, tuple))

# 4 all
print(dir('ABC'))
len('ABC') # 函数内部为 'ABC'__len__(), 自己的类如果有这个函数,也可以用len()

# getattr(), setattr() hasattr()
class MyObject(object):
pass
def power(self):
pass
obj = MyObject()
hasattr(obj, 'x') # False
setattr(obj, 'x', 10)
getattr(obj, 'x')
getarrr(obj, 'z', 404) # if have no 'z', return 404
fn = getarrr(ojb, 'power') # fn() same as obj.power()

实例属性和类属性

1
2
3
4
class Student(object):
name = 'Student' # 类属性
def __init__(self, name='zhang'): # 实例属性,不是一回事,而且不要同名
self.name = name

面向对象高级编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 给实例绑定属性
s = Student()
s.age = 16
# 给实例绑定方法
def set_age(self, age):
self.age = age
from types import MethodType
s.set_age = MethodType(set_age, s) # 对另一实例不起作用
s.set_age(25)
Student.set_score = MethodType(set_type, Student) # 给class绑定方法

# 限定实例的属性
class Student(object):
__slots__ = ('name', 'age')

使用@property

  • 类似于装饰器,可以给函数动态加上功能,@property装饰器就是负责把一个方法变成属性调用
  • 把一个getter方法变成属性,只需要加上@property就可以了,此时@property又创建了另一个装饰器@socre.setter,负责把setter方法变成属性赋值
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
55
56
57
58
class Student(object):
@property
def score(self):
return self._score

@score.setter
def score(self, value):
if not isinstance(value, int)
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

s = Student()
s.score = 60
print(s.score)

# 'birth' read and write, 'age' read only
class Student(object):

@property
def birth(self):
return self._birth

@birth.setter
def birth(self, value):
self._birth = value

@property
def age(self):
return 2015 - self._birth

# test 1
class Screen(object):

@property
def width(self):
return self._width

@width.setter
def width(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
self._width = value

@property
def height(self):
return self._height

@height.setter
def height(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
self._height = value

@property
def resolution(self):
return self._height * self._width

多重继承

  • Mixln
1
2
class MyTCPServer(TCPServer, ForkingMixIn):
pass

定制类

  • 类似__xxx__的变量或函数名,有特殊用途
  • __slots__, __len__, __str__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
__repr__ = __str__ # __repr__() 返回程序开发者看到的字符串,为调试服务
print(Student('zhang')

# 2 __iter__ __next__
class Fib(object)
def __init__(self):
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > 100000
raise StopIteration();
return self.a
for i in Filb()
print(i)

枚举类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)

from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
for name, member in Weekday.__members__.items():
print(name, '=>', member, member.value)

使用元类

错误、调试和测试

  • try...except...finally
  • try…except捕获错误还有一个巨大的好处,就是可以跨越多层调用
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
# 1
try:
print('try...')
r = 10 / 0
print('reslut:', r)
except ZeroDivisionError as e:
print('except:', e)
finally:
print('finally...')
print('END')

# 2
try:
print('try...')
r = 10 / int('a')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
finally:
print('finally...')
print('END')

# 3
# err.py:
def foo(s):
return 10 / int(s)

def bar(s):
return foo(s) * 2

def main():
bar('0')

main()
'''
$ python3 err.py
Traceback (most recent call last):
File "err.py", line 11, in <module>
main()
File "err.py", line 9, in main
bar('0')
File "err.py", line 6, in bar
return foo(s) * 2
File "err.py", line 3, in foo
return 10 / int(s)
ZeroDivisionError: division by zero
'''