这篇文章介绍魔术方法。
目录
1. __enter__ 和 __exit__ 实现上下问管理器
1. __enter__ 和 __exit__ 实现上下问管理器
class OpenFile(object):
def __init__(self, file_name, mode, encoding='utf-8'):
self.file_name = file_name
self.mode = mode
self.encoding = encoding
def __enter__(self):
print("上下文管理器进入方法")
self.obj_f = open(file=self.file_name, mode=self.mode, encoding=self.encoding)
return self.obj_f
def __exit__(self, exc_type, exc_val, exc_tb):
self.obj_f.close()
print("上下文管理器退出方法")
print(exc_type) # 异常类型
print(exc_val) # 异常值
print(exc_tb) # 异常溯源信息
with OpenFile("test1.txt", 'a') as f:
f.write('121218938219382193')
print("使用方法")
print(f)
# print(name)
这里使用的__enter__ 和 __exit__ 方法来实现上下文管理器的,不用手动地去关闭文件,在__exit__中做相关关闭的操作即可。
使用__enter__ 和 __exit__ 实现连接MySQL数据库的实例:
def do_config():
"""
从配置文件中读取数据库的配置
:return:
"""
return '数据库配置'
# 第一题
class MyDb(object):
def __init__(self, host, user, password, db, port, charset):
self.host = do_config("database", "host")
self.user = do_config("database", "user")
self.password = do_config("database", "password")
self.db = do_config("database", "db")
self.port = do_config("database", "port")
self.charset = do_config("database", "charset")
def __enter__(self, sql, args=None, is_all=False):
self.cursor = self.conn.cursor()
self.cursor.execute(sql, args)
self.conn.commit()
if not is_all:
try:
res = self.cursor.fetchall() # 表示获取数据中的所有记录
except Exception as e:
raise e
else:
try:
res = self.cursor.fetchone() # 表示只取数据中的一条记录
except Exception as e:
raise e
return res
def __exit__(self, exc_type, exc_val, exc_tb):
self.cursor.close() # 关闭数据库游标
self.conn.close() # 关闭数据库连接
2. __str__ 和 __repr__方法
都是用来格式化输出对象的,本质上并无任何区别,但是在不同情景下会调用不同的方法
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__
没有被定义,那么就会使用__repr__
来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
class MyClass(object):
def __str__(self):
print("acc")
def __repr__(self):
return "__repr__的返回方法"
# 目的是:
# 可以在类中定义__str__方法,做当前类的说明
# str总共有3种触发方法
m1 = MyClass()
# 第1种:直接打印触发
print(m1)
# 第2种:通过str转换对象为字符串时触发
res = str(m1)
print(res)
# 第3种:通过format内置函数处理对象时触发
res2 = format(m1)
print(res)
# repr的触发方法
# 1. 交互环境下直接输入对象,会触发repr方法
# 2. repr内置函数处理对象时会触发repr方法
# 3. str方法的备胎
3. __add__ 和 __sub__ 方法
(1)使用 __add__ 和 __sub__ 实现两个字符串的相加和相减。
class MyStr(object):
def __init__(self, value):
self.value = value
def __add__(self, other):
"""
实现两个字符串的拼接
:param other: 另一个字符串
:return: 字符串拼接结果
"""
res = '{}{}'.format(self, other)
return res
def __sub__(self, other):
"""
字符串相减
:param other:第二个字符串
:return: 从第一个字符串中减去第二个字符串
"""
return str(self).replace(str(other), '')
def __str__(self):
return self.value
s1 = MyStr('abcde')
s2 = MyStr('12345')
s3 = MyStr('abcde12345')
print(s1 + s2)
print(s3 - s2)
# 执行结果
abcde12345
abcde
(2)使用 __add__ 和 __sub__ 实现两个字典的相加和相减
class MyDic(dict):
"""实现两个字典的相加和相减"""
def __add__(self, other):
"""实现相加"""
new_dict = self.copy()
new_dict.update(other)
return MyDic(new_dict)
def __sub__(self, other):
"""实现相减"""
new_dict = self.copy()
for key in other.keys():
if key in new_dict.keys():
new_dict.pop(key)
return new_dict
testDic1 = MyDic({'a': '111', 'b': '222'})
testDic2 = MyDic({'a': '111', 'b': '111', 'c': '222'})
res = testDic1 + testDic2
print(res)
res2 = testDic2 - testDic1
print(res2)
4. __call__ 方法
直接使用实例对象后面跟上参数,即可使用类。
class MyCall:
"""实现__call__方法"""
def __init__(self):
pass
def __call__(self, a, b, *args, **kwargs):
result = a + b
print(result)
if __name__ == '__main__':
m = MyCall()
m(100, 111)
5.__new__方法
class MyNew:
def __init__(self, num=None):
self.num = num
print("__init__方法被调用")
def __new__(cls, *args, **kwargs):
print("__new__方法被调用")
return object.__new__(cls)
def add(self, a, b):
print(a + b + self.num)
new1 = MyNew(1)
new1.add(1, 2)
各个方法被调用的时间总结:
__new__ :在创建对象时会被调用
__str__ :在print打印对象的时候调用
__repr__:repr函数处理,或者控制台输入时
__call__:对象加括号调用的时候触发
<完>