1.什么是魔法函数

    以__开始和结束,不需要专门调用,在特定场合下,python会自己调用,如__init__, __str__等

 python 魔法函数学习_Test

2.常用的魔法函数

    __str__: 返回类对象友好的提示,例子

class Test:
def __init__(self, name):
self.name = name

def __str__(self):
return self.name

obj = Test(name="Hello, World")
print(obj)

    __len__:计算对象容器中元素的个数      # 应用场景???,将类当容器处理

class TestLen:
def __init__(self, mylist):
self.mylist = mylist

def __len__(self):
return len(self.mylist)

obj = TestLen([1,2,3,4])
print(len(obj)) # 去掉__len__, 则报错

__setitem__(新建字典),__getitem__(通过key获取value),__delitem__(删除key对应的value),应用场景,将类当字典处理  

class TestNewClass:
# 不会调用
def __get__(self, instance, owner):
print("get")
def __set__(self, instance, value):
print("set")
def __delete__(self, instance):
print("delete")

obj = TestNewClass()
# 不会调用get,set,delete方法
obj.name = "hyh"
print(obj.name)
del obj.name
print(obj.name) # 报错

新式类__get__,set,delete,达到上面效果,但是为啥不调用get,set,delete

参考:​​https://zhuanlan.zhihu.com/p/356076165

class TestDict:
def __init__(self):
self.dict = {}

# 新建字典
def __setitem__(self, key, value):
self.dict[key] = value

# 通过字典key获取value
def __getitem__(self, item):
return self.dict[item]

# 删除对应key的记录
def __delitem__(self, key):
del self.dict[key]

obj = TestDict()
obj.dict["name"] = "hyh" # 调用__setitem__
obj["age"] = 18 # 效果同上
print(obj.dict)
print(obj["name"]) # 调用__getitem__
del obj["age"] # 调用__delitem__
print(obj.dict)

 

__iter__,__next__:迭代器 ,将类对象当作可迭代对象

class TestIterator:
def __init__(self, value):
self.start = 0
self.end = value

def __iter__(self):
return self

def __next__(self):
if self.start < self.end:
self.start += 1
return self.start
else:
raise StopIteration

obj = TestIterator(5)
# 可遍历
for i in obj:
print(i)

# 使用next函数遍历
#print(next(obj))
#print(next(obj))

 __enter__,__exit__:实现with上下文管理  

class TestWith:
def __init__(self, filename, mode="r", encoding="utf-8"):
self.filename = filename
self.__file = open(filename, mode, encoding=encoding)

def __enter__(self):
print("enter")
return self

def write(self, content):
print("write")
self.__file.write(content)

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

with TestWith(r"E:\python_apps\bk-pipline\haoyong_test\hyh.txt", mode="w", encoding="utf-8") as f:
f.write("nihao\n hello world")

实现数据库连接释放

import pymysql
import time

class TestConMysql:
def __init__(self, host, port, account, passwd, dbname):
self.host = host
self.port = port
self.account = account
self.passwd = passwd
self.dbname = dbname
self.conn = None

def __enter__(self):
print("打开连接")
self.conn = pymysql.connect(host=self.host,user=self.account,passwd=self.passwd,db=self.dbname, charset="utf8")
return self


def __exit__(self, exc_type, exc_val, exc_tb):
print("关闭连接")
self.conn.close()

def cmd(self):
cursor = self.conn.cursor()
exe = cursor.execute("show databases")
time.sleep(30)


with TestConMysql(host="192.168.226.128", port=3306, account="root", passwd="111111", dbname="xxxx") as con:
con.cmd()

登录数据库查看连接数

__init__类实例化对象时被调用

class TestInit:
def __init__(self, name):
print(name)

obj = TestInit(name="hyh")

__new__负责创建类,在__init__之前执行

class TestNew:
#创建类
def __new__(cls, *args, **kwargs): #cls参数有python解释器提供
print("优先执行")
instance = super().__new__(cls) # 使用super创建类
print(id(instance))
return instance # 必须有返回值
#初始化类
def __init__(self, name):
print(name)

print(id(self))

__call__实现类对象像普通函数那样可调用

class TestCall:
def __init__(self, name):
self.name = name

def __call__(self, age):
print(f"我叫{self.name}, 今年{age}岁")

call = TestCall(name="hyh")
call(22)

__lt__实现对象可比较,应用场景,比较,排序对象

class People:
def __init__(self, name, age):
self.name = name
self.age = age

def __str__(self):
return self.name + ":" + str(self.age)

def __lt__(self, other):
return self.age < other.age

people1 = People("hyh", 18)
people2 = People("hyh1", 19)
print(people1 > people2) # False