在Python中,所有以双下划线__
包起来的方法,统称为Magic Method(魔术方法) ,它是一种的特殊方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行。
魔术方法在类或对象的某些事件出发后会自动执行,让类具有神奇的“魔力”。如果希望根据自己的程序定制自己特殊功能的类,那么就需要对这些方法进行重写。
Python中常用的运算符、for循环、以及类操作等都是运行在魔术方法之上的。
__doc__
1 2 3 4 5 6 class Foo : """描述类信息,这个是工具类""" def func (self ): pass print (Foo.__doc__)
__module__ 和 __class__
__module__
表示当前操作的对象在那个模块
__class__
表示当前操作的对象的类是什么
test.py
1 2 3 class Person : def __init__ (self ): self.name = 'william'
main.py
1 2 3 4 5 from test import Personobj = Person print (obj.__module__) print (obj.__class__)
结果
1 2 test <class 'test.Person' >
__init__
1 2 3 4 5 6 class Person : def __init__ (self, name ): self.name = name self.age = 18 obj = Person('william' )
__del__
此方法一般无需定义,__del__
的调用是由解释器在进行垃圾回收时自动触发执行的
1 2 3 class Foo : def __del__ (self ): pass
__call__
__init__
方法的执行是由创建对象触发的,即:对象 = 类名()
;而对于 __call__
方法的执行是由对象后加括号触发的,即对象()
或者类()()
1 2 3 4 5 6 7 8 9 class Foo : def __init__ (self ): pass def __call__ (self, *args, **kwargs ): print ("__call__" ) obj = Foo() obj()
__dict__
类的实例属性属于对象;类中的类属性和方法属于类,即:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Province : country = "China" def __init__ (self, name, count ): self.name = name self.count = count def func (self, *args, **kwargs ): print ("func" ) print (Province.__dict__) obj1 = Province("山东" , 10000 ) print (obj1.__dict__)obj2 = Province("山西" , 20000 ) print (obj2.__dict__)
__str__
如果一个类定义了__str__
方法,那么打印对象时,默认输出该方法返回值
1 2 3 4 5 6 class Foo : def __str__ (self ): return 'william' obj = Foo() print ("当前对象返回值为: %s" %obj)
__repr__ 函数__str__
用于将值转化为适于人阅读的形式,而__repr__
转化为供解释器读取的形式,某对象没有适于人阅读的解释形式的话,__str__
会返回与__repr__
,所以print
展示的都是__str__
的格式。
默认情况下,__repr__
会返回和调用者有关的 类名+object at+内存地址
(<__main__.CLanguage object at 0x000001A7275221D0>)信息。当然,我们还可以通过在类中重写这个方法,从而实现当输出实例化对象时,输出我们想要的信息。
1 2 3 4 5 6 7 8 class CLanguage : def __init__ (self ): self.name = "C语言中文网" self.add = "http://c.biancheng.net" def __repr__ (self ): return "CLanguage[name=" + self.name +",add=" + self.add +"]" clangs = CLanguage() print (clangs)
结果
1 CLanguage[name=C语言中文网,add=http://c.biancheng.net]
__getitem__、__setitem__、__delitem__
用于索引操作,如字典。已上分别表示获取、设置、删除数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Foo : def __getitem__ (self, key ): print ("__getitem__" , key) def __setitem__ (self, key, value ): print ("__setitem__" , key, value) def __delitem__ (self, key ): print ("__delitem__" , key) obj = Foo() result = obj['k1' ] obj['k2' ] = 'william' del obj['k1' ]
我们可以自定义“有序字典”类,它允许我们按照元素插入的顺序进行迭代,并且同时支持通过键来访问、修改和删除元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class OrderedDict : def __init__ (self ): self.keys = [] self.values = {} def __getitem__ (self, key ): if key not in self.values: raise KeyError(f"Key {key} not found" ) return self.values[key] def __setitem__ (self, key, value ): if key not in self.keys: self.keys.append(key) self.values[key] = value def __delitem__ (self, key ): if key not in self.values: raise KeyError(f"Key {key} not found" ) self.keys.remove(key) del self.values[key] def __iter__ (self ): for key in self.keys: yield self.values[key] def __repr__ (self ): return f"OrderedDict({repr (dict (zip (self.keys, self.values)))} )" od = OrderedDict() od['a' ] = 1 od['b' ] = 2 od['c' ] = 3 print (od['b' ]) od['b' ] = 20 print (od['b' ]) del od['c' ] for value in od: print (value) print (od)
在这个例子中,OrderedDict
类使用两个内部数据结构:一个列表 keys
用于保存键的插入顺序,一个字典 values
用于保存键值对。通过实现 __getitem__
、__setitem__
和 __delitem__
方法,我们可以像操作普通字典一样操作 OrderedDict
实例,同时还保留了元素的插入顺序。
__getslice__、__setslice__、__delslice__ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Foo : def __getslice__ (self, i, j ): print ('__getslice__' , i, j) def __setslice__ (self, i, j, sequence ): print ('__setslice__' , i, j) def __delslice__ (self, i, j ): print ('__delslice__' , i ,j) obj = Foo() obj[-1 :1 ] obj[0 :1 ] = [11 ,22 ,33 ,44 ] del obj[0 :2 ]
__iter__和__next__ __iter__
它允许一个对象定义自己的迭代行为。当你尝试在一个对象上使用迭代(例如,在 for
循环中或在内置函数如 list()
或 sum()
中)时,Python会查找这个对象是否实现了 __iter__
方法。
__iter__
方法应该返回一个迭代器对象,该对象实现了 __iter__
和 __next__
方法。迭代器是一个可以记住遍历的位置的对象。
以下是一个简单的例子,演示如何在一个自定义类中实现 __iter__
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Fib : def __init__ (self, max ): self.max = max self.a = 0 self.b = 1 def __iter__ (self ): print ("__iter__ called" ) return self def __next__ (self ): print ("__next__ called" ) fib = self.a if fib > self.max : raise StopIteration self.a, self.b = self.b, self.a + self.b return fib if __name__ == '__main__' : for i in Fib(5 ): print (i)
结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 __iter__ called __next__ called 0 __next__ called 1 __next__ called 1 __next__ called 2 __next__ called 3 __next__ called 5 __next__ called
定义 iter 表示这个类是一个迭代器(iterator)。它只在迭代开始的时候运行一次。返回的是对象本身。这里还给顺手给对象添加了 a 和 b 两个属性。接下来就是循环调用 next 直到遇到 raise StopIteration 为止。调用的过程就是模拟斐波那契数列的过程。