python魔术方法使用 所谓魔法函数(Magic Methods),是Python的一种高级语法,允许你在类中自定义函数,并绑定到类的特殊方法中。比如在类A中自定义__str__()函数,则在调用str(A())时,会自动调用__str__()函数,并返回相应的结果。
Python 的类以其神奇的方法而闻名,通常称为 dunder(双下划线)方法。下面先列举Python里面的魔术方法,挑一些常用的魔术方法进行学习。
1.魔术方法索引 1.二元操作符 1 2 3 4 5 6 7 8 9 10 11 12 + object .__add__(self, other) - object .__sub__(self, other) * object .__mul__(self, other) // object .__floordiv__(self, other) / object .__div__(self, other) % object .__mod__(self, other) ** object .__pow__(self, other[, modulo]) << object .__lshift__(self, other) >> object .__rshift__(self, other) & object .__and__(self, other) ^ object .__xor__(self, other) | object .__or__(self, other)
2.扩展二元操作符 1 2 3 4 5 6 7 8 9 10 11 12 += object .__iadd__(self, other) -= object .__isub__(self, other) *= object .__imul__(self, other) /= object .__idiv__(self, other) //= object .__ifloordiv__(self, other) %= object .__imod__(self, other) **= object .__ipow__(self, other[, modulo]) <<= object .__ilshift__(self, other) >>= object .__irshift__(self, other) &= object .__iand__(self, other) ^= object .__ixor__(self, other) |= object .__ior__(self, other)
3.一元操作符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - object .__neg__(self) + object .__pos__(self)abs () object .__abs__(self) ~ object .__invert__(self)complex () object .__complex__(self)int () object .__int__(self) long() object .__long__(self)float () object .__float__(self)oct () object .__oct__(self)hex () object .__hex__(self)round () object .__round__(self, n) floor() object__floor__(self) ceil() object .__ceil__(self) trunc() object .__trunc__(self)
4.比较函数 1 2 3 4 5 6 < object .__lt__(self, other) <= object .__le__(self, other) == object .__eq__(self, other) != object .__ne__(self, other) >= object .__ge__(self, other) > object .__gt__(self, other)
5.类的表示、输出 1 2 3 4 5 6 7 str () object .__str__(self) repr () object .__repr__(self)len () object .__len__(self)hash () object .__hash__(self) bool () object .__nonzero__(self) dir () object .__dir__(self) sys.getsizeof() object .__sizeof__(self)
6.类容器 1 2 3 4 5 6 7 8 len () object .__len__(self) self[key] object .__getitem__(self, key) self[key] = value object .__setitem__(self, key, value)del [key] object .__delitem__(self, key)iter () object .__iter__(self)reversed () object .__reversed__(self)in 操作 object .__contains__(self, item) 字典key不存在时 object .__missing__(self, key)
2.常用魔术方法 1.__init__
它是一个类初始化器。 每当创建一个类的实例时,都会调用其 __init__()
方法。 例如:
1 2 3 4 5 6 class GetTest (object ): def __init__ (self ): print ('Greetings!!' ) def another_method (self ): print ('I am another method which is not automatically called' )
可以看到在实例在创建后会立即调用 __init__
。 还可以在初始化期间将参数传递给类。
1 2 3 4 5 6 class GetTest (object ): def __init__ (self, name ): print ('Greetings!! {0}' .format (name)) def another_method (self ): print ('I am another method which is not automatically called' )
2.__getitem__
在类中实现 __getitem__
允许其实例使用[]
(索引器)运算符。这是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class GetTest (object ): def __init__ (self ): self.info = { 'name' :'Yasoob' , 'country' :'Pakistan' , 'number' :12345812 } def __getitem__ (self,i ): return self.info[i] >>> foo = GetTest()>>> foo['name' ]'Yasoob' >>> foo['number' ]12345812
如果没有__getitem__
方法,我们会遇到以下错误:
1 2 3 4 >>> foo['name' ] Traceback (most recent call last): File "<stdin>" , line 1 , in <module> TypeError: 'GetTest' object has no attribute '__getitem__'
3.__del__
del ()是delete的缩写,这是析构魔术方法。当一块空间没有了任何引用时 默认执行__del__回收这个类地址,一般我们不自定义__del__ 有可能会导致问题。
触发时机:当对象被内存回收的时候自动触发,有下面两种情况: 页面执行完毕回收所有变量 当多个对象指向同一地址,所有对象被del的时候 功能:对象使用完毕后资源回收 参数:一个self接受对象 返回值:无
注意:程序自动调用__del__()
方法,不需要我们手动调用。
来看例子:现在我们有一个类,在__del__()
中打印一些信息,以便我们看到__del__()
的调用时机。
1 2 3 4 5 6 class Cat : def eat (self ): print ("我嘎嘎能吃" ) def __del__ (self ): print ("ohohoh,我被销毁了" )
现在我们对类实例化:
1 2 3 print ("<=======start======>" ) cat1 = Cat()print ("<=======ends======>" )
程序的输出为:
<=======start======> <=======ends======> ohohoh,我被销毁了
出现上面现象的原因是在没有手动执行del
的情况下,程序执行结束后自动触发析构方法。
继续,现在加一个实例化,并且我们del
cat1:
1 2 3 4 5 cat1 = Cat() cat2 = cat1print ("<=======start======>" )del cat1print ("<=======ends======>" )
程序的输出为:
<=======start======> <=======ends======> ohohoh,我被销毁了
既然我们在start与end中间删除了cat1,为啥程序还是在执行完后触发析构方法?这主要是因为cat2还在继续占用cat1的内存地址,所以会在cat2执行完毕后触发析构方法。
只要同时删除cat1和cat2,内存地址没有指向的值,这块内存被释放就会触发析构方法:
1 2 3 4 5 6 cat1 = Cat() cat2 = cat1print ("<=======start======>" )del cat1del cat2print ("<=======ends======>" )
程序的输出为:
<=======start======> ohohoh,我被销毁了 <=======ends======>
注意 :如果这个对象产生了循环引用,并且实现了__del__
方法,那么这个对象将得不到释放,从而产生内存泄漏。
4.__call__
call ()方法可以让类的实例具有类似于函数的行为,这进一步模糊了函数和对象之间的概念。
触发时机:把对象当作函数调用的时候自动触发 功能:模拟函数化操作 参数:参数不固定,至少一个self参数 返回值:看需求 其使用方式为:对象后面加括号,触发执行。即:对象() 或者 类()()
1 2 3 4 5 6 7 class A (object ): def __call__ (self, *args, **kwargs ): print ('call....' ) a = A() a()
来看个例子:使用__call__()
方法实现斐波那契数列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Fibonacci (object ): def __call__ (self, num ): a, b = 1 , 1 lst = [] if num <= 2 : lst.append(a) lst.append(b) else : for i in range (num): lst.append(a) a, b = b, a + b return lst>>> f = Fibonacci()>>> print (f(5 )) [1 , 1 , 2 , 3 , 5 ]
5.__slots__
Python是一门动态语言,这使得我们可以在程序运行的时候给对象绑定新的属性或方法,这就是动态语言的灵活性。
我们先定义一个类:
1 2 3 4 class Person (object ): def __init__ (self, name, age ): self._name = name self._age = age
然后创建一个实例并动态为这个实例绑定一个属性和方法 ,但是为实例绑定的属性和方法对另一个实例并不起作用,如果需要应用在多个实例上,则需要将其绑定到类上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from types import MethodTypedef fly (self ): print ('I can fly~' )>>> p1 = Person('王大锤' , 18 )>>> p2 = Person('爱丽丝' , 16 ) >>>>>> p1.fly = MethodType(fly, p1)>>> p1.fly() I can fly~ >>>>>> p2.fly() Traceback (most recent call last): File "D:\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py" , line 3331 , in run_code exec (code_obj, self.user_global_ns, self.user_ns) File "<ipython-input-31-07b12cf8c526>" , line 1 , in <module> p2.fly() AttributeError: 'Person' object has no attribute 'fly'
动态绑定确实方便,但是如果我们需要限定自定义类型的对象只能绑定某些属性要怎么办呢?__slots__
可以解决这个需求。
定义类的时候,可以定义一个特殊的__slots__
变量,来限制该类实例能添加的属性:
1 2 3 4 5 6 class Person (object ): __slots__ = ('_name' , '_age' , '_gender' ) def __init__ (self, name, age ): self._name = name self._age = age
实例就不能再添加不在限定范围内的属性了:
1 2 3 4 5 6 7 8 9 10 11 >>> p = Person('陆七岁' , 7 )>>> p._gender = '男' >>> p._gender'男' >>> p._school = 'Q小学' Traceback (most recent call last): File "D:\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py" , line 3331 , in run_code exec (code_obj, self.user_global_ns, self.user_ns) File "<ipython-input-36-c90af696bffa>" , line 1 , in <module> p._school = 'Q小学' AttributeError: 'Person' object has no attribute '_school'
但要注意的是,限制只是针对实例 ,类本身并不会被限制 。怎么理解能?就是我们仍然可以通过类去添加属性或方法:
1 2 3 4 5 6 7 8 9 10 >>> Person._school = 'Q小学' >>> Person._school'Q小学' >>> p1._school Traceback (most recent call last): File "D:\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py" , line 3331 , in run_code exec (code_obj, self.user_global_ns, self.user_ns) File "<ipython-input-38-f12357d4471f>" , line 1 , in <module> p1._school AttributeError: 'Person' object has no attribute '_school'
总结:
__slots__是针对类实例的限制,要添加属性或方法仍可以通过类去添加; __slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
6.__str__
__str__()
方法可以改变对象的字符串显示。在打印某个对象的时候,会调用这个对象的__str__
方法,打印这个方法的返回值。
触发时机:使用print(对象)
或str(对象)
时触发。
1 2 3 4 5 6 7 8 9 10 11 12 class Cat : def __init__ (self, name, sex ): self.name = name self.sex = sex def __str__ (self ): return f"我是一只可爱的小{self.sex} 猫咪,我的名字是{self.name} " >>> cat = Cat("小白" , "公" )>>> print (cat) 我是一只可爱的小公猫咪,我的名字是小白
7.__repr__
repr ()方法可以改变对象的字符串显示。__repr__魔术方法是用来表述某个对象在内存中的展示形式。如果在终端直接输入一个对象,然后按回车,那么将会执行这个对象的__repr__方法。
此方法是__str__()
的“备胎”,如果找不到__str__()
就会找__repr__()
方法。
%r
默认调用的是__repr__()
方法,%s
调用__str__()
方法
repr()
方法默认调用__repr__()
方法
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 A (object ): def __init__ (self, name, age ): self.name = name self.age = age def __str__ (self ): msg = 'name:{},age:{}' .format (self.name, self.age) return msg def __repr__ (self ): msg = 'name--->{},age--->{}' .format (self.name, self.age) return msg>>> a = A('za' , 34 )>>> print ('%s' % a) name:za, age:34 >>> print ('%r' % a) name-->za, age-->34 >>> print (a) name:za, age:34 >>> print (repr (a)) name-->za, age-->34
注意:如果将几个对象扔到一个容器中(比如:列表),那么在打印这个容器的时候,会依次调用这个容器中的元素的__repr__
方法。如果没有实现这个__repr__
方法,那么得到的将是一个类名+地址的形式,这种形式的是不好理解的。
8.__new__
触发时机: 在实例化对时触发 参数:至少一个cls 接收当前类 返回值:必须返回一个对象实例 作用:实例化对象
注意:实例化对象是Object
类底层实现,其他类继承了Object
的__new__
才能够实现实例化对象。
第一个例子:查看__new__
方法的执行时机。
1 2 3 4 5 6 7 8 9 10 11 12 class Person (object ): def __init__ (self ): print ('__init__(): 我也被调用啦~' ) def __new__ (cls, *args, **kwargs ): print ('__new__(): 哈哈我被调用啦~' )>>> per = Person() __new__(): 哈哈我被调用啦~>>> print (per)None
None
说明没有创建对象,因为我们重写了__new__
方法,__new__
方法不再具有创建对象的功能,只有打印的功能。
第二个例子:调用父类的__new__
方法,创建当前对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Person (object ): def __init__ (self ): print ('__init__(): 我也被调用啦~' ) def __new__ (cls, *args, **kwargs ): print ('__new__(): 哈哈我被调用啦~' ) ret = super ().__new__(cls) return ret>>> per = Person() __new__(): 哈哈我被调用啦~ __init__(): 我也被调用啦~>>> print (per) <__main__.Person object at 0x0000020FA3892848 >
9.__eq__
说到__eq__()
魔法方法,就必须提到Python中的is
和==
。先来看看这两者的区别:
is
比较两个对象的 id
值是否相等,是否指向同一个内存地址;
==
比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。
==
在比较类时,会默认调用object.__eq__
方法,默认比较两个对象的地址(id)。
第一个例子:list1
和list2
的值相同,但id
不同,来看看is
和==
的区别。
1 2 3 4 5 6 7 8 9 10 11 12 >>> list1 = [1 , 2 , 3 ]>>> list2 = [1 , 2 , 3 ]>>> print (id (list1)) 1759352803720 >>> print (id (list2))1759352804232 >>> print (list1 == list2) True >>> print (list1 is list2) False
第二个例子:类的比较:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Cat : def __init__ (self, name, sex ): self.name = name self.sex = sex>>> c1 = Cat('小白' , 2 )>>> c2 = Cat('小白' , 2 )>>> print (c1.__dict__) {'name' : '小白' , 'sex' : 2 }>>> print (c2.__dict__) {'name' : '小白' , 'sex' : 2 }>>> print (c1 == c2) False >>> print (c1 is c2) False
重写__eq__()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Cat : def __init__ (self, name, sex ): self.name = name self.sex = sex def __eq__ (self, other ): return self.__dict__ == other.__dict__>>> c1 = Cat('小白' , 2 )>>> c2 = Cat('小白' , 2 )>>> print (c1.__dict__) {'name' : '小白' , 'sex' : 2 }>>> print (c2.__dict__) {'name' : '小白' , 'sex' : 2 }>>> print (c1 == c2) True >>> print (c1 is c2) False
10.__bool__
触发时机:使用bool(对象)
的时候自动触发
功能:强转对象
参数:一个self
接受当前对象
返回值:必须是布尔类型
1 2 3 4 5 6 7 8 9 10 11 12 class Cat : def __init__ (self, name, sex ): self.name = name self.sex = sex def __bool__ (self ): return True >>> cat = Cat("小白" , "公" )>>> print (bool (cat))True
11.__add__
__add__
与__radd__
都是做加法,只是加法的顺序不一样,会调用不同的魔法函数。
触发时机:使用对象进行运算相加的时候自动触发
功能:对象运算
参数:两个对象参数
返回值:运算后的值
对象在加号的左侧时,自动调用__add__()
函数。
1 2 3 4 5 6 7 8 9 10 11 12 class Sum : def __init__ (self, num ): self.num = num def __add__ (self, other ): return self.num + other>>> value = Sum(7 )>>> res = value + 8 >>> print (res)15
对象在加号的右侧时,自动调用__radd__()
函数。
1 2 3 4 5 6 7 8 9 10 11 12 class Sum (): def __init__ (self, num ): self.num = num def __radd__ (self, other ): return self.num + other>>> value = Sum(7 )>>> res = 10 + value>>> print (res)17
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Sum1 : def __init__ (self, num ): self.num = num def __add__ (self, other ): return self.num + otherclass Sum2 : def __init__ (self, num ): self.num = num def __radd__ (self, other ): return self.num * 2 + other>>> value1 = Sum1(10 )>>> value2 = Sum2(7 )>>> res = value1 + value2>>> print (res)
分析:首先将res=value1+value2
传入Sum1
中,得出值res=10+value2
,再将res=10+value2
传入Sum2
中,所以res=14+10=24
。
12.__len__
触发时机:使用len对象的时候自动触发
功能:用于检测对象中或者类中成员个数
参数:一个self接收当前对象
返回值:必须是整型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class List : def __init__ (self ): self.num = [] def add (self, x ): self.num.append(x) def __len__ (self ): return len (self.num)>>> l = List ()>>> l.add(2 )>>> print (len (l))
13.__dict__
获取类或对象的的内部成员结构 。主要用来获取用户自定义的属性,以及这个属性对应的值。返回的是一个字典 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class MyClass (): name1 = "Lsir" name2 = "Wsir" name3 = "Zsir" def task1 (self ): print ("task1" ) def task2 (self ): print ("tesk2" ) def task3 (self ): print ("task3" )>>> print (MyClass.__dict__) {'__module__' : '__main__' , 'name1' : 'Lsir' , 'name2' : 'Wsir' , 'name3' : 'Zsir' , 'task1' : <function MyClass.task1 at 0x0000020C16385558 >, 'task2' : <function MyClass.task2 at 0x0000020C16385D38 >, 'task3' : <function MyClass.task3 at 0x0000020C16385708 >, '__dict__' : <attribute '__dict__' of 'MyClass' objects>, '__weakref__' : <attribute '__weakref__' of 'MyClass' objects>, '__doc__' : None }
和dir
函数做一个区分。dir
函数返回的是这个对象上拥有的所有属性,包括Python内置的属性和用户自己添加的,并且只是获取属性名字,不会获取这个属性对应的值。
14.__doc__
获取类或对象内部文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 class MyClass (): """ 我是一个类,这里说明一些有用的信息 """ def __init__ (self ): pass print (MyClass.__doc__) 我是一个类,这里说明一些有用的信息
15.__name__
获取类名或函数名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Class1 : pass class MyClass : def task1 (self, func1 ): print (func1.__name__)def func (): print ("我是func1函数" )>>> obj = MyClass()>>> obj.task1(func) func>>> obj.task1(Class1) Class1
16.__class__
获取当前对象获取的类
1 2 3 4 5 6 7 8 9 class Class1 : pass >>> obj = Class1()>>> print (obj.__class__) <class '__main__.Class1' >>>> print (obj.__class__.__name__) Class1
17.__bases__
获取一个类直接继承的所有父类,返回元组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Class1 : pass class Class2 : pass class MyClass (Class1, Class2): pass >>> print (MyClass.__bases__) (<class '__main__.Class1' >, <class '__main__.Class2' >)
18.__getattr__
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 Base : n = 0 class Point (Base ): z = 6 def __init__ (self, x, y ): self.x = x self.y = y def show (self ): print (self.x, self.y) def __getattr__ (self, item ): return item >>> p1.x4 >>> p1.z6 >>> p1.n0 >>> p1.t't'
实例属性会按照继承关系 寻找,如果找不到,就会执行__getattr__()
方法,如果没有这个方法,就会抛出AttributeError
异常标识找不到属性。
19.__setattr__
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 class Base : n = 0 class Point (Base ): z = 6 def __init__ (self, x, y ): self.x = x self.y = y def show (self ): print (self.x, self.y) def __getattr__ (self, item ): return item def __setattr__ (self, key, value ): print (key, value) >>> p1 = Point(4 , 5 ) x 4 y 5 >>> print (p1.x) x>>> print (p1.z)6 >>> print (p1.n)0 >>> print (p1.t) t>>> p1.x = 50 >>> print (p1.x) x>>> print (p1.__dict__) {}>>> p1.__dict__['x' ] = 60 >>> print (p1.__dict__) {'x' : 60 }>>> p1.x60
实例通过.
点号设置属性,例如self.x=x
,就会调用__setattr__()
,属性要加到实例的__dict__
中,就需要自己完成。
setattr()
方法,可以拦截堆实例属性的增加,修改操作,如果要设置生效,需要自己操作实例的__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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Base : n = 200 class A (Base ): z = 100 d = {} def __init__ (self, x, y ): self.x = x setattr (self, 'y' , y) self.__dict__['a' ] = 5 def __getattr__ (self, item ): print (item) return self.d[item] def __setattr__ (self, key, value ): print (key, value) self.d[key] = value >>> a = A(4 , 5 ) x 4 y 5 >>> print (a.__dict__) {'a' : 5 }>>> print (A.__dict__) A.__dict__ mappingproxy({'__module__' : '__main__' , 'z' : 100 , 'd' : {'x' : 4 , 'y' : 5 }, '__init__' : <function __main__.A.__init__(self, x, y)>, '__getattr__' : <function __main__.A.__getattr__(self, item)>, '__setattr__' : <function __main__.A.__setattr__(self, key, value)>, '__doc__' : None })>>> print (a.x, a.y) x y4 5 >>> print (a.a)5
20.__delattr__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Point : z = 5 def __init__ (self, x, y ): self.x = x self.y = y def __delattr__ (self, item ): print (item) p = Point(14 , 5 ) >>> p = Point(3 , 4 )>>> del p.x x>>> p.z=15 >>> del p.z z>>> del p.Z Z>>> print (Point.__dict__) {'__module__' : '__main__' , 'z' : 5 , '__init__' : <function Point.__init__ at 0x0000019E93B01318 >, '__delattr__' : <function Point.__delattr__ at 0x0000019E93B013A8 >, '__dict__' : <attribute '__dict__' of 'Point' objects>, '__weakref__' : <attribute '__weakref__' of 'Point' objects>, '__doc__' : None }
21.__getattribute__
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 class Base : n = 0 class Point (Base ): z = 6 def __init__ (self, x, y ): self.x = x self.y = y def __getattr__ (self, item ): return item def __getattribute__ (self, item ): return item >>> p1 = Point(4 , 5 )>>> print (p1.__dict__) __dict__>>> print (p1.x) x>>> print (p1.z) z>>> print (p1.n) n>>> print (p1.t) t>>> print (Point.__dict__) {'__module__' : '__main__' , 'z' : 6 , '__init__' : <function Point.__init__ at 0x000001F5EB7063A8 >, '__getattr__' : <function Point.__getattr__ at 0x000001F5EB706558 >, '__getattribute__' : <function Point.__getattribute__ at 0x000001F5EB706168 >, '__doc__' : None }>>> print (Point.z)6
实例的所有的属性访问,第一个都会调用__getattribute__方法,它阻止了属性的查找,该方法应该返回值或者抛出一个AttributeError异常。
该方法的返回值将作为属性查找的结果。
如果抛出AttributeError
异常,则会直接调用__getattr__
方法,因为属性没有找到,__getattribute__
方法中为了避免在该方法中无限递归,它的实现应该永远调用基类的同名方法以访问需要的任何属性。
需要注意的是,除非明确知道__getattrtbute__方法用来做什么,否则不要使用。
3.实例 3.1 setitem和getitem 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class MyClass : def __init__ (self ): self.data = {} def __setitem__ (self, key, value ): self.data[key] = value obj = MyClass() obj['name' ] = 'John' obj['age' ] = 30 print (obj.data)
在这个例子中,__setitem__
方法允许我们使用类似字典赋值的语法(obj['name'] = 'John'
)将数据存储到 MyClass
实例中。在这里,obj.data
将包含键值对 {'name': 'John', 'age': 30}
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class MyClass : def __init__ (self ): self.data = {'name' : 'John' , 'age' : 30 } def __getitem__ (self, item ): return self.data.get(item, None ) obj = MyClass() name = obj['name' ] age = obj['age' ] unknown_key = obj['unknown_key' ]print (name) print (age) print (unknown_key)
在这个例子中,__getitem__
方法允许我们使用方括号表示法获取 MyClass
实例中的元素。如果请求的键在 self.data
字典中存在,则返回对应的值;否则返回 None
。