python上下文管理类型

Python上下文管理类型

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
# 上下文管理协议(常用于文件自动关闭、线程锁自动释放、数据库自动关闭连接、socket连接)
# 最简单的实现
class Sample(object):
def __enter__(self):
print("enter")
return self

def __exit__(self, exc_type, exc_val, exc_tb):
print("exit")

def do_something(self):
print("do something")
# with语句首先先调用__enter__方法
with Sample() as sample:
# 方法执行结束后自动调用__exit__方法
sample.do_something()

# 线程锁自动释放的实现
import threading
class LockContext(object):

def __init__(self):
self.lock = threading.Lock()

def __enter__(self):
print("enter")
self.lock.acquire()
return self

def __exit__(self, exc_type, exc_val, exc_tb):
print("exit")
self.lock.release()

my_list=[1,2,3]
with LockContext():
my_list.append(4)


# 附加:
# 文件自动关闭、线程锁自动释放、数据库自动关闭连接,socket自动关闭连接
with open("a.txt",'w') as file:
file.write("hello world")

import threading
lock = threading.Lock()

my_list=[1,2,3]
with lock:
my_list.append(4)

import sqlite3
sql_conn = sqlite3.connect("result.db", timeout=5)

with sql_conn as cur:
cur.execute("SELECT * FROM xxx")

import socket
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as client:
client.connect("127.0.0.1",8000)
client.send("hello".encode("utf8"))


# 使用上下文管理工具contextlib,不用再创建类以及实现__enter__,__exit__方法
from contextlib import contextmanager

@contextmanager
def make_conn_context(sqlpath):
import sqlite3
sql_conn = sqlite3.connect(sqlpath, timeout=5)
try:
yield sql_conn
finally:
sql_conn.close()

with make_conn_context(sqlpath="result.db") as cur:
create_sql = '''create table requisitioninfo(
ip_address varchar(20) not null,
master varchar(50) not null);
'''
cur.execute(create_sql)

Python常用的魔术方法

作用:增强类的功能,定义后不需要显式调用,主要分为以下几类

  • 字符串表示:__str__,__repr__
  • 集合,序列相关,__len__,__getitem__,__setitem__,__delitem__,__contains__
  • 迭代相关:__iter__,__next__
  • 可调用:__call__
  • with上下文管理器:__enter__,__exit__
  • 数值转换:__abs__,__bool__,__int__,__float__,__hash__,__index__
  • 元类相关:__new__,__init__
  • 属性相关:__getattr(self, name)__,__setattr(self, name, value)__,__getattribute__,__setattribute__,__dir__,__dict__
  • 属性描述符:__get__,__set__,__delete__
  • 数学二元运算符:__lt__,__le__,__eq__,__ne__,__gt_,__ge__,

1.字符串表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 字符串表示
"""
打印实例,返回我们想要的结果,可以添加__repr__,__str__方法
打印列表以及字典等容器类型或命令行查看实例会调用: __repr__ 方法,
"""
class MyClass(object):
def __init__(self,str1):
self.str1 = str1

def __str__(self):
return "__str__:{}".format(self.str1)

def __repr__(self):
return "__repr__:{}".format(self.str1)

if __name__ == '__main__':
str1 = "示例字符串"
mc = MyClass(str1)
print(mc)

2.集合,序列相关,迭代相关

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
# -*- coding: utf-8 -*-
# 自定义list
class FunctionalList(object):
''' 实现了内置类型list的功能,并丰富了一些其他方法: head, tail, init, last, drop, take'''

def __init__(self, values=None):
if values is None:
self.values = []
else:
self.values = values

def __len__(self):# 返回长度
return len(self.values)

def __getitem__(self, key):# 返回list某个索引的值
return self.values[key]

def __setitem__(self, key, value):
self.values[key] = value

def __delitem__(self, key):
del self.values[key]

def __contains__(self, item):
if item in self.values:
return True
return False

def __iter__(self):
return iter(self.values)

def __reversed__(self):
return FunctionalList(reversed(self.values))

def append(self, value):
self.values.append(value)
def head(self):
# 获取第一个元素
return self.values[0]
def tail(self):
# 获取第一个元素之后的所有元素
return self.values[1:]
def init(self):
# 获取最后一个元素之前的所有元素
return self.values[:-1]
def last(self):
# 获取最后一个元素
return self.values[-1]
def drop(self, n):
# 获取所有元素,除了前N个
return self.values[n:]
def take(self, n):
# 获取前N个元素
return self.values[:n]

if __name__ == '__main__':
fl = FunctionalList(values=[1,2,3,4,5])
print(1 in fl)
print(len(fl))
for i in reversed(fl):
print(i)
print(fl.head())
print(fl.tail())
print(fl.init())
print(fl.last())
print(fl.drop(1))
print(fl.take(1))
fl.append(6)
for i in fl:
print(i)

3.属性相关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#  正确用法
def __setattr__(self, name, value):
self.__dict__[name] = value # 给类中的属性名分配值

def __getattr__(self, name):
return self.__dict__[name]

"""
附加说明
__getattribute__与__getattr__的区别

__getattribute__定义了你的属性被访问时的行为,
相比较,__getattr__只有该属性不存在时才会起作用。
因此,在支持__getattribute__的Python版本,
调用__getattr__前必定会调用 __getattribute__。
__getattribute__同样要避免”无限递归”的错误。
需要提醒的是,最好不要尝试去实现__getattribute__,因为很少见到这种做法,而且很容易出bug。
"""

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
34
'''
使用描述符来实现需要类型检查的属性:
分别实现__get__,__set__,__delete__方法,在
__set__内使用isinstance函数做类型检查
'''

class Attr(object):
def __init__(self, name, type_):
self.name = name
self.type_ = type_

def __get__(self, instance, cls):
# print('in __get__', instance, cls)
return instance.__dict__[self.name]

def __set__(self, instance, value):
print('in __set__')
if not isinstance(value,self.type_):
raise TypeError('expected an %s' % self.type_)
instance.__dict__[self.name] = value

def __delete__(self, instance):
# print('in __del__')
del instance.__dict__[self.name]

class Person(object):
# x = Descriptor() # x为类的属性
name = Attr('name', str)
age = Attr('age', int)
heigth = Attr('height', float)

p = Person()
p.name = 'Bob'
print(p.name)

5.数学二元运算符,描述符

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
# coding:utf8
from functools import total_ordering
from math import pi
from abc import ABCMeta, abstractmethod

@total_ordering # 装饰器
class Shape(object):

@abstractmethod
def getArea(self):
pass

def __lt__(self, obj):
print('in__lt__')
if not isinstance(obj, Shape):
raise TypeError('obj is not Shape')
return self.getArea() < obj.getArea()

def __eq__(self, obj):
print('in__eq__')
if not isinstance(obj, Shape):
raise TypeError('obj is not Shape')
return self.getArea() == obj.getArea()

class Circle(Shape):
def __init__(self, radius):
self.radius = radius

def getRadius(self):
# return self.radius
return round(self.radius, 2) # 表示四舍五入后保留小数点后两位

def setRadius(self, value):
if not isinstance(value, (int, long, float)):
raise valueError('wrong type .')
self.radius = float(value)

def getArea(self):
return self.radius * self.radius * pi

R = property(getRadius, setRadius)

radius1 = Circle(4)
radius2 = Circle(5)
print(radius1 == radius2)
print(radius1 < radius2)
坚持原创技术分享,您的支持将鼓励我继续创作!