python 内置方法/魔法方法

什么是内置方法?

# 定义在类内部,以__开头并以__结果的方法
# 特点:会在某种情况下自动触发执行

为什么要用内置方法?

# 为了定制化我们的类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
'''

setattr,getattr,setitem,getitem演示

setitem、getitem

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)

with 上下文管理器(__enter__、__exit__)

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
原文地址:https://www.cnblogs.com/baicai37/p/12706127.html