Python3 基础

Python3 基础

已学习的包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from collections import Iterable # 可迭代
from collections import Iterator # 迭代器
from types # 封装了内置类型判断变量
import functools # reduce wraps等
import re # 文字处理:正则 findall sub search match
import time # 日期包
import datetime # 日期包
import math # 数字工具
import random # 随机数工具
import pathlib # 文件操作
import os.path # 目录访问
import tarfile # 数据压缩和归档
import threading # 多线程
import queue # 生产者消费者队列
import base64
import json
# 内置网络请求,推荐使用第三方requests库
from urllib.request import urlopen
from urllib.parse import urlencode
# 标记语言处理工具,推荐使用第三方库:xmltodict BeautifulSoup等第三方库
import html
import xml
常用内置函数
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
abs(-45) # 获取数字的绝对值
all([0,1]) # 判断给定的参数中的所有元素是否都为TRUE。元素除了是 0、空、None、False 外都算 True;空元组、空列表返回值为True
any([0,1]) # 判断是否有元素为TRUE
bin(10) # 返回二进制数0b1010
oct() # 将一个整数转换成八进制字符串。
int() # 用于将一个字符串或数字转换为整型。
hex() # 用于将一个整数转换为十六进制数
round() # 返回浮点数x的四舍五入值(精度不能做保证)
pow(2,2) # 返回x的y次方的值。
bool() # 函数用于将给定参数转换为布尔类型
sum([1,2,3]) # 对参数进行求和计算。
bytearray("abcd",encoding="utf-8") # 返回一个新字节数组
callable() # 函数用于检查一个对象是否可调用的。对于函数、方法、lambda函式、类以及实现了 __call__ 方法的类实例, 它都返回 True
chr(98) # 函数用一个范围在range(256)内(即0~255)的整数作参数,返回一个对应的ASCII数值。
dict() # 函数用来将元组/列表转换为字典格式。
dir() # 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表
enumerate() # 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列
eval('3 * 2') # 函数用来执行一个字符串表达式,并返回表达式的值。
exec("print('Hello World')") # 执行储存在字符串或文件中的Python语句,相比于eval,exec可以执行更复杂的Python代码。
float() # 函数用于将整数和字符串转换成浮点数。
frozenset() # 返回一个冻结的集合(一个无序的不重复元素序列),冻结后集合不能再添加或删除任何元素。
hasattr() # 用于判断对象是否包含对应的属性。如果对象有该属性返回 True,否则返回 False。
getattr() # 用于获取对象对应的属性
hash() # 用于获取一个对象(数字或者字符串等)的哈希值
id()# 用于获取对象的内存地址。
input() # 接受一个标准输入数据,返回为 string 类型
iter() # 函数用来生成迭代器
next() # 返回迭代器的下一个项目。
len() # 返回对象(字符、列表、元组等)长度或元素个数。
list() # 方法用于将元组转换为列表。
max() # 返回给定参数的最大值,参数可以为序列。
min() # 函数返回给定参数的最小值,参数可以为序列。
repr() # 函数将对象转化为供解释器读取的形式。返回一个对象的 string 格式。
自动关闭资源-上下文管理器
1
2
white open("file name") as f:
f.read()
闭包

内部函数调用外部函数变量

注意一:如果内部函数没有调用外部函数变量(包含外部函数局部变量),则无法构成闭包,没有__closure__属性

注意二:如果内部函数局部变量有相同的变量名被赋值,则认为是新建的局部变量,并没有调用外部变量,同样也无法构成闭包。可以通过nonlocal声明该变量为非局部变量解决这个问题

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
def out_method(a):
b = 5
def inner_method(x):
return a*x + b
return inner_method
def method(a):
b = 5
return lambda x:a*x+b

m = out_method()
print(m(2))
# __closure__ 闭包对象属性,如果inner_method内没有使用a、b等外部变量,则该属性为None
print(m.__closure__)
print(m.__closure__[0].cell_contents) # 对应a值,如果inner_method没有引用a则没有该值
print(m.__closure__[1].cell_contents) # 对应b值,如果inner_method没有引用b则没有该值
print(m.__closure__[...].cell_contents)

# 内部函数局部变量赋值举例
def out_method():
a = 5
def inner_method():
# a被python认为是局部变量,并没有引用外部变量a,所以也不构成闭包
# nonlocal a 可通过该方式声明a变量为非局部变量,使其形成闭包
a = 10
return a
return inner_method
高级特性
  1. 切片

    1
    2
    3
    4
    5
    6
    '''
    start: 开始位置,如果为负数则从末尾起算,空则从最左侧起算
    end:结束位置,如果为负数则从末尾起算,空则从最右侧结束
    step:间隔
    '''
    list[start:end:step]
  2. 迭代

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    '''
    所有的列表 map set都可以通过for...in...的格式迭代
    判断是否可迭代:
    from collections import Iterable
    print(isinstance(list, Iterable))

    列表:
    for i in list:
    如需获取索引可通过:for i,v in enumerate(list)

    map:
    默认map迭代的是key,需要同时迭代key和value:map kv: for k,v in map.items():

    set:
    for i in set:

    多值遍历:
    for x, y in [(1, 1), (2, 4), (3, 9)]:
    '''
  3. 列表生成式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    '''
    格式:[表达式 生成器 条件]
    '''
    # 举例:
    list = [x * x for x in range(1, 11) if x % 2 == 0]
    # 嵌套:
    list = [m + n for m in 'ABC' for n in 'XYZ']
    # dict:
    list = [k + '=' + v for k, v in d.items()]
    # if else:
    list = [x if x % 2 == 0 else -x for x in range(1, 11)]
    # 生成 dict:
    dict1 = {i * i: i + 1 for i in range(1, 11) if i % 2 == 0}
  4. 生成器

    生成器可以延迟生成数据,可有效防止一次性创建过多数据造成的内存压力

    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
    '''
    判断是否是生成器:
    from types import GeneratorType
    print(isinstance(gene, GeneratorType))

    方式一 生成器:
    将列表生成式的[]更改为(),如:[x for x in range(0, 10)] -> (x for x in range(0, 10))
    g = (x for x in range(0, 10))
    即可next(g) 或 for i in g:

    方式二 生成器函数:
    def frange(start, end, step):
    x = start
    while x < end:
    yield x # 会阻塞在此,直到外部消费了x值,才继续下一步
    x += step
    f = frange(0, 10, 0.5)
    即可next(g) 或 for i in f:

    方式三 生成器类
    class GeneratorTest():
    def __init__(self):
    self.i = 0

    def __iter__(self):
    return self # 因为自身就是生成器,所以返回self

    def __next__(self): # 允许next形成生成器
    if self.i >= 5:
    raise StopIteration()
    self.i += 1
    return self.i
    '''
  5. 迭代器

    1
    2
    3
    4
    5
    6
    7
    8
    from collections import Iterable
    from collections import Iterator

    '''
    凡是可作用于for循环的对象都是Iterable类型;
    凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
    集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
    '''
装饰器
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
# 无参数装饰器
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
# 使用 @函数名 声明函数
@log
def start():
print('start...')
'''
相当于:
start = log(start)
start() 该start实际上为wrapper函数
'''
start()

#带参数装饰器
def log(tag):
def decorator(func):
def wrapper(*args, **kw):
print("%s call %s" % (tag, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
# 使用 @函数名(args) 声明函数
@log("描述")
def start():
print('start...')
'''
相当于:
start = log("描述")(start)
start() 该start实际上为wrapper函数
'''
start()

'''
由于函数对象有一个__name__属性,可以拿到函数的名字:
>>> start.__name__
'start'
经过上面装饰器装饰后:
>>> start.__name__
'wrapper'
这样会造成一些需要通过函数名判断信息的程序出错
不过也不需要编写wrapper.__name__ = func.__name__这样的代码
通过functools.wraps装饰wrapper函数即可
'''
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
偏函数

当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

1
2
3
4
5
6
7
8
9
10
11
# 如有大量的字符串需要转换成8进制数值,每次都编写base=8过于繁琐
int('12345', base=8)
# 可通过偏函数使某个参数携带指定的默认值
import functools
int2 = functools.partial(int, base=8)
# 相当于执行 int('12345', base=8)
int2('123456')

max2 = functools.partial(max, 10)
# 相当与执行max(10, 5, 6, 7)
max2(5, 6, 7)
协程
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
# 手动实现协程
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'

def produce(c):
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()

c = consumer()
produce(c)
'''
注意到consumer函数是一个generator,把一个consumer传入produce后:
1. 首先调用c.send(None)启动生成器;
2. 然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
3. consumer通过yield拿到消息,处理,又通过yield把结果传回;
4. produce拿到consumer处理的结果,继续生产下一条消息;
5. produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
'''

# python3.4+ 使用标准库asyncio实现
import asyncio
@asyncio.coroutine
def hello():
print("say hello!")
yield from asyncio.sleep(1)
print("say hello again!")

loop = asyncio.get_event_loop()
# loop.run_until_complete(hello()) # 执行单个任务
loop.run_until_complete(asyncio.wait({hello(), hello()})) # 执行多个任务
loop.close() # 任务执行完后直接结束
# loop.run_forever() # 任务执行完后保持运行

# python3.5+ 新增简化版协程声明async和await
@asyncio.coroutine
def hello():
print("Hello world!")
r = yield from asyncio.sleep(1)
print("Hello again!")
# 将@asyncio.coroutine换成async,将yield from换成await即可
async def hello():
print("Hello world!")
r = await asyncio.sleep(1)
print("Hello again!")
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
'''
class 类名(父类):
name = '' # 类变量,允许外部通过 类名.变量名 。相当于java的类静态变量
def __init__(self, arg): # 构造函数,首个参数必须为self
self.arg = arg # 赋值给实例变量arg,无需像name一样声明成员变量
pass

def 函数名(self): # 自定义函数,首个参数必须为self
print(self.name) # 使用类变量
print(类名.name) # 使用类变量
print(self.__class__.name) # 使用类变量
print(self.arg) # 使用实例变量
# 通过 self.变量名 的方式优先查找实例变量,如果实例变量空则查找类变量

@classmethod
def 函数名(cls): # 类函数
print(cls.name)
print(Student.name)

@staticmethod
def 函数名(): # 静态函数
print(Student.name)


print(实例名.__dict__) # 打印实例所有的实例变量
print(类名.__dict__) # 打印所有的类变量、内置函数和自定义函数
'''

'''
注意一:在变量命名和函数命名在前面增加双下划线 __ ,则相当于声明为私有
注意二:实例.__变量名 = xxx, 相对于给实例新声明一个公开变量,并没有为私有变量赋值
stu = Student()# 内部含有私有变量__name
stu2 = Student()
stu.__name = "xxx"
print(stu.__name) # 打印新声明的公开变量
print(stu2.__name) # 报错没有该变量

注意三:私有变量和私有函数的私有原理为系统发现双下划线时重命名了变量名和函数名:_类名__变量名 _类名__函数名,外部通过重命名后的方式也是可以继续调用的
'''

'''
限制类可声明得变量
class 类名(父类):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

注意一:仅对当前类实例起作用,对继承的子类是不起作用
注意二:除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
'''

'''
动态生成类
def fn():
print("hello")
参数一:class的名称
参数二:继承的父类集合,tuple类型
参数三:声明变量或函数
Hello = type('Hello', (object,), dict(hello=fn))
h = Hello()
h.hello()

与以下类声明效果一致,实际Python解释器也是扫面以下语法定义,然后通过type函数创建类
class Hello(object):
def fn(self):
print("hello")
'''

'''
元类(用于扩展类信息,在编写orm等框架相当有用)
class MyMetaclass(type):
# args[0] = 类名
# args[1] = 父类tuple
# args[2] = 所含有的字段和函数dict
def __new__(cls, *args, **kwargs):
args[2]['add'] = lambda self, value: self.append(value) #动态添加函数
return type.__new__(cls, name, bases, attrs)
# 使用
class MyList(list, metaclass=ListMetaclass):
pass

'''

'''
上下文类
class Test():
def __enter__(self):
# 初始化逻辑
return self

def __exit__(self, exc_type, exc_val, exc_tb):
# 退出结束逻辑

def fun(self):
pass
# 使用
with Test() as t:
t.fun()

高级变种上下文:
from contextlib import contextmanager
class Test():
def fun(self):
pass
@contextmanager
def my_Test():
# 初始化逻辑
yield Test()
# 退出结束逻辑
with my_Test() as t:
t.fun()
'''

'''
类函数属性化:函数可以像属性一样调用
class Test():
@property
def go(self):
return self.name

@go.setter
def go(self,name):
self.name = name
t = Test()
t.go = "aa"
print(t.go)
'''

'''
常用内置函数
__str__ 调用打印时的内容
__repr__ 程序打印时显示的内容
__iter__ __next__ 使对象变成可迭代

__getitem__
使实例能够通过 实例[i]的方式获取值
如果要实现切片功能需要做如下操作:
def __getitem__(self, n):
if isinstance(n, int): # n是索引
# todo
return data
if isinstance(n, slice): # n是切片
start = n.start
stop = n.stop
step = n.step
# todo
return [...]
还有与之对应的__setitem__和__delitem__的方法

__getattr__ 当实例调用一个没有声明的变量或方法时,会尝试调用该方法
__setattr__ 为实例赋值会调用该方法
__call__ 使实例成为callable类型,实例() 的方式调用,通过callable()判断是否是callable类型
'''
枚举
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from enum import Enum,IntEnum,unique

# 自己的枚举类
class 类名(Enum):
VALUE_1 = 1
VALUE_ALIAS = 1 #枚举别名 VALUE_1 == VALUE_ALIAS
VALUE_2 = 'A' # 字符串
VALUE_3 = 1 # 值可重复

class 类名(IntEnum): # 继承自IntEnum只能使用int值
VALUE_1 = 1

@unique # 声明值不可重复
class 类名(Enum):
VALUE_1 = 1

'''
使用: 类名.VALUE_1
枚举名: 类名.VALUE_1.name
枚举值: 类名.VALUE_1.value
遍历枚举: for i in 类名
遍历枚举名: for i in 类名.__members__
常规值转换成枚举值: 类名(1) -> 类名.VALUE_1
'''