python编程-类的特殊方法
目录
一、定义特殊方法
1. 方法命名规范
2. 方法定义位置
3. 方法参数约定
__init__
__str__
__repr__
__len__
__getitem__
__setitem__
__delitem__
__iter__
__next__
__call__
__eq__
4. 示例
二. 调用时机和作用概述
三. 常见特殊方法及功能
__init__
__str__
__repr__
__len__
__getitem__
__setitem__
__delitem__
__iter__
__next__
__call__
__eq__
__ne__
__lt__
四、用途及示例
1. __str__
2. __repr__
3. __len__
4. __getitem__
5. __setitem__
6. __delitem__
7. __iter__
8. __next__
9. __call__
10. __eq__
11. __ne__
12. __lt__
13. __gt__
14. __le__
15. __ge__
类的特殊方法(也称为魔法方法或双下划线方法)是在 Python 类中定义的一些以双下划线(__
)开头和结尾的方法。它们具有特殊的用途,会在特定的情况下自动被调用,帮助实现类的各种功能和行为,使类能够更好地与 Python 的内置函数、运算符以及其他语言特性进行交互。
以下是对其详细介绍:
一、定义特殊方法
1. 方法命名规范
特殊方法是以双下划线(__
)开头和结尾的方法名,例如 __init__
、__str__
、__len__
等。必须严格按照这种命名格式来定义特殊方法,否则它们不会被 Python 识别为具有特殊行为的方法。
2. 方法定义位置
特殊方法需要定义在对应的类内部。每个特殊方法都有其特定的调用时机和用途,与类的实例以及相关的语言操作(如运算符使用、内置函数调用等)相关联。
3. 方法参数约定
不同的特殊方法有不同的参数约定,以下是一些常见特殊方法及其参数要求:
__init__
- 参数:通常第一个参数是
self
,表示类的实例本身,这是 Python 中类的实例方法的约定俗成的参数表示方式。之后可以根据类的初始化需求添加其他参数,比如在创建一个Person
类的实例时,可能需要传入姓名和年龄等参数,那么__init__
方法可以定义为def __init__(self, name, age)
。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
__str__
- 参数:第一个参数同样是
self
,表示要转换为字符串表示的类的实例。该方法需要返回一个字符串,用于描述实例的状态,例如def __str__(self): return f"Person named {self.name} with age {self.age}"
,这里假设类中有name
和age
两个属性。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Person named {self.name} with age {self.age}"
__repr__
- 参数:也是以
self
为第一个参数。它返回的字符串应该是一个能够准确重现该对象的表示形式,比如def __repr__(self): return f"Person({self.name}, {self.age})"
。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Person({self.name}, {self.age})"
__len__
- 参数:第一个参数为
self
,表示要获取长度的类的实例。该方法需要返回一个整数,表示实例的某种 “长度” 概念,例如对于一个自定义的列表类,def __len__(self): return len(self.items)
,这里假设类中有一个items
属性存储列表元素。
class Person(object):
def __init__(self, name, age, items):
self.name = name
self.age = age
self.items = items # hobby
def __len__(self):
return len(self.items)
__getitem__
- 参数:第一个参数是
self
,表示可索引或可键控的类的实例;第二个参数根据索引或键的类型而定,如果是通过整数索引获取元素,那么第二个参数就是整数类型,如果是通过键获取元素(如字典那样),那么第二个参数就是键的类型(可以是各种可哈希的类型)。例如def __getitem__(self, index): return self.items[index]
,这里假设类中有一个items
属性存储可索引的元素。
class Person(object):
def __init__(self, name, age, items):
self.name = name
self.age = age
self.items = items # hobby
def __getitem__(self, index):
return self.items[index]
__setitem__
- 参数:第一个参数是
self
,表示要设置元素的类的实例;第二个参数同样根据索引或键的类型而定;第三个参数是要设置的值的类型。例如def __setitem__(self, index, value): self.items[index] = value
。
class Person(object):
def __init__(self, name, age, items):
self.name = name
self.age = age
self.items = items # hobby
def __setitem__(self, index, value):
self.items[index] = value
__delitem__
- 参数:第一个参数是
self
,表示要删除元素的类的实例;第二个参数根据索引或键的类型而定。例如def __delitem__(self, index): del self.items[index]
。
class Person(object):
def __init__(self, name, age, items):
self.name = name
self.age = age
self.items = items # hobby
def __delitem__(self, index):
del self.items[index]
__iter__
- 参数:第一个参数是
self
,表示要使其可迭代的类的实例。该方法需要返回一个迭代器对象,可以是类自身实现了__iter__
和__next__
方法的迭代器,也可以是通过iter()
函数对类中的某个可迭代属性进行迭代得到的迭代器,例如def __iter__(self): return iter(self.items)
,这里假设类中有一个items
可迭代属性。
class Person(object):
def __init__(self, name, age, items):
self.name = name
self.age = age
self.items = items # hobby
def __iter__(self):
return iter(self.items)
__next__
- 参数:第一个参数是
self
,表示迭代器类的实例。该方法需要返回下一个元素,如果迭代器没有更多元素可提供,应该抛出StopIteration
异常,例如def __next__(self): if self.index < len(self.items): result = self.items[self.index] self.index += 1 return result else: raise StopIteration
,这里假设类中有一个items
属性存储可迭代元素,且有一个index
属性记录当前迭代位置。
class Person(object):
def __init__(self, name, age, items, index):
self.name = name
self.age = age
self.items = items # hobby
self.index = index
def __next__(self):
if self.index < len(self.items):
result = self.items[self.index]
self.index += 1
return result
else:
raise StopIteration
__call__
- 参数:第一个参数是
self
,表示可调用的类的实例。之后可以根据类的可调用功能需求添加其他参数,就像定义一个普通函数一样,例如def __call__(self, x, y): return x + y
,这里假设类的实例可实现两数相加的功能。
class Person(object):
def __init__(self, name, age, items, index):
self.name = name
self.age = age
self.items = items # hobby
self.index = index
def __call__(self, x, y):
return x + y
__eq__
- 参数:第一个参数是
self
,表示要比较的类的实例;第二个参数是other
,表示与self
进行比较的另一个实例。该方法需要根据类的相等定义返回True
或False
,例如def __eq__(self, other): if isinstance(other, self.class_type): return self.attr1 == other.attr1 and self.attr2 == other.attr2 return False
,这里假设类中有attr1
和attr2
两个属性,且class_type
是类本身的类型。
def __eq__(self, other):
if isinstance(other, self.class_type):
return self.attr1 == other.attr1 and self.attr2 == other.attr2
return False
4. 示例
以下是一个简单的 Point
类的示例,展示了如何定义几个常见的特殊方法:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Point({self.x}, {self.y})"
def __repr__(self):
return f"Point({self.x}, {self.y})"
def __len__(self):
return 2
def __getitem__(self, index):
if index == 0:
return self.x
elif index == 1:
return self.y
else:
raise IndexError("Invalid index")
def __setitem__(self, index, value):
if index == 0:
self.x = value
elif index == 1:
self.y = value
else:
raise IndexError("Invalid index")
def __delitem__(self, index):
if index == 0:
del self.x
elif index == 1:
del self.y
else:
raise IndexError("Invalid index")
def __iter__(self):
yield self.x
yield self.y
def __next__(self):
raise StopIteration
def __call__(self, other_x, other_y):
return Point(self.x + other_x, self.y + other_y)
def __eq__(self, other):
if isinstance(other, Point):
return self.x == other.x and self.y == other.y
return False
def __ne__(self, other):
return not self.__eq__(other)
def __lt__(self, other):
if isinstance(other, Point):
return (self.x ** 2 + self.y ** 2) < (other.x ** 2 + other.y ** 2)
return False
def __gt__(self, other):
if isinstance(other, Point):
return (self.x ** 2 + self.y ** 2) > (other.x ** 2 + other.y ** 2)
return False
def __le__(self, other):
if isinstance(other, Point):
return (self.x ** 2 + self.y ** 2) <= (other.x ** 2 + other.y ** 2)
return False
def __ge__(self, other):
if isinstance(other, Point):
return (self.x ** 2 + self.y ** 2) >= (other.x ** 2 + other.y ** 2)
return False
在上述 Point
类中:
(1)__init__
- 用于初始化
Point
类的实例,接受x
和y
坐标作为参数,并将它们分别赋值给实例的x
和y
属性。
(2)__str__
和 __repr__
__str__
方法返回一个简洁、直观描述Point
实例的字符串,方便在使用print()
函数打印实例时展示信息。__repr__
方法返回一个能够准确重现该对象的字符串表示形式,可用于调试等场景,这里两者返回形式相同,但在实际应用中可根据需求微调。
(3)__len__
- 定义了
Point
实例的 “长度” 概念为固定值2
,可根据实际需求赋予不同含义,这里只是简单示例。
(4)__getitem__
、__setitem__
和 __delitem__
__getitem__
方法允许通过索引获取Point
实例的坐标值,索引0
对应x
坐标,索引1
对应y
坐标,其他索引则抛出异常。__setitem__
方法用于通过索引设置Point
实例的坐标值,同样遵循索引0
对应x
坐标,索引1
对应y
坐标的规则,其他索引抛出异常。__delitem__
方法用于通过索引删除Point
实例的坐标值,按索引对应关系删除x
或y
坐标,其他索引抛出异常。
(5)__iter__
和 __next__
__iter__
方法使得Point
实例可迭代,这里通过yield
语句逐个返回x
和y
坐标,实现简单的迭代功能。__next__
方法在这个示例中直接抛出StopIteration
异常,因为在__iter__
中已经通过yield
实现了迭代逻辑,这里只是遵循迭代器的规范定义该方法。
(6)__call__
- 使得
Point
类的实例可以像函数一样被调用,这里定义了实例调用时接受另外两个坐标值,并返回一个新的Point
实例,其坐标为原实例坐标与传入坐标的和。
(7)__eq__
、__ne__
、__lt__
、__gt__
、__le__
和 __ge__
- 这些方法分别定义了
Point
实例之间的相等、不等、小于、大于、小于等于和大于等于比较操作。例如,__eq__
方法通过比较坐标值来判断两个Point
实例是否相等,其他比较操作方法也根据坐标值的相关计算来确定比较结果,若比较对象不是Point
类实例,则返回相应的默认值(如False
)。
以下是一些使用示例:
point1 = Point(1, 2)
point2 = Point(3, 4)
# 使用 __str__ 和 __repr__
print(point1)
# 输出: Point(1, 2)
print(repr(point1))
# 输出: Point(1, 2)
# 使用 __len__
print(len(point1))
# 输出: 2
# 使用 __getitem__
print(point1[0])
# 输出: 1
print(point1[1])
# 输出: 2
# 使用 __setitem__
point1[0] = 5
print(point1)
# 输出: Point(5, 2)
# 使用 __delitem__
del point1[0]
point1[0] = 0
print(point1)
# 输出: Point(0, 2)
# 使用 __iter__
for coord in point1:
print(coord)
# 输出: 0 2
# 使用 __call__
new_point = point1(2, 3)
print(new_point)
# 输出: Point(2, 5)
# 使用 __eq__、__ne__、__lt__、__gt__、__le__、__ge__
print(point1 == point2)
# 输出: False
print(point1!= point2)
# 输出: True
print(point1 < point2)
# 输出: True
print(point1 > point2)
# 输出: False
print(point1 <= point2)
# 输出: True
print(point1 >= point2)
# 输出: False
通过这些特殊方法的定义,使得 Point
类能够更好地与 Python 的内置函数、运算符以及其他语言特性进行交互,提供了更丰富和灵活的功能。
二. 调用时机和作用概述
- 这些特殊方法不是由开发者手动调用的(通常情况下),而是在特定的语言操作涉及到对应的类的实例时自动触发执行。
- 例如,当使用
print()
函数打印一个类的实例时,会自动调用该实例所属类的__str__
或__repr__
方法;当对一个类的实例使用len()
函数时,会自动调用类的__len__
方法。
三. 常见特殊方法及功能
__init__
- 调用时机:当创建一个类的新实例时,会自动调用这个方法。
- 功能:用于对实例进行初始化操作,比如给实例的属性赋初始值、进行一些必要的设置等。它接受类的实例本身(通常约定俗成用
self
表示)以及其他可能的参数,通过这些参数可以在实例化时传递初始信息给类。
__str__
- 调用时机:当使用
print()
函数打印一个类的实例或者将类的实例转换为字符串形式(例如通过str()
函数)时,会自动调用该实例所属类的__str__
方法。 - 功能:用于返回一个能够简洁、直观地描述实例状态的字符串,以便在打印或显示对象时提供有意义的信息。
__repr__
- 调用时机:与
__str__
类似,但更侧重于提供一个能够准确重现对象的字符串表示形式,通常用于调试目的。在交互式解释器中直接输入类的实例时,也会调用__repr__
方法来显示对象。 - 功能:返回一个可以用来重新创建该对象的字符串表示,使得开发者在调试等场景下能够清楚地了解对象的内部结构和状态。
__len__
- 调用时机:当对一个类的实例使用内置的
len()
函数时,如果该实例所属类定义了__len__
方法,就会调用这个方法来获取实例的某种 “长度” 概念。 - 功能:定义实例的 “长度” 属性,例如对于自定义的列表类,可以通过
__len__
方法返回列表中元素的个数;对于其他具有可计量某种属性数量的类,也可以通过该方法来定义其 “长度”。
__getitem__
- 调用时机:当使用类似
obj[index]
或obj[key]
的表达式时,如果对象所属类定义了__getitem__
方法,就会调用该方法来获取对应的值。 - 功能:使得类的实例可以像列表、字典等可迭代或可索引的数据结构一样,支持通过索引或键来获取其中的元素。
__setitem__
- 调用时机:当使用类似
obj[index] = value
或obj[key] = value
的表达式时,如果对象所属类定义了__setitem__
方法,就会调用该方法来进行赋值操作。 - 功能:与
__getitem__
相对应,用于设置对象中指定索引或键对应的值。
__delitem__
- 调用时机:当使用类似
obj[index]
或obj[key]
的表达式并在后面跟有del
关键字(如del obj[index]
或del obj[key]
)时,如果对象所属类定义了__delitem__
方法,就会调用该方法来执行删除操作。 - 功能:用于删除对象中指定索引或键所对应的元素。
__iter__
- 调用时机:当对一个类的实例使用
for
循环时,如果该实例所属类定义了__iter__
方法,就会调用这个方法来获取一个迭代器对象,然后通过迭代器对象来逐个获取对象中的元素。 - 功能:使得类的实例可以被迭代,即可以在
for
循环中使用该对象,为类的实例提供可迭代性。
__next__
- 调用时机:是迭代器类必须定义的方法,与
__iter__
配合使用。当通过__iter__
获取到迭代器对象后,每次在for
循环中获取下一个元素时,就会调用迭代器对象的__next__
方法来获取下一个元素。如果迭代器没有更多元素可提供,应该抛出StopIteration
异常。 - 功能:在迭代过程中提供下一个元素,与
__iter__
一起实现迭代器的功能。
__call__
- 调用时机:当定义了一个类并在类中定义了
__call__
方法后,创建的实例就可以通过在实例后面直接跟括号的方式(如instance()
)来调用,就像调用一个函数一样,并且会执行__call__
方法中的代码。 - 功能:使得类的实例可以像函数一样被调用,为类的实例赋予了类似函数的功能。
__eq__
- 调用时机:当使用
==
运算符比较两个类的实例时,如果实例所属类定义了__eq__
方法,就会调用该方法来判断两个实例是否相等。 - 功能:用于定义类的实例之间的相等比较操作,不同的类可以根据自身的需求定义不同的相等比较规则。
__ne__
- 调用时机:当使用
!=
运算符比较两个类的实例时,如果实例所属类定义了__ne__
方法,就会调用该方法来判断两个实例是否不等。 - 功能:用于定义类的实例之间的不等比较操作,不同的类可以根据自身的需求规定不同的不等比较规则。
__lt__
- 调用时机:当使用
<
运算符比较两个类的实例时,如果实例所属类定义了__lt__
方法,就会调用该方法来判断两个实例是否满足小于关系。 - 功能:用于定义类的实例之间的小于比较操作,不同的类可以根据自身的了。
四、用途及示例
1. __str__
- 用途:当使用
print()
函数打印一个对象实例或者将对象实例转换为字符串形式(例如通过str()
函数)时,会自动调用该对象所属类的__str__
方法。它用于返回一个能够简洁、直观地描述对象状态的字符串。 - 示例:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Person named {self.name} with age {self.age}"
person = Person("Alice", 25)
print(person)
# 输出: Person named Alice with age 25
2. __repr__
- 用途:与
__str__
类似,但更侧重于提供一个能够准确重现对象的字符串表示形式,通常用于调试目的。在交互式解释器中直接输入对象实例时,也会调用__repr__
方法来显示对象。 - 示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x}, {self.y})"
point = Point(3, 5)
print(repr(point))
# 输出: Point(3, 5)
3. __len__
- 用途:当对一个对象使用内置的
len()
函数时,如果该对象所属的类定义了__len__
方法,就会调用这个方法来获取对象的某种 “长度” 概念。例如,对于列表、元组等可迭代对象,len()
函数就是通过调用它们内部定义的__len__
方法来获取元素个数的。 - 示例:
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3])
print(len(my_list))
# 输出: 3
4. __getitem__
- 用途:使得对象可以像列表、字典等可迭代或可索引的数据结构一样,支持通过索引或键来获取其中的元素。当使用类似
obj[index]
或obj[key]
的表达式时,如果对象所属类定义了__getitem__
方法,就会调用该方法来获取对应的值。 - 示例:
class MyDictionary:
def __init__(self, data):
self.data = data
def __getitem__(self, key):
return self.data[key]
my_dict = MyDictionary({"name": "Alice", "age": 25})
print(my_dict["name"])
# 输出: Alice
5. __setitem__
- 用途:与
__getitem__
相对应,用于设置对象中指定索引或键对应的值。当使用类似obj[index] = value
或obj[key] = value
的表达式时,如果对象所属类定义了__setitem__
方法,就会调用该方法来进行赋值操作。 - 示例:
class MyListWithSetter:
def __init__(self, items):
self.items = items
def __str__(self):
return str(self.items)
def __setitem__(self, index, value):
self.items[index] = value
my_list = MyListWithSetter([1, 2, 3])
my_list[1] = 4
print(my_list)
# 输出: [1, 4, 3]
6. __delitem__
- 用途:用于删除对象中指定索引或键所对应的元素。当使用类似
obj[index]
或obj[key]
的表达式并在后面跟有del
关键字(如del obj[index]
或del obj[key]
)时,如果对象所属类定义了__delitem__
方法,就会调用该方法来执行删除操作。 - 示例:
class MyListWithDeleter:
def __init__(self, items):
self.items = items
def __str__(self):
return str(self.items)
def __delitem__(self, index):
del self.items[index]
my_list = MyListWithDeleter([1, 2, 3, 4, 5, 6, 7, 8, 9])
print(my_list) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
del my_list[2]
print(my_list) # [1, 2, 4, 5, 6, 7, 8, 9]
7. __iter__
- 用途:使得对象可以被迭代,即可以在
for
循环中使用该对象。当对一个对象使用for
循环时,如果该对象所属类定义了__iter__
方法,就会调用这个方法来获取一个迭代器对象,然后通过迭代器对象来逐个获取对象中的元素。 - 示例:
class MyIterable:
def __init__(self, items):
self.items = items
def __iter__(self):
return iter(self.items)
my_iterable = MyIterable([1, 2, 3])
for item in my_iterable:
print(item)
# 输出: 1, 2, 3
8. __next__
- 用途:是迭代器类必须定义的方法,与
__iter__
配合使用。当通过__iter__
获取到迭代器对象后,每次在for
循环中获取下一个元素时,就会调用迭代器对象的__next__
方法来获取下一个元素。如果迭代器没有更多元素可提供,应该抛出StopIteration
异常。 - 示例:
class MyIterable:
def __init__(self, items):
self.items = items
self.index = 0
def __iter__(self):
return iter(self.items)
def __next__(self):
if self.index < len(self.items):
self.index += 1
return self.items[self.index]
else:
raise StopIteration
my_iterable = MyIterable([1, 2, 3])
for item in my_iterable:
print(item)
# 输出: 1, 2, 3
9. __call__
- 用途:使得类的实例可以像函数一样被调用。当定义了一个类并在类中定义了
__call__
方法后,创建的实例就可以通过在实例后面直接跟括号的方式(如instance()
)来调用,就像调用一个函数一样,并且会执行__call__
方法中的代码。 - 示例:
class Adder:
def __call__(self, x, y):
return x + y
adder = Adder()
print(adder(3, 4))
# 输出: 7
10. __eq__
- 用途:用于定义对象之间的相等比较操作。当使用
==
运算符比较两个对象时,如果对象所属类定义了__eq__
方法,就会调用该方法来判断两个对象是否相等。不同的类可以根据自身的需求定义不同的相等比较规则。 - 示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if isinstance(other, Point):
return self.x == other.x and self.y == other.y
return False
point1 = Point(3, 5)
point2 = Point(3, 5)
print(point1 == point2)
# 输出: True
11. __ne__
- 用途:用于定义对象之间的不等比较操作。当使用
!=
运算符比较两个对象时,如果对象所属类定义了__ne__
因。不同的类可以根据自身的需求定义不同的不等比较规则。 - 示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __ne__(self, other):
return self.x != other.x or self.y != other.y
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1 != p2)
12. __lt__
- 用途:用于定义对象之间的小于比较操作。当使用
<
运算符比较两个对象时,如果对象所属类定义了__lt__
方法,就会调用该方法来判断两个对象是否满足小于关系。不同的类可以根据自身的需求定义不同的小于比较规则。 - 示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __lt__(self, other):
return self.x < other.x
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1 < p2)
13. __gt__
- 用途:用于定义对象之间的大于比较操作。当使用
>
运算符比较两个对象时,如果对象所属类定义了__gt__
方法,就会调用该方法来判断两个对象是否满足大于关系。不同的类可以根据自身的需求定义不同的大于比较规则。 - 示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __gt__(self, other):
return self.x > other.x
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1 > p2)
14. __le__
- 用途:用于定义对象之间的小于等于比较操作。当使用
<=
运算符比较两个对象时,如果对象所属类定义了 le 方法,就会调用该方法来判断两个所对象是否满足小于等于关系。不同的类可以根据自身的需求定义不同的小于等于比较规则。 - 示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __le__(self, other):
return self.x <= other.x and self.y <= other.y
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1 <= p2)
15. __ge__
- 用途:用于定义对象之间的大于等于比较操作。当使用
>=
运算符比较两个对象时,如果对象所属类定义了 ge 方法,就会调用该方法来判断两个所对象是否满足大于等于关系。不同的类可以根据自身的需求定义不同的大于等于比较规则。 - 示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __ge__(self, other):
return self.x >= other.x or self.y >= other.y
p1 = Point(1, 2)
p2 = Point(3, 4)
print(p1 >= p2)
这些特殊方法在实现类的各种特性,如对象的字符串表示、可迭代性、比较操作等方面发挥着重要作用,是 Python 面向对象编程中非常重要的部分。