在Python中,类特殊成员是指以双下划线开头和结尾的属性和方法,也被称为魔术方法(Magic methods)或特殊方法(Special methods)。这些特殊成员在类的定义中具有特殊的语法和功能,用于实现对象的特定行为和操作。
特殊方法一般由Python解释器调用,无需手动调用。通过在类中定义这些特殊方法,可以改变对象的默认行为,使其具备更多的功能和操作。特殊方法提供了一种更加Pythonic的面向对象编程的方式,可以让代码更加简洁和易读。
__init__
__init__是Python中的一个特殊方法,也被称为构造方法。它在创建对象时自动调用,用于初始化对象的属性。通过在类中定义__init__方法,我们可以在对象创建时为其赋予初始状态,设置属性的默认值,或执行其他必要的初始化操作。
__init__方法的格式通常如下:
def __init__(self, arg1, arg2, ...):
self.attribute1 = arg1
self.attribute2 = arg2
# ...
self代表对象本身,arg1、arg2等是用于接收传入的参数的形参,我们可以根据实际需要为__init__方法传入不同的参数。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person1 = Person("Alittle", 30)
在__init__方法中,我们可以执行其他的初始化操作,例如连接数据库、打开文件、设置默认值等。这使得我们能够在创建对象时,做一些必要的准备工作,确保对象在初始化后即可用。
需要注意的是,Python 中的__init__方法是可选的,不是必须定义的。如果类中没有定义__init__方法,Python 会使用默认的空的__init__方法。但通常情况下,我们会定义__init__方法来初始化对象的属性。
__del__
__del__是Python中的一个特殊方法,也被称为析构方法。它在对象被销毁前自动调用,用于进行清理工作。当对象的引用计数为零时(即没有任何变量引用该对象),Python解释器会自动触发__del__方法的调用。
__del__方法的格式通常如下:
def __del__(self):
# 清理代码
在__del__方法中,self代表对象本身。我们可以在__del__方法中编写需要在对象销毁之前执行的清理代码,例如关闭文件、释放资源、记录日志等。
另外需要注意的是,__del__方法的调用是由Python解释器自动控制的,并不是我们手动调用的。因此,我们不能依赖__del__方法来进行关键性的清理工作,如释放内存。一般来说,Python有自己的垃圾回收机制,会自动管理对象的内存释放。我们只需确保在__del__方法中执行一些简单的清理操作即可。此外,应尽量避免在__del__方法中抛出异常,以免影响其他代码的执行。
__str__
__str__也是Python中的一个特殊方法,也被称为字符串表示方法。它定义了当我们对一个对象使用内置的str()函数或print()函数进行输出时,应该返回的字符串形式表示。简而言之,__str__方法用于定制对象的字符串输出。
__str__方法的格式通常如下:
def __str__(self):
# 返回表示对象的字符串
在__str__方法中,self代表对象本身,没有其他的参数了,我们可以在该方法中编写需要返回的表示对象的字符串形式的代码,例如组织对象的属性信息、状态等。
以下是一个示例,展示了如何使用__str__方法来定制对象的字符串输出:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
print("call __str__")
return f"Point({self.x}, {self.y})"
p = Point(3, 4)
print(p)
print("-----------------")
str(p)
上面的示例中的输出
call __str__
Point(3, 4)
-----------------
call __str__
我们定义了一个Point类,其中的__init__方法用于初始化点的坐标。在__str__方法中,我们使用格式化字符串 f-string 将点的坐标表示为 '(x, y)' 的形式。当我们对p对象使用print(p)和str(p)时,会自动调用__str__方法,并返回该方法中定义的字符串(3, 4)。
__repr__
__repr__与__str__方法类似,下面直接用一个例子来说明这个和__str__的区别。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
print("call __str__")
return f"Point1({self.x}, {self.y})"
def __repr__(self):
print("call __repr__")
return f"Point2({self.x}, {self.y})"
p = Point(3, 4)
print(p)
print("-----------------")
str(p)
repr(p)
上面的示例中的输出
call __str__
Point1(3, 4)
-----------------
call __str__
call __repr__
从上面的输出可以看出,repr(p)函数可以自动调用__repr__,默认情况下,__str__和__repr__同时存在的话,str()和print()函数就会优先调用__str__,而如果只有__repr__的话,就会调用__repr__,不信你们可以把上面例子中的__str__注释掉,然后看看输出情况。
__len__
__len__用于定义对象的长度。它主要被用于内置函数len()的操作,用于返回一个对象的长度或元素的个数。
__len__方法的格式通常如下:
def __len__(self):
# 返回对象的长度或元素的个数
在__len__方法中,self代表对象本身。我们可以在该方法中编写代码,返回一个整数,表示对象的长度或元素的个数。
以下是一个示例,展示了如何使用__len__方法来定义一个自定义的容器类并使用len()函数获取其长度:
在上面的示例中,我们定义了一个名为MyContainer的容器类,该类包含一个名为data的列表用于存储元素。在__len__方法中,我们使用内置函数len()计算了data列表的长度,并返回该长度。当我们通过调用len(container)来获取container对象的长度时,实际上会自动调用__len__方法,并返回该方法中定义的长度值。
__len__方法应该返回一个整数,表示对象的长度或元素的个数。如果一个类没有定义__len__方法,或者__len__方法返回的值不是整数类型,那么调用len()函数时会抛出TypeError异常。
__getitem__和__setitem__
__getitem__和__setitem__几乎都是成对出现的,__getitem__用于定义对象的索引操作,即允许通过索引值访问对象的元素,__setitem__用于定义对象的赋值操作,即允许通过索引值设置对象的元素值,它主要用于支持下标操作和切片操作。
__getitem__和__setitem__方法的格式通常如下:
def __getitem__(self, index):
# 返回指定索引位置的元素
def __setitem__(self, index, value):
# 设置指定索引位置的元素为指定的值
这两个方法一个就是取值,一个就是赋值,主要就是应用在对象上面,相对而言比较好理解。
class MyList:
def __init__(self):
self.data = []
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
mylist = MyList()
mylist.data = [1, 2, 3, 4, 5]
print(mylist[2]) # 输出 3,调用了 __getitem__ 方法
mylist[2] = 10 # 调用了 __setitem__ 方法赋值
print(mylist[2]) # 输出 10,调用了 __getitem__ 方法
在上面的示例中,我们定义了一个名为MyList的列表类,该类包含一个名为data的列表用于存储元素。通过实现__getitem__和__setitem__方法,我们可以使用类似于列表的方式通过索引来访问和设置data列表中的元素。__getitem__方法通常与__setitem__方法一起使用,以支持对象的索引和切片操作。通过定义这些方法,我们可以使自定义的类对象能够像内置的容器类型一样进行元素的访问和修改。
如果一个类没有定义__getitem__和__setitem__方法,或者__getitem__和__setitem__方法不能处理给定的索引值或切片对象,那么当我们尝试通过索引或切片来访问(设置)对象时,会抛出TypeError异常。
__call__
__call__用于使对象能够像函数一样被调用。通过定义__call__方法,我们可以将一个对象变成一个可调用的实例,类似于函数的行为。
__call__方法的格式通常如下:
def __call__(self, *args, **kwargs):
# 定义对象的调用逻辑
在__call__方法中,self代表对象本身,args和kwargs是传递给对象调用时的参数。
当我们像调函数一样使用对象时,Python 解释会自动调用对象的__call__方法,并将传入的参数作为参数递给该方法。我们可以在__call__方法中定义对象的调用逻,然后执行相应的操作。
以下一个示例,展示了如何使用__call__方法来定义一个可调用的对象:
class Adder:
def __call__(self, x, y):
return x + y
add = Adder()
# 将对象 add 当作函数进行调用
result = add(3, 5)
print(result) # 输出:8
在上述示例中,我们定义了一个Adder类,并实现了__call__方法。在该方法中,我们将传入的两个参数进行相加,Python 解释器会自动调用对象add的__call__方法,并将传递给该方法。__call__方法中的逻辑会被执行,参数进行相加操作,然后返回结果。
通过使用__call__方法,我们可以将一个对象实例化后,即可像函数一样进行调用,并执行预定义的逻辑。这样可以增加对象的灵活性,使其更加接近函数的行为。__call__方法只有在对象被调用时才会被调用,也就是对象被函数那样调用。
通常情况下,__call__方法常用于实现可调用的对象,如自定义的函数对象、装饰器、上下文管理器等。通过定义__call__方法,我们可以使对象具有函数的特性,并能够直接调用执行相应的逻辑。
领取专属 10元无门槛券
私享最新 技术干货