测试开发进阶(五)

测试开发进阶(五)

面向对象

魔术方法(魔法方法,特殊方法)

__new__方法和单例模式

__init__:在创建对象的时候,自动调用对 创建的对象 进行初始化设置的

魔术方法:以双下划线开头,双下划线结尾的方法

1
2
3
4
@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" Create and return a new object. See help(type) for accurate signature. """
pass

从源码可以看出,__new__方法的作用是创建然后返回一个对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Hero(object):
def __init__(self, name):
print('这个是init方法')
self.name = name

def __new__(cls, *args, **kwargs):
# 创建对象时第一步做的就是__new__方法
print('这个是new方法')
return super().__new__(cls)


h1 = Hero('zx')
print(h1)
print(h1.name)
"""
这个是new方法
这个是init方法
<__main__.Hero object at 0x1033b1f60>
zx
"""
单例模式

类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做?

普通模式:

1
2
3
4
5
6
7
class Hero(object):
def __init__(self):
print('这个是init方法')

h1 = Hero()
h2 = Hero()
print(id(h1), id(h2)) # 4328290400 4340056528

单例模式:

第一次创建对象存起来,之后创建对象的时候直接返回第一次创建的对象

实现思路:

  • 定义一个类属性,来记录该类是否创建过对象
  • __new__方法中
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
class MyClass(object):
count = 0
instance = None

def __new__(cls, *args, **kwargs):
if cls.count == 0:
# 调用父类的__new__方法创建一个对象
cls.instance = object.__new__(cls)
cls.count += 1
return cls.instance


h = MyClass()
h1 = MyClass()
h2 = MyClass()
h3 = MyClass()
print(id(h), id(h1), id(h2), id(h3)) # 4349229152 4349229152 4349229152 4349229152

# 精简
class MyClass(object):
instance = None

def __new__(cls, *args, **kwargs):
if not cls.instance:
# 调用父类的__new__方法创建一个对象
cls.instance = object.__new__(cls)
return cls.instance

上下文管理器

上下文管理器:上下文管理器是一个python对象,为操作提供额外的上下文信息。这种额外的信息,使用with语句初始化上下文,以及完成with块中的所有代码时,采用可调用的形式

with关键字:启动对象的上下文管理器

  • object.__enter__(self)

输入与次对象相关的运行时上下文。如果存在的话,with语句将绑定该方法的返回值到该语句的as子语句中指定的目标

  • object.__exit__(self, exc_type, exc_val, exc_tb)
1
2
3
with open('0814.py', 'r', encoding='utf8') as f:
content = f.read()
print(content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyOpen(object):
def __enter__(self):
print('enter') # 1⃣️

def __exit__(self, exc_type, exc_val, exc_tb):
print('exit') # 3⃣️

with MyOpen() as f:
print(f) # 2⃣️

"""
enter 1⃣️
None 2⃣️
exit 3⃣️
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MyOpen(object):
def __enter__(self):
print('enter') # 1⃣️
return 999 # 2⃣️

def __exit__(self, exc_type, exc_val, exc_tb):
print('exit') # 3⃣️

with MyOpen() as f:
print(f) # 2⃣️

"""
enter 1⃣️
999 2⃣️
exit 3⃣️
"""

自己实现的文件操作上下文管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MyOpen(object):
def __init__(self, file_name, method, encoding):
self.file_name = file_name
self.method = method
self.encoding = encoding
self.f = open(self.file_name, self.method, encoding=self.encoding)

def __enter__(self):
return self.f

def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()


with MyOpen('0814.py', 'r', encoding='utf8') as f:
print(f.read())
1
2
3
exc_type # 异常类型
exc_val # 异常值
exc_tb # 异常回溯追踪
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
class MyOpen(object):
def __init__(self, file_name, method, encoding):
self.file_name = file_name
self.method = method
self.encoding = encoding
self.f = open(self.file_name, self.method, encoding=self.encoding)

def __enter__(self):
return self.f

def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
print(exc_type) # <class 'NameError'>
time.sleep(0.5)
print(exc_val) # name 'a' is not defined
time.sleep(0.5)
print(exc_tb)
"""
Traceback (most recent call last):
File "/Users/zhongxin/Desktop/py/zx/05/0814_2.py", line 34, in <module>
print(a)
NameError: name 'a' is not defined
"""


with MyOpen('0814.py', 'r', encoding='utf8') as f:
print(a)

执行顺序:实例化(__init__)—-> 执行__enter__—->执行with中的代码—–>执行 __exit__

__str__,__repr__方法

1
2
3
4
5
>>> a = 'abc'
>>> print(a)
abc
>>> a
'abc'

当我们使用print()这个内置函数之后,给他传入一个对象,实际上是触发了它的__str__方法,将方法返回的内容输出到控制台

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Hero(object):
def __init__(self, name):
self.name = name
h = Hero('zx')
print(h) # <__main__.Hero object at 0x103295908>


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

def __str__(self):
print('STR') # 1⃣️
return '666' # 2⃣️


h = Hero('zx')
print(h)
"""
STR 1⃣️
666 2⃣️
"""

在交互环境中,输入对象,返回的是__repr__方法中所返回的内容

  • 内置函数str转化一个对象时候,触发__str__方法
  • 内置函数format处理对象时,触发__str__方法
  • 内置函数repr函数,触发__repr__方法
1
2
3
4
5
6
7
8
9
10
11
12
class Hero(object):
def __init__(self, name):
self.name = name

def __str__(self):
return self.name


h = Hero('zx')
print(h) # zx
print(str(h)) # zx
print(repr(h)) # <__main__.Hero object at 0x1031c7860>

__repr____str__的备胎,当没有__str__的时候调用__repr__,反过来不会

算数运算相关的魔术方法

  • __add__:相加

  • __sub__:减法

  • __mul__:乘法

  • __stuediv__:除法

  • __floordiv__:整除

  • __mod__:取余

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyStr():
def __init__(self, value):
self.value = value

def __str__(self):
return self.value

def __add__(self, other):
return f'{self}{other}'

def __sub__(self, other):
return f'{self}-{other}'


v1 = MyStr('aaa')
v2 = MyStr('bbb')
print(v1 + v2) # aaabbb
print(v1 - v2) # aaa-bbb

多个连续相加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyStr():
def __init__(self, value):
self.value = value

def __str__(self):
return self.value

def __add__(self, other):
return MyStr(f'{self}{other}')#⚠️


v1 = MyStr('aaa')
v2 = MyStr('bbb')
v3 = MyStr('ccc')
print(v1 + v2 + v3) # aaabbbccc

一个没啥用的减法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyStr():
def __init__(self, value):
self.value = value

def __str__(self):
return self.value

def __add__(self, other):
return MyStr(f'{self}{other}')

def __sub__(self, other):
return MyStr(self.value.replace(other.value, ''))


v1 = MyStr('aaa')
v2 = MyStr('bbb')
v12 = v1 + v2
print(v12)
print(v12 - v1)
 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
您的支持将鼓励我继续创作!