Python运算符重载详解及实例代码
本文深入解析Python中的运算符重载机制,通过重写内置魔法方法如__init__、__add__、__str__等,实现自定义类的行为定制。文章结合构造函数、算术运算、字符串表示、索引访问及迭代器等具体场景,提供完整代码示例,帮助开发者掌握Python面向对象编程的核心技巧。
Python运算符重载
Python语言内置了运算符重载功能,这赋予了语言更高的灵活性,其机制与C++有相似之处,但也存在显著差异。鉴于该特性在开发中的重要性,本文将详细探讨Python运算符重载的实现原理与应用。
Python提供了丰富的魔法方法(Magic Methods),运算符重载正是通过重写这些内置的魔法方法来实现的。这些方法的命名规范是以双下划线开头和结尾,格式为__X__。Python利用这种特殊的命名约定来拦截特定的操作符,从而触发用户定义的行为。当对类对象执行内置操作时,Python会自动搜索并调用对象中对应的指定方法以完成操作。
类可以重载加减运算、打印输出、函数调用以及索引访问等内置运算,使得自定义对象的行为与Python内置对象保持一致。Python在遇到操作符时会自动调用相应的方法,例如,若类中实现了__add__方法,当该类的实例参与加法运算(+)时,Python会自动调用此方法。
常见运算符重载方法
|
方法名 |
重载说明 |
运算符调用方式 |
|
__init__ |
构造函数 |
对象创建: X = Class(args) |
|
__del__ |
析构函数 |
X对象收回 |
|
__add__/__sub__ |
加减运算 |
X+Y, X+=Y/X-Y, X-=Y |
|
__or__ |
运算符| |
X|Y, X|=Y |
|
_repr__/__str__ |
打印/转换 |
print(X)、repr(X)/str(X) |
|
__call__ |
函数调用 |
X(*args, **kwargs) |
|
__getattr__ |
属性引用 |
X.undefined |
|
__setattr__ |
属性赋值 |
X.any=value |
|
__delattr__ |
属性删除 |
del X.any |
|
__getattribute__ |
属性获取 |
X.any |
|
__getitem__ |
索引运算 |
X[key],X[i:j] |
|
__setitem__ |
索引赋值 |
X[key],X[i:j]=sequence |
|
__delitem__ |
索引和分片删除 |
del X[key],del X[i:j] |
|
__len__ |
长度 |
len(X) |
|
__bool__ |
布尔测试 |
bool(X) |
|
__lt__, __gt__, __le__, __ge__, __eq__, __ne__ |
特定的比较 |
依次为X<Y,X>Y,X<=Y,X>=Y, X==Y,X!=Y 注释:(lt: less than, gt: greater than, le: less equal, ge: greater equal, eq: equal, ne: not equal ) |
|
__radd__ |
右侧加法 |
other+X |
|
__iadd__ |
实地(增强的)加法 |
X+=Y(or else __add__) |
|
__iter__, __next__ |
迭代 |
I=iter(X), next() |
|
__contains__ |
成员关系测试 |
item in X(X为任何可迭代对象) |
|
__index__ |
整数值 |
hex(X), bin(X), oct(X) |
|
__enter__, __exit__ |
环境管理器 |
with obj as var: |
|
__get__, __set__, __delete__ |
描述符属性 |
X.attr, X.attr=value, del X.attr |
|
__new__ |
创建 |
在__init__之前创建对象 |
以下将介绍常用运算符重载方法的具体使用方式。
构造函数和析构函数:__init__和__del__
这两个方法主要负责对象的创建与销毁。当实例被创建时,__init__构造方法会被自动调用;当实例对象被垃圾回收机制回收时,析构函数__del__会自动执行相应的清理工作。
>>> class Human():
... def __init__(self, n):
... self.name = n
... print("__init__ ",self.name)
... def __del__(self):
... print("__del__")
...
>>> h = Human('Tim')
__init__ Tim
>>> h = 'a'
__del__
加减运算:__add__和__sub__
通过重载这两个方法,可以在自定义对象上支持加号和减号运算符。下面的代码演示了加减运算符的使用:如果代码中移除了__sub__方法,再次调用减号运算符将会引发错误。
>>> class Computation(): ... def __init__(self,value): ... self.value = value ... def __add__(self,other): ... return self.value + other ... def __sub__(self,other): ... return self.value - other ... >>> c = Computation(5) >>> c + 5 10 >>> c - 3 2
对象的字符串表达形式:__repr__和__str__
这两个方法均用于定义对象的字符串表示形式。print()和str()函数会调用__str__方法,而print()、str()以及repr()函数会调用__repr__方法。从示例可以看出,当两个方法同时定义时,Python会优先搜索并调用__str__方法。
>>> class Str(object): ... def __str__(self): ... return "__str__ called" ... def __repr__(self): ... return "__repr__ called" ... >>> s = Str() >>> print(s) __str__ called >>> repr(s) '__repr__ called' >>> str(s) '__str__ called'
索引取值和赋值:__getitem__, __setitem__
通过实现这两个方法,可以使用X[i]的形式对对象进行取值和赋值操作,同时支持对对象进行切片操作。
>>> class Indexer:
data = [1,2,3,4,5,6]
def __getitem__(self,index):
return self.data[index]
def __setitem__(self,k,v):
self.data[k] = v
print(self.data)
>>> i = Indexer()
>>> i[0]
1
>>> i[1:4]
[2, 3, 4]
>>> i[0]=10
[10, 2, 3, 4, 5, 6]
设置和访问属性:__getattr__、__setattr__
我们可以通过重载__getattr__和__setattr__来拦截对对象成员的访问。当访问对象中不存在的成员时,__getattr__方法会被自动调用。__setattr__方法则在初始化或设置对象成员(即修改__dict__中的项)时被调用。具体示例如下:
class A():
def __init__(self,ax,bx):
self.a = ax
self.b = bx
def f(self):
print (self.__dict__)
def __getattr__(self,name):
print ("__getattr__")
def __setattr__(self,name,value):
print ("__setattr__")
self.__dict__[name] = value
a = A(1,2)
a.f()
a.x
a.x = 3
a.f()
上述代码的运行结果如下:从结果可以看出,当访问不存在的变量x时会触发__getattr__方法;而在__init__执行期间,赋值运算会调用__setattr__方法。
__setattr__
__setattr__
{'a': 1, 'b': 2}
__getattr__
__setattr__
{'a': 1, 'x': 3, 'b': 2}
迭代器对象: __iter__, __next__
Python中的迭代可以通过重载__getitem__方法来实现,参考下面的示例。
>>> class Indexer: ... data = [1,2,3,4,5,6] ... def __getitem__(self,index): ... return self.data[index] ... >>> x = Indexer() >>> for item in x: ... print(item) ... 1 2 3 4 5 6
虽然上述方法可以实现迭代,但这并非最佳实践。Python的迭代机制会优先尝试调用__iter__方法,其次才尝试__getitem__。迭代环境通过iter()函数寻找__iter__方法,该方法需返回一个迭代器对象。若已提供__iter__,Python会重复调用迭代器对象的next()方法,直到抛出StopIteration异常。若未找到__iter__,Python才会回退使用__getitem__机制。下面展示迭代器的具体示例。
class Next(object):
def __init__(self, data=1):
self.data = data
def __iter__(self):
return self
def __next__(self):
print("__next__ called")
if self.data > 5:
raise StopIteration
else:
self.data += 1
return self.data
for i in Next(3):
print(i)
print("-----------")
n = Next(3)
i = iter(n)
while True:
try:
print(next(i))
except Exception as e:
break
程序的运行结果如下:
__next__ called 4 __next__ called 5 __next__ called 6 __next__ called ----------- __next__ called 4 __next__ called 5 __next__ called 6 __next__ called
可见,实现了__iter__和__next__方法后,既可以通过for...in语句迭代遍历对象,也可以通过iter()和next()函数进行迭代遍历。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









