魔术方法

魔术方法

特殊属性

属性含义
__name__类,函数,方法等名字
__module__类,函数,实例,方法等,所在的模块名
__class__对象或类所属的类
__bases__类的基类元组,顺序为他们在基类列表中出现的顺序
__doc__类,函数的文档字符串,如果没有定义则为None
__mro__类的mro,class.mro()返回的结果保存在__mro__中。(方法查找顺序)
__dict__类或实例的属性,可写的字典

查看属性

方法意义
__dir__返回类或者对象的所有成员名称列表。
dir()函数操作实例就是调用__dir__()方法

如果dir([obj])参数obj包含方法__dir__(),该方法就将被调用,如果参数obj不包含该方法,那么它将最大限度的搜集属性信息。

dir(obj)对于不同类型的对象obj具有不同的行为:

  • 如果对象是模块对象,返回的列表包含魔魁啊的属性名和变量名
  • 如果对象是类型或者是类对象,返回的列表包含类的属性名,及他的祖先类的属性名
  • 如果是类的实例
    • __dir__方法,返回可迭代对象的返回值
    • 没有__dir__方法,则尽可能收集是的属性名,类的属性和祖先类的属性名
  • 如果obj不写,返回列表包含内容也有不同
    • 在模块中,返回模块的属性和变量名
    • 在函数中,返回本地作用于的变量名
    • 在方法中,返回本地作用域的变量名

内建函数

  • locals()返回当前作用于中的变量字典
  • globals()当前模块全局变量的字典

魔术方法

分类:

  • 创建,初始化,销毁

    • __new__
    • __init__
    • __del__
  • 可视化

  • hash

  • bool

  • 运算符重载

  • 容器和大小

  • 可调用对象

  • 反射

  • 描述器

  • 其他杂项

实例化

方法意义
__new__实例化一个对象,该方法需要返回一个值,如果该值不是cls的实例,则不会调用__init__,该方法永远是静态方法
class A:
	def __new__(cls,*args,**kwargs):
		print(args,kwargs)
		print(cls)
		return super().__new__(cls)

该方法很少使用,即使创建了该方法,也会使用return super().__new__(cls)基类object的方法来创建实例并返回。

构造器

方法意义
__init__实例化后会做出厂配置,一般继承类自身实现了该方法,还应调用父类的该方法
class P:
    def __init__(self):
        self.a = 50
    
class A(P):
    def __init__(self):
        super().__init__()
        
a = A()
a.__dict__#{'a':50}

析构器

方法意义
__del__对象销毁时会调用该方法,做清理工作

可视化

方法意义
__str__str,format,print,函数调用需要返回对象的字符串表达,如果没有定义,就去调用__repr__方法返回字符串表达,如果__repr__也没有定义,就直接返回对象的内存地址信息
__repr__内建函数repr()对uige对象获取字符串表达
调用__repr__方法返回字符串表达,如果__repr__也没有定义,就直接返回对象的内存地址信息
__bytes__bytes()函数调用,返回一个对象的bytes表达,即返回bytes对象
class A:
    def __init__(self):
        self.a = 100
     
    def __repr__(self):
        return f"repr {self.a}"
    
    def __str__(self):
        return f"str {self.a}"
    
    def __bytes__(self):
        return self.a.encode()
    
a = A()
print(a,[a])
print('{}'.format(a))
print(bytes(a))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RO8v82bW-1572778904434)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571889091345.png)]

注意不能通过是否带有引号来判断输出值类型,类型判断需要使用type或isinstance

hash

方法意义
__hahs__内建函数hash()调用的返回值,返回一个整数,如果定义这个方法该类的实例就可以hash,如果只有hash没有eq,那么遇到哈希冲突时就不知道两个对象是否相等,此时就不能够去重,只能作为set或dict的key
__eq__对应==操作符,判断2个对象内容是否相等,返回bool值
定义了这个方法,如果不提供__hahs__,那么实例将不可hash

思考:

1.list类实例为什么不可hash?

  • 所有类都继承object,而该类实现了hash,所以list类就覆盖了obj的hash方法,实现__hash__ = None

2.functools.lru_cache使用到的functools._HashedSeq类继承自list,为什么可以hash?

  • 该类中实现的hash返回值为哈希一个元组的值

练习

设计二位坐标类Point,使其可以成为hash的类型,不比较两个坐标的实例是否相等

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __hash__(self):
        return hash((self.x,self.y))
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    def __repr__(self):
        return f"{self.x,self.y}"
    
p1 = Point(4,5)
p2 = Point(4,5)
{p1,p2}#->{(4,5)}

bool

方法意义
__bool__内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值。没有定义__bool__(),就找__len__()返回长度,非零为真。如果没有__len__()那么所有实例返回真

运算符重载

operator模块提供以下的特殊方法,可以将类的实例使用下面的操作符来操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KBZSN8JB-1572778904436)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571900449500.png)]

实现两个实例相减

class A:
    def __init__(self,x,y):
        self.x = x
        self.y = y
        
    def __sub__(self,other):
        return A(self.x-other.x,self.y-other.y)
    
    def __repr__(self):
        return f"{self.x,self.y}"
    
a = A(4,5)
a - a#->(0, 0)

__isub__方法定义,一般会in-place就地修改
如果没有定义,则会调用__sub__

实现了__eq__可以推断出不等
实现了__gt__可以推断出小于
实现了__ge__可以推断出小于等于
也就是用了3个方法,就可以把剩下的推断出结果。

运算符重载应用场景

往往是用面向对象实现的类,需要做大量的运算,而运算符是这种运算在数学上最常见的表达式,例如上例中的对 - 进行了运算符重载,实现了类的二元操作
提供运算符重载,比直接提供加法要更加适合该领域内使用的习惯。
int类,几乎实现了所有的操作符,可以作参考。

容器相关方法

方法意义
__len__内建函数len(),返回对象的长度(>=0的整数),如果把对象当作容器类型看,就如同list或者dict
bool()函数调用的时候,如果没有实现__bool__()则会调用该方法,
__iter__迭代容器时,调用,返回一个新的迭代器对象
__contains__in 成员运算符,没有实现,就调用__iter__方法遍历
__getitem__实现self[key]访问,序列对象,key接受整数为索引,或者切片,对于set或者dict,key为hashable。key不存在引发KeyError
__setitem____getitem__的访问类似,是设置值的方法
__missing__字典或其子类使用__getitem__调用时,key不存在执行该方法

可调用对象

方法意义
__call__类中定义一个该方法,实例就可以像函数一样调用

可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用

练习:
定义一个fib数列类,方便调用,计算第n项,增加迭代方法,返回数列长度,和索引

class Fib:
    def __init__(self):
        self.items = [0,1,1]
        
    def __iter__(self):
        return iter(self.items)
    
    def __len__(self):
        return len(self.items)
        
    def __call__(self,index):
        if index < 0:
            raise IndexError
        for i in range(len(self),index + 1):
            self.items.append(self.items[i-1] + self.items[i-2])
        return self.items[index]
    
    def __str__(self):
        return str(self.items)

f = Fib()
print(f(6))
 raise IndexError
    for i in range(len(self),index + 1):
        self.items.append(self.items[i-1] + self.items[i-2])
    return self.items[index]

def __str__(self):
    return str(self.items)

f = Fib()
print(f(6))


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值