Python中类的特殊属性与魔术方法

2024-08-24 13:48

本文主要是介绍Python中类的特殊属性与魔术方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • Python中类的特殊属性与魔术方法
    • 特殊的属性
      • 查看属性
      • 特殊函数
    • 魔术方法
      • 实例化
      • 可视化
      • 可哈希(hash)与等等运算符(==)
      • bool
      • 运算符重载
        • 1.比较运算符重载
        • 2.算术运算符重载
        • 3.反向运算符
        • 4.赋值运算符的重载
        • 运算符重载的应用场景
        • functools.total_ordering装饰器
      • 容器相关方法
      • 可调用对象

Python中类的特殊属性与魔术方法

特殊的属性

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

查看属性

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

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

  • dir(obj) #如果没有参数,返回当前局部作用域中的名称列表。使用参数时,尝试返回该对象的有效属性列表。
    • dir(obj)相当于调用obj.__dir__()的方法
    • 对于不同类型的对象obj具有不同的行为:
    1. 如果对象是模块对象,返回的列表包含模块的属性名和变量名
    2. 如果对象是类型或者说是类对象,返回的列表包含类的属性名,及它祖先类的属性名。
    3. 如果是类的实例
      • 有__dir__方法,返回可迭代对象的返回值
      • 没有__dir__方法,尽可能收集实例的属性名、类的属性和祖先类的属性名
    4. 如果obj不写,返回列表包含内容不同
      • 在模块中,返回模块的属性和变量名
      • 在类中,返回类本地作用域的属性和变量名
      • 在函数中,返回本地作用域的变量名
      • 在方法中,返回本地作用域的变量名
  1. 示例1,不同作用域中的dir返回值 返回局部作用域中的名称列表

    • animal.py文件信息如下:
    #animal.py文件信息如下:
    class Animal:
    x = 123
    def __init__(self,name):self._name = nameself.__age = 18self.weight = 20print("animal.py names = {}".format(dir()))
    
    • cat.py文件信息如下:
    
    #cat.py文件信息如下:
    import animal
    from animal import Animalclass Cat(Animal):x = "cat"y = "abcd"print("Cat class 类中 names = {}".format(dir()))z = "xyz"def show(self):a = selfb = 10print("show方法中 names = {}".format(dir()))print("cat.py names = {}".format(dir()))
    cat = Cat("苗")
    cat.show()
    

    执行cat.py文件输出结果如下:
    class4_001

  2. 示例2:类型中的__dir__

    • 如果对象是类型或者说是类对象,返回的列表包含类的属性名,及它祖先类的属性名。
    • dir(类) 等价于调用type.__dir__(类)方法。应为类型type
    class Animal:x = 123def __init__(self,name):self._name = nameself.__age = 18self.weight = 20class Cat(Animal):x = "cat"z = "xyz"def show(self):a = selfb = 10print("show方法中 names = {}".format(dir()))class Dog(Animal):def __dir__(self):return ["dog"]  #__dir__方法必須返回可迭代对象#Cat类的dir 会调用type中的__dir__方法返回类Cat的dir,应为Cat是类
    print(type(Cat))
    print("Cat 类的 names = {}".format(dir(Cat)))
    #相当于排序后的集合
    print("Cat 类的 names = {}".format(sorted((Cat.__dict__.keys()| Animal.__dict__.keys() | object.__dict__.keys()))))
    print("Dog 类的 names = {}".format(dir(Dog)))
    

    class4_003

  3. 示例3:示例属性中的__dir__ (尽可能的最大收集实例属性的属性名)

    • dir(self) 等价于 self.__dir__ #self为实例对象
    • 如果类中重写了__dir__方法,那么dir(self)调用的返回值是重写的__dir__方法的返回值
    • __dir__方法的返回值必须是一个可迭代对象
    class Animal:x = 123def __init__(self,name):self._name = nameself.__age = 18self.weight = 20class Cat(Animal):x = "cat"z = "xyz"def show(self):a = selfb = 10print("show方法中 names = {}".format(dir()))class Dog(Animal):def __dir__(self):return ["dog"]  #__dir__方法必須返回可迭代对象cat = Cat("苗")
    dog = Dog("旺旺")#注意:dir(cat) 等价于cat.__dir__()
    print("cat 实例属性,dir() = {}".format(dir(cat)))
    print("cat 的内建函数__dir__ = {}".format(sorted(cat.__dir__())))
    print("dog 实例的实例属性 dir() = {}".format(dir(dog)))
    print("dog 实例的实例属性 __dir__() = {}".format(dog.__dir__()))
    

    class4_002

特殊函数

  • locals() 返回当前作用域中的变量字典
  • globals() 当前模块全局变量的字典
class Animal:x = 123def __init__(self,name):self._name = nameself.__age = 18self.weight = 20class Cat(Animal):x = "cat"z = "xyz"print("Cat 类中 globals = {}".format(sorted(globals().keys())))print("Cat 类中 dir = {}".format(dir()))print("Cat 类中 locals = {}".format(sorted(locals().keys())))def show(self):a = selfb = 10print("show方法中 globals = {}".format(sorted(globals().keys())))print("show方法中 dir = {}".format(dir()))print("show方法中 locals = {}".format(sorted(locals().keys())))class Dog(Animal):def __dir__(self):return ["dog"]  #__dir__方法必須返回可迭代对象print("Dog 类中 globals = {}".format(sorted(globals().keys())))print("Dog 类中 dir = {}".format(dir()))print("Dog 类中 locals = {}".format(sorted(locals().keys())))print("cat.py 模块中 globals = {}".format(sorted(globals().keys())))
print("cat.py 模块中 locals = {}".format(sorted(locals().keys())))
print("cat.py 模块中 dir = {}".format(dir()))
cat = Cat("苗")
cat.show()

class4_004

魔术方法

实例化

方法意义
__new__(self,*args,**kwargs)示例化一个对象
该方法需要返回一个值,如果该值不少cls的实例,则会调用__init__
该方法永远都是静态方法
调用new方法前还没有实例对象,正常调用完成后会生成实例对象。
__init__(self)对实例进行初始化,通常用来设置实例属性,基本配置信息等。
调用init方法前已经存在实例对象
__del__(self)实例的引用次数为0时调用。即删除实例时调用。
当系统自动调用del方法后实例已经没有对象记录,等着垃圾回收gc来清理。
  • new的简单示例(init和del方法在前面文章中已经讲到,这里不做演示)
class A:def __new__(cls,*args,**kwargs):print(cls)print(args)print(kwargs)# return super().__new__(cls)# return 1return Nonedef __init__(self,name):self.name = namea = A()
print(a)

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

可视化

方法等效的内建函数含义
__str__(self)str()str()函数、format()函数、print()函数调用,需要返回对象的字符串表达式。如果没有定义,就去调用__repr__方法返回字符串的表达。如果__repr__没有定义,就直接返回对象的内存地址信息
__repr__(self)repr()内建函数repr()对一个对象获取字符串表达。
调用__repr__方法返回字符串表达,如果__repr__也没有定义,就直接返回object的定义,显示内存地址信息。
__bytes__(self)bytes()bytes()函数调用,返回一个对象的bytes表达,即返回bytes对象
  • 简单示例:
class A:def __init__(self,name,age=18):self.name = nameself.age = agedef __repr__(self):return "repr:{},{}".format(self.name,self.age)def __str__(self):return "str:{},{}".format(self.name,self.age)def __bytes__(self)->bytes:import jsonreturn json.dumps(self.__dict__).encode()a = A("tom")
print(a) #print函数会默认调用对象的__str__ 等价于a.__str__
print([a]) #等价于[a].__str__  但[]里面会默认调用a的__repr__即等价于[a.__repr__()].__str__()
print([a.__repr__()].__str__())
print(bytes(a)) #等价于str(bytes(a))  等价于 a.__bytes__().__str__()
print( a.__bytes__().__str__())

class4_006

可哈希(hash)与等等运算符(==)

方法等效的内建函数意义
__hash__(self)hash()内建函数hash()调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash。
__eq__(self)==对等等操作符,判断2个对象是否相等,返回值bool值
定义了这个方法,如果不提供__hash__方法,那么实例对象将不可hash了。
  • __hash__ 方法只是返回一个hash值作为set的key,但是 去重 ,还需要 __eq__ 来判断2个对象是否相等。 hash值相等,只是hash冲突,不能说明两个对象是相等的。
  • 因此,一般来说提供 __hash__ 方法是为了作为set或者dict的key,如果 去重 要同时提供 __eq__ 方法。
  • 判断对象是否可哈希isinstance(obj, collections.Hashable),obj为需要判断的对象。
  1. 示例1:

    • 对象的hash值取决于对象的__hash__函数的返回值
    • 如果使用"=="运算符,其结果为__eq__函数的返回值
    class A:def __init__(self,name,age=18):self.name = nameself.age = agedef __hash__(self):return hash("{},{}".format(self.name,self.age))def __repr__(self):return "repr {} {}".format(self.name,self.age)def __eq__(self,other):# return "abc"  #如果返回字符串,那么print(b==a)的结果就是返回的字符串return True__str__ = __repr__a = A("旺旺")
    b = A("哈哈")
    print(a)
    print(hash(a),a.__hash__())
    print(hash(b),b.__hash__())
    print(b==a) #等价于 b.__eq__(a)
    

    class4_007

  2. 示例2:

    • set字典中唯一性先判断对象是否可hash,在判断hash值是否相等以及是否“==”来判断新增加的值是否已经存在
    class stt:def __repr__(self):return "("+",".join("{}:{}".format(x,y) for x,y in self.__dict__.items())+")"class Point(stt):def __init__(self,x,y):self.x = xself.y = yclass Point2(stt):def __init__(self,x,y):self.x = xself.y = ydef __hash__(self):return hash("{},{}".format(self.x,self.y))def __eq__(self,other):return self.x==self.x and self.y==self.yprint(set([Point(1,2),Point(1,2)]))
    print(set([Point2(1,2),Point2(1,2)]))
    

    class4_008

  3. 示例3:

    • 扩展
    • hash值对int类型求值是用一个大整数取摸(%)计算得到的结果
    • hash值的整数为:【2305843009213693951】
    • 下面示例求出hash值对应的大整数是多少
    # %%timeit
    def getHashbigInt():i = 0ii = 2 #增量while ii >1:i = i+iiif hash(i)==i:ii = ii*2 #增量加大else: #调整增量i = i-ii  #i值还原ii = ii//2 #增量缩小return i+1hig = getHashbigInt()
    print(hig)
    print(hash(hig-1),hash(hig),hash(hig+1))
    

    class4_009

bool

方法对应的内建函数意义
__bool__(self)bool()内建函数bool(),或者对象放在逻辑表达式的位置,调整这个函数返回布尔值。
如果对象没有定义__bool__(),就找__len__()返回长度,非0为真
如果__len__()也没有定义,那么所有实例都返回真
  • if obj等价于 if obj.__bool__()
  • bool(obj)等价于 obj.__bool__()
class A:passclass B:def __bool__(self)->bool:#注意:bool函数的返回值必须是bool类型,否则会报错return Falseclass C:def __len__(self):return 1class D:def __len__(self):return 0a = A()
b = B()
c = C()
d = D()
print(bool(a),bool(b),bool(c),bool(d))
if a: #if a等价于 if a.__bool__()print("this is a = true")
if b:print("this is b = true")
if c:print("this is c = true")
if d:print("this is d = true")

class4_0010

运算符重载

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

1.比较运算符重载
特殊方法运算符含义
__lt__(self,other)<小于运算符等效符调用的对应方法
obj1 < obj2时调用obj1.__lt__(obj2)
__le__(self,other)<=小于等于运算符等效符调用的对应方法
obj1 <= obj2时调用obj1.__le__(obj2)
__eq__(self,other)==等等运算符等效调用的对应方法
obj1 == obj2时调用obj1.__eq__(obj2)
__gt__(self,other)>大于运算符等效调用的对应方法
obj1 > obj2时调用obj1.__gt__(obj2)
__ge__(self,other)>=大于等于运算符等效调用的对应方法
obj1 >= obj2时调用obj1.__ge__(obj2)
__ne__(self,other)!=不等运算符等效调用的对应方法
obj1 != obj2时调用obj1.__ne__(obj2)

注意:

  • 完成小于方法,对应的大于方法可以不用重新也能使用。反之也一样。
  • 完成小于等于方法,对应的大于等于方法可以不用重写。反之也一样。
  • 简单示例:
class A:def __init__(self,age = 18):self.age = agedef __lt__(self,other): #完成小于方法,大于方法也可以使用return self.age < other.agedef __ge__(self,other): #完成大于等于方法,小于等于方法也可以使用return self.age >= other.agedef __eq__(self,other): #完成return self.age == other.agea1 = A()
a2 = A(20)
a3 = A(10)
a4 = A()
print("a1 < a2 ,{}".format( a1 < a2 ))
print("a1 > a2 ,{}".format( a1 > a2 ))
print("a1 >= a2 ,{}".format( a1 >= a2 ))
print("a1 <= a2 ,{}".format( a1 <= a2 ))
print("a1 <= a4 ,{}".format( a1 <= a4 ))
print("a1 == a4 ,{}".format( a1 == a4 ))

class4_0011

2.算术运算符重载
特殊方法运算符含义
__add__(self,other)+加法运算等效调用的对应方法
obj1 + obj2时调用obj1.__add__(obj2)
__sub__(self,other)-减法运算等效调用的对应方法
obj1 - obj2时调用obj1.__sub__(obj2)
__mul__(self,other)*乘法运算等效调用的对应方法
obj1 * obj2时调用obj1.__mul__(obj2)
__truediv__(self,other)/除法运算等效调用的对应方法
obj1 / obj2时调用obj1.__truediv__(obj2)
__mod__(self,other)%**取摸运算(取余数)**等效调用的对应方法
obj1 % obj2时调用obj1.__mod__(obj2)
__floordiv__(self,other)//整除运算(向下取整)等效调用的对应方法
obj1 // obj2时调用obj1.__floordiv__(obj2)
__pow__(self,other)**
pow(x,n)
次幂运算等效调用的对应方法。也等价于pow(x,n)方法
obj1 ** obj2时调用obj1.__pow__(obj2)
__divmod__(self,other)divmod(obj1,obj2)获取数的商和余数组成的元组等效的对应方法
divmod(obj1,obj2)时调用obj1.__divmod__(obj2)
__matmul__(self,other)@矩阵运算符等效调用的对应方法
obj1 @ obj2时调用obj1.__matmul__(obj2)
__and__(self,other)&与运算符等效的对应方法
obj1 & obj2时调用obj1.__and__(obj2)
__or__(self,other)|或运算符等效的对应方法
obj1 | obj2时调用obj1.__or__(obj2)
__xor__(self,other)^异或运算符等效的对应方法
obj1 ^ obj2时调用obj1.__xor__(obj2)
__lshift__(self,other)<<左移运算符等效的对应方法
obj1 << obj2时调用obj1.__lshift__(obj2)
__rshift__(self,other)>>右移运算符等效的对应方法。
obj1 >> obj2时调用obj1.__rshift__(obj2)
__invert__(self,other)~按位取反运算符等效的对应方法
在~obj时调用obj.__invert__()
  • 简单示例:
class A:def __init__(self,age=18):self.age = agedef __repr__(self):return "(age = {})".format(self.age)def __add__(self,other):return A(self.age + other.age)a1 = A(15)
a2 = A(18)
print(a1,a2,a1+a2)

class4_0012

3.反向运算符
  • obj1 + obj2中如果obj1不支持+操作,那么obj1.__add__(self,other)的返回值应该是NotImplemented,此时系统会调用obj2中的__radd__(self,other)方法来实现运算。即执行obj2.__radd__(obj1)
特殊方法运算符含义
以下示例中。按照__iadd__方法来举例:
obj1中必须没有定义对应的方法__add__。或者返回值为NotImplemented。才会调用obj2.__radd__(obj1)来完成运算
__radd__(self,other)+加法运算等效调用的对应方法
obj1 + obj2时调用obj2.__radd__(obj1)
__rsub__(self,other)-减法运算等效调用的对应方法
obj1 - obj2时调用obj2.__rsub__(obj1)
__rmul__(self,other)*乘法运算等效调用的对应方法
obj1 * obj2时调用obj2.__rmul__(obj1)
__rtruediv__(self,other)/除法运算等效调用的对应方法
obj1 / obj2时调用obj2.__rtruediv__(obj1)
__rmod__(self,other)%**取摸运算(取余数)**等效调用的对应方法
obj1 % obj2时调用obj2.__rmod__(obj1)
__rfloordiv__(self,other)//整除运算(向下取整)等效调用的对应方法
obj1 // obj2时调用obj2.__rfloordiv__(obj1)
__rpow__(self,other)**
pow(x,n)
次幂运算等效调用的对应方法。也等价于pow(x,n)方法
obj1 ** obj2时调用obj2.__rpow__(obj1)
__rdivmod__(self,other)divmod(obj1,obj2)获取数的商和余数组成的元组等效的对应方法
如果obj1没有__divmod__方法,或者返回NotImplemented,则会调用obj2.__rdivmod__(obj1)
__rmatmul__(self,other)@矩阵运算符等效调用的对应方法
obj1 @ obj2时调用obj2.__rmatmul__(obj1)
__rand__(self,other)&与运算符等效的对应方法
obj1 & obj2时调用obj2.__rand__(obj1)
__ror__(self,other)|或运算符等效的对应方法
obj1 | obj2时调用obj2.__ror__(obj1)
__rxor__(self,other)^异或运算符等效的对应方法
obj1 ^ obj2时调用obj2.__rxor__(obj1)
__rlshift__(self,other)<<左移运算符等效的对应方法
obj1 << obj2时调用obj2.__rlshift__(obj1)
__rrshift__(self,other)>>右移运算符等效的对应方法。
obj1 >> obj2时调用obj2.__rrshift__(obj1)
  • 简单流程运行图:
    a+b

  • 简单示例:

class A:def __init__(self,age=18):self.age = agedef __repr__(self):return "(age = {})".format(self.age)def __add__(self,other):return A(self.age + other.age)def __radd__(self,other):return A(self.age + other.age)class B:def __init__(self,age= 18):self.age = agedef __repr__(self):return "(age = {})".format(self.age)a = A(10)
b = B(15)
print(a+b)
print(b+a)

class4_0013

4.赋值运算符的重载
特殊方法运算符含义
__iadd__(self,other)+=加等赋值运算等效调用的对应方法
obj1 += obj2时调用obj1 = obj1.__iadd__(obj2)
__isub__(self,other)-=减等赋值运算等效调用的对应方法
obj1 -= obj2时调用obj1 = obj1.__isub__(obj2)
__imul__(self,other)*=乘等赋值运算等效调用的对应方法
obj1 *= obj2时调用obj1 = obj1.__imul__(obj2)
__itruediv__(self,other)/=除等赋值运算等效调用的对应方法
obj1 /= obj2时调用obj1 = obj1.__itruediv__(obj2)
__imod__(self,other)%=取模等赋值运算等效调用的对应方法
obj1 %= obj2时调用obj1 = obj1.__imod__(obj2)
__ifloordiv__(self,other)//=整除等赋值运算符等效调用的对应方法
obj1 //= obj2时调用obj1 = obj1.__ifloordiv__(obj2)
__ipow__(self,other)**=次幂等运算符等效调用的对应方法
obj1 **= obj2时调用obj1 = obj1.__ipow__(obj2)
__imatmul__(self,other)@=矩阵等赋值运算等效调用的对应方法
obj1 @= obj2时调用obj1 = obj1.__imatmul__(obj2)
__iand__(self,other)&=与等赋值运算等效的对应方法
obj1 &= obj2时调用obj1 = obj1.__iand__(obj2)
__ior__(self,other)|=或等赋值运算等效的对应方法
obj1 |= obj2时调用obj1 = obj1.__ior__(obj2)
__ixor__(self,other)^=异或等赋值运算等效的对应方法
obj1 ^= obj2时调用obj1 = obj1.__ixor__(obj2)
__ilshift__(self,other)<<=左移等赋值运算等效的对应方法
obj1 <<= obj2时调用obj1 = obj1.__ilshift__(obj2)
__irshift__(self,other)>>=右移等赋值运算等效的对应方法
obj1 >>= obj2时调用obj1 = obj1.__irshift__(obj2)
  • 注意:例如:obj1 += obj2中,如果obj1没有对应的加法赋值运算__iadd__那么等式会转换成obj1 = obj1 + obj2obj1 = obj1.__add__(obj2),其他赋值也同样适用。
  • 简单示例01:
class A:def __init__(self,age=18):self.age = agedef __repr__(self):return "(age = {})".format(self.age)def __add__(self,other):return A(self.age + other.age)def __iadd__(self,other):self.age = self.age + other.agereturn selfa1 = A(15)
a2 = A(18)
print(a1,a2,a1+a2)
a1 += a2
print(a1)

class4_0014

  • 简单示例02:
class A:def __init__(self,age=18):self.age = agedef __repr__(self):return "(age = {})".format(self.age)def __add__(self,other):return A(self.age + other.age)a1 = A(15)
a2 = A(18)
print(a1,a2,a1+a2)
a1 += a2  #如果没有__iadd__方法,会转换成 a1 = a1+a2来调用
print(a1)

class4_015

  • 综合示例:完成Point类设计,实现判断点相等的方法,并完成向量的加法
    1. 在直角坐标系里面,定义原点为向量的起点。两个向量和与差的坐标分别等于这两个向量相应坐标的和与差若向量 的表示为(x,y)形式。
    2. A(X1,Y1) B(X2,Y2),则A+B=(X1+X2,Y1+Y2),A-B=(X1-X2,Y1-Y2)
class Point:def __init__(self,x:int,y:int):self.x = xself.y = ydef __add__(self,other):return Point(self.x+other.x,self.y+other.y)# def __iadd__(self,other):#     self.x += other.x#     self.y += other.y#     return selfdef __sub__(self,other):return Point(self.x-other.x,self.y-other.y)# def __isub__(self,other):#     self.x -= other.x#     self.y -= other.y#     return selfdef __repr__(self):return "<Point {},{}>".format(self.x,self.y)p1 = Point(5,6)
p2 = Point(1,2)
print(p1+p2,p1-p2)
p1-=p2
print(p1)

class4_0016

运算符重载的应用场景

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

functools.total_ordering装饰器

__lt__ , __le__ , __eq__ , __gt__ , __ge__ 是比较大小必须实现的方法,但是全部写完太麻烦,使用 @functools.total_ordering 装饰器就可以大大简化代码。
但是要求 __eq__ 必须实现,其它方法 __lt__ , __le__ , __gt__ , __ge__ 实现其一

from functools import total_ordering@total_ordering
class Person:def __init__(self,name,age):self.name = nameself.age = agedef __eq__(self,other):return self.age == other.agedef __gt__(self,other):return self.age > other.agetom = Person("tom",20)
jerry = Person("jerry",16)
print(tom > jerry)
print(tom < jerry)
print(tom >= jerry)
print(tom <= jerry)

class4_0017

上例中大大简化代码,但是一般来说比较实现等于或者小于方法也就够了,其它可以不实现,所以这个装饰器只是 看着很美好,且可能会带来性能问题,建议需要什么方法就自己创建,少用这个装饰器。

class Person:def __init__(self,name,age):self.name = nameself.age = agedef __eq__(self,other):return self.age == other.agedef __gt__(self,other):return self.age >other.agedef __ge__(self,other):return self.age >= other.agetom = Person("tom",20)
jerry = Person("jerry",16)
print(tom > jerry)
print(tom < jerry)
print(tom >= jerry)
print(tom <= jerry)
print(tom == jerry)
print(tom != jerry)

class4_0018

  • __eq__等于可以推断不等于
  • __gt__大于可以推断小于
  • __ge__大于等于可以推断小于等于
    也就是用3个方法,就可以把所有比较解决了。

容器相关方法

方法对应的操作意义
__len__(self)len(obj)内建函数len(),返回对象的长度(>=0的整数),如果把对象当做容器类型看,就如同list或者dict。
bool()函数调用的时候,如果没有__bool__()方法,则会看__len__()方法是否存在,存在返回非0为真。
__iter__(self)for i in obj迭代容器时,调用,返回一个新的可迭代对象
__contains__(self,item)x in objin 成员运算符,没有实现,就默认调用__iter__方法遍历
__getitem__(self,key)obj[key]实现self[key]访问。序列对象,key接受整数为索引,或者切片。对于set和dict,key为可以hashable(即可哈希)。key不存在引发KeyError异常
__setitem__(self,key)obj[key] = value__getitem__的访问类似,是设置值的方法
__missing__(self,key)字典或其子类使用__getitem__()调用时,key不存在执行该方法
  • __missing__(self,key)例子:
class A(dict):def __missing__(self,key):print("键值对不存在。。{}".format(key))return 0a = A()
a["a"] = 10
print(a["a"])
print(a["b"])

class4_0019

  • 简单综合示例:不使用继承,实现一个容器
class Goods:def __init__(self,name):self.name = namedef __repr__(self):return "<Goods name = {}>".format(self.name)class Cart:def __init__(self):self.__goods = list()def __len__(self):return len(self.__goods)def add(self,good:Goods):self.__goods.append(good)def __add__(self, other):self.add(other)return selfdef __iter__(self):# yield from self.__goodsreturn iter(self.__goods)def __getitem__(self, item):return self.__goods[item]def __setitem__(self, key, value):self.__goods[key] = valuedef __repr__(self):return str(self.__goods)gd = Goods("棒棒糖")
gd2 = Goods("宫保鸡丁")
cat = Cart() + gd + gd2
cat.add(Goods("火爆鸡精"))
print(cat)

class4_0020

可调用对象

Python中一切皆对象,函数也不例外。

def foo():print(foo.__module__,foo.__name__)foo()
#等价于
foo.__call__()

class4_0021

函数即对象,对象foo加上(),就是调用此函数对象的 __call__() 方法

方法等效意义
__call__(self)obj()类中定义一个该方法,类的实例就可以像函数一样调用
  • 示例1:可调用对象,定义一个类,并实例化得到其实例,将实例像函数一样调用。
class Adder:def __call__(self,*args):self.sum = sum(args)return self.sumadder = Adder()
print(adder(4,5,6,3,2))
print(adder.sum)

class4_0022

  • 示例2:定义一个斐波拉契数列,方便调用,计算第n项。
    1. 增加迭代的方法、返回容器长度、支持索引的方法。
class Xdd_Fib:"""斐波拉契数列类,获取第num个位置的斐波拉契数列。"""def __init__(self):self.fib = [0,1,1]def __len__(self):return len(self.fib)#类的实例可调用def __call__(self,num:int):if not isinstance(num,int):raise TypeError("num必须是int类型")if num<0:raise KeyError("选项错误,必须大于0")elif num<3:return self.fib[num]else:for i in range(len(self),num + 1):self.fib.append(self.fib[i-1]+self.fib[i-2])return self.fib[num]#类可迭代def __iter__(self):return iter(self.fib)def __repr__(self):return ",".join(map(str,self.fib))__str__ = __repr____getitem__ = __call__ #类可以像数组一样访问fib = Xdd_Fib()
print(fib(5),fib(6),fib(8))
print(fib)

class4_0023

这篇关于Python中类的特殊属性与魔术方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1102653

相关文章

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

C#中读取XML文件的四种常用方法

《C#中读取XML文件的四种常用方法》Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具,下面我们就来看看C#中读取XML文件的方法都有哪些吧... 目录XML简介格式C#读取XML文件方法使用XmlDocument使用XmlTextReader/XmlTextWr

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本