python基础 27 专题 魔法方法

103 阅读5分钟
  1. 被两条下划线所包围的方法(魔法方法或魔法属性)

  2. 魔法方法是Python的一切

init()

构造方法(初始化方法)---构造器 

new()

1. 在创建对象时init并不是第一个被调用的方法,而是new() 
2. 作用:用于创建对象 
3. 不建议修改new方法 
    new方法负责创建对象(在内存中开辟一块空间,并创建一个对象数据) 
    自省---(类或对象都有自己的魔法成员,可以通过魔法成员的修改反过来影响类或对象的性质) 
    创建对象时的参数,先传递给new方法,进一步传递给构造方法 
规律: 
    1. 给原有的功能做修改 
    2. 覆盖父类中的同名方法 
    3. 修改 
    4. 重新调用父类中的方法 

del()

析构方法---析构器
当一个对象在消亡的时候,自动调用__del__ 
1. __del__和del语句无关 

    垃圾回收机制: 
    1. 如果一个对象没有任何引用,则会被视为垃圾,通过垃圾回收器回收掉 
    2. 对象一旦被视为垃圾,并不会马上消亡,而是被存储到垃圾缓存中 
    3. 如果python在对象消亡前,需要被创建,则不会创建新的对象,而是从缓存中将已经置位垃圾的对 象重新使用
    4. 不建议重复删除并创建同一个类型的对象 
2. 如果对象的引用被删除,不会触发del方法,只有当对象消亡时才会触发del方法 

四 运算相关魔法方法

数据和对象不一样 1是数据,只能用于数学运算 int(1)是对象,对象间运算
1. + 触发对象的__add__() 
2. a+b 调用形式: 
a.__add__(b) 

class MyInt(int):
    def __add__(self, other): 
        print('this is add method') 
        # return int.__add__(self,other) 
        # return 10000 
        # print('self:%s'%self) 
        # print('other:%s'%other)
        return int(self)+int(other) # 避免无限递归 
a=MyInt(100) 
b=MyInt(200) 
print(a+b) # 加好前后的值的位置和add方法有关--- 

五 返运算

1. 更改方法调用的主动性 
    主动性:运算符被解析成方法调用的形式,被调用的对象拥有主动的 
    
class MyInt(int): 
    def __add__(self, other): 
        print('this is add method') 
        # return int.__add__(self,other) 
        # return 10000 
        # print('self:%s'%self) 
        # print('other:%s'%other) 
        return int(self)+int(other) 
        
    def __radd__(self, other): 
        print('this is radd') 
        return int.__radd__(self,other) 
    
a=MyInt(100) 
b=MyInt(200) 
# print(a+b) 
# print(b+a) 
# print(a+1) # a.__add__(1) 
print(1+a) #

六 补充

add:+ 
sub:- 
mul:* 

truediv:/ 
floordiv:// 
mod:% 
pow:** 

lshift:<< 
rshift:>> 

and:& 
xor:^ 
or:| 

七 和属性相关的魔法方

1. __getattr__(self,name) 
    当访问一个属性,该属性不存在时,自动调用该方法 
2. __getattribute__(self,name) 
    只要访问属性,自动调用该方法
3. __setattr__(self,name,value) 
    设置属性时,会自动调用该方法 
4. __delattr__(self,name) 
    删除属性时,会自动调用该方法 
    
class A(object): 
    age=18 
    def __init__(self): 
        self.hehe=100 
    
    def __getattribute__(self, item): 
        print('this is getattribute') 
        return super().__getattribute__(item) 
        # return '您想找的属性存在,但就不告诉你'
    
    def __getattr__(self, item): 
        print('this is getattr')
        return '该属性不存在' 
    
    def __setattr__(self, key, value): 
        print('this is setattr') 
        super().__setattr__(key,value)
    
    def __delattr__(self, item): 
        print('this is delattr') 
        # super().__delattr__(item) 
        # del self.__dict__[item] 
    
a=A() 
# print(a.age) 
# print(a.hehe)
# print(a.age) 
# a.age=20 
# print(a.age) 
del a.hehe
# print(a.hehe) 

八 描述符

描述符:descriptor --- 是Python2.2版本引入的 是Python特有的  

1. 是一个类实现了__get__(),__set__(),__delete__()三个方法中至少一个方法的类,该类则称之为描 述符(描述符类)
2. 作用: 
    更加真实的将一个对象模拟成一个属性 
3. 使用: 
    描述符的使用,至少需要两个类,通过描述符类创建的实例对象,作为另一个类的类属性 
    另一个类:拥有者类owner 
    描述符类:slave类(佣人类)---描述符 
4. 方法: 
1. __get__(self,instance,owner) 
    拥有者类访问自己的属性时,自动调用描述符类的get方法 
2. __set__(self,instance,value) 
    拥有者类设置自己的属性时,自动调用描述符类的set方法 
3. __delete__(self,instance) 
    拥有者类删除自己的属性时,自动调用描述符类的delete方法 
    
self:指代当前对象(self一定是描述符对象) 
instance:拥有者的实例对象 
owner:拥有者的类对象 

class A: 
    def __init__(self,hehe): 
        self.hehe=hehe 

    def __get__(self,instance,owner): 
        print('this is get method') 
        return self.hehe

    def __set__(self,instance,value):
        print('this is set method') 
        self.hehe=value 

    def __delete__(self, instance): 
        print('this is delete method') 
        del self.hehe 
    
class B: 
    age=A(18)
    
b=B() 
print(b.age)
b.age=20 
print(b.age) 

九 描述符的作用

1. 代码书写更加优雅 
2. 提高代码的可重用性 
3. 更加真实的将一个对象模拟成属性 

class Score: 
def __get__(self,instance,owner): 
    return self.score 

def __set__(self,instance,value): 
    if 100>=value>=0: 
        self.score=value 
    else: print('输入有误') 

class CheckScore: 
    score=Score() 
    def __init__(self,score):
        self.score=score 
        
    def check(self): 
        if self.score>=60: 
        return '及格' 
        else: 
        return '不及格' 

a=CheckScore(30) 
a.score=80 
print(a.check()) 


补充 :
property是一个描述符,底层实现如下: 

class MyProperty: 
    def __init__(self,fget=None,fset=None,fdel=None,doc=None): 
    self.fget=fget 
    self.fset=fset 
    self.fdel=fdel 
    
    def __get__(self, instance, owner): 
        return self.fget(instance) 

    def __set__(self, instance, value): 
        self.fset(instance,value)

    def __delete__(self, instance): 
        self.fdel(instance) 
    
class A: 
    def __init__(self,age): 
        self.__age=age 
        
    def setAge(self,newAge): 
        self.__age=newAge 
        
    def getAge(self): 
        return self.__age 
        
    def delAge(self):
        del self.__age 
        
    x=MyProperty(getAge,setAge,delAge) 
a=A(18) 
print(a.x) 
a.x=20 
print(a.x) 
del a.x 
print(a.x) 

十 定制序列

1. 协议:protocols --- 接口(标准) 
2. 定制序列协议: 
    1. 不可变类型协议 
        __len__() 
        __getitem__() 
    2. 可变类型协议 
        __len__() 
        __getitem__() 
        __setitem__() 
        __delitem__() 
    
# class MyList: # 不可变序列
    # def __init__(self,*args):
        # self.l=[i for i in args] 
# 
    # def __len__(self): 
        # return len(self.l) 
# 
    # def __getitem__(self, item): 
        # return self.l[item] 
# 
# l=MyList(1,2,3,4,5) 
# print(len(l)) 
# print(l[3]) 

class MyList: # 不可变序列
    def __init__(self,*args): 
        self.l=[i for i in args] 
        
    def __len__(self):
        return len(self.l) 
        
    def __getitem__(self, item): # item:下标
        return self.l[item]
        
    def __setitem__(self, key, value): # key:下标 value:值 
    self.l[key]=value 
    
    def __delitem__(self, key): 
    del self.l[key] 

l=MyList(1,2,3,4,5)
print(len(l)) 
print(l[3]) 
l[0]=100 
print(l.l) 

十一 迭代器

可迭代对象中包含迭代器 
1. 迭代器是一个特殊的可迭代对象 
2. 迭代器是自己的迭代器 
3. 任何实现了__iter__ 和__next__方法的对象

# 斐波那契数列 
# result=int(input('请输入想要查询的项数'))
# 
# def fun(n): 
    # count = 0 
    # a, b = 0, 1 
    # while count < n:
        # count += 1 
        # print(a) 
        # a, b = b, a + b 
# fun(result) 

class Fib: 
    def __init__(self): 
        self.a,self.b=0,1 
        
    def __iter__(self): 
        return self 
        
    def __next__(self): 
        self.a,self.b=self.b,self.a+self.b 
        return self.a 

f=Fib() 
for i in range(12): 
     # print(next(f)) 
     print(f.__next__())
     
     
补充
1. __str__ 
    使用print函数打印对象时,会自动调用该方法 
2. __repr__ 
    在交互式界面直接显示对象时,会自动调用该方法