什么是内置方法?
# 定义在类内部,以__开头并以__结果的方法 # 特点:会在某种情况下自动触发执行
为什么要用内置方法?
# 为了定制化我们的类or对象
python中常用魔法方法
# __init__:类实例化会触发 # __str__:打印对象会触发 # __call__:对象()触发,类也是对象 类(),类的实例化过程调用元类的__call__ # __new__:在类实例化会触发,它比__init__早(造出裸体的人,__init__穿衣服) # __del__:del 对象,对象回收的时候触发 # __setattr__,__getattr__:(.拦截方法),当对象.属性--》赋值会调用setattr,如果是取值会调用getattr # __getitem__,__setitem__:([]拦截) # __enter__和__exit__ 上下文管理器
如何使用内置方法?
__str__:在打印对象时会自动触发,然后将返回值(必须是字符串类型)当做本次打印的结果输出
class People: def __init__(self, name, age): self.name = name self.age = age def __str__(self): # print('运行了...') return "<%s:%s>" %(self.name,self.age) obj = People('辣白菜同学', 18) # print(obj.__str__()) print(obj) # <'辣白菜同学':18>
__del__:在清理对象时触发,会先执行该方法
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print(class_name, "销毁") pt1 = Point() pt2 = pt1 print(id(pt1),id(pt2)) # 打印对象的id del pt1 #要等pt2执行完才会触发__del__ print(pt2) ''' 2074762969384 2074762969384 <__main__.Point object at 0x000001E311828128> Point 销毁 '''
__format__:自定义打印时间格式
date_dic={ 'ymd':'{0.year}:{0.month}:{0.day}', 'dmy':'{0.day}/{0.month}/{0.year}', 'mdy':'{0.month}-{0.day}-{0.year}', } class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day def __format__(self, format_spec): if not format_spec or format_spec not in date_dic: format_spec='dmy' fmt=date_dic[format_spec] return fmt.format(self) d1=Date(2016,12,29) print(format(d1)) print(format(d1,"mdy")) ''' 执行结果 29/12/2016 12-29-2016 '''
class Person: def __init__(self,name): self.name=name def __setitem__(self, key, value): setattr(self,key,value) #反射 def __getitem__(self, item): return getattr(self,item) # 反射取值 p=Person('lqz') # p.name='ppp' p['name']=10 # 本来这么赋值是不可以的,如何就可以了呢,重写__setitem__魔法方法 # print(p.name) print(p['name'])
__setattr__、__getattr__
class Mydic(dict): def __setattr__(self, key, value): print("对象加点赋值,会触发我") self[key]=value def __getattr__(self, item): print("对象加点取值,会触发我") return self[item] # 不要加引号 mydic=Mydic(name='lqz',age=18) # print(mydic['name']) print(mydic.name) # mydic.name=99 # print(mydic.name)
案例:
class Fun(): def __init__(self,name,age,male): self.name = name self.age = age self.male = male def __setattr__(self, key, value): if key == "name": if isinstance(value,str): super().__setattr__(self, key, value) else: print("不能赋值非字符串类型") else: super.__setattr__(self, key, value) def __getattr__(self, item): print("加点取值会调用我") print(type(self.__dict__),self.__dict__) return self.__dict__.get(item) fun = Fun("lxx",18,"male") fun.name = 13 print(fun.age)
class Person: def __enter__(self): print("我在with管理的时候,会触发") print('进入with语句块时执行此方法,此方法如果有返回值会赋值给as声明的变量') return 'oo' def __exit__(self, exc_type, exc_val, exc_tb): print('退出with代码块时执行此方法') print('1', exc_type) print('2', exc_val) print('3', exc_tb) with Person() as p: # 这句话执行,会触发类的__enter__,这个p就是上面__enter__中return的 print(p)
案例:上下文管理MySQL链接
import pymysql class Mysql: def __enter__(self): print("我在with管理的时候,会触发") print('进入with语句块时执行此方法,此方法如果有返回值会赋值给as声明的变量') # 链接 self.conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123456', database='book_user', charset='utf8', ) # 游标 self.cursor = self.conn.cursor() # 执行完毕返回的结果集默认以元组显示 return self def __exit__(self, exc_type, exc_val, exc_tb): self.cursor.close() self.conn.close() print('退出with代码块时执行此方法') # print('1', exc_type) # print('2', exc_val) # print('3', exc_tb) with Mysql() as self: # 这句话执行,会触发类的__enter__ print(self) sql = 'select * from app01_book;' rows = self.cursor.execute(sql) print(rows)
__eq__
class A: def __init__(self,x,y): self.x = x self.y = y # def __eq__(self,obj): # # 打印出比较的第二个对象的x值 # print(obj.x) # if self.x +self.y == obj.x+obj.y: # return True # else: # return False a=A(1,2) b=A(99,3) print(a==b) # 当执行==s时,会触发__eq__的执行,并且把b传进去,就是object # ==后只要是对象,就可以传进去,就是object