在学习面向对象的时候,我们知道在 python 中有一类特殊的方法,叫做魔法方法,这种方法的特点如下:
- 方法定义的时候以两个下划线开头和两个下划线结尾:如
__init__
、__str__
和__repr__
- 这类方法一般不需要我们手动调用,在满足某个条件的时候会自动调用,这个满足的条件我们可以成为调用时机
__str__()
方法
这个类方法(str())主要的作用是在print(实例)的时候返回你指定的字符串,一般来说在定义类的时候不用重写这个方法的,但是在一些注重交互的模块类的编写上,可能会重写这个类。下面直接进入例子。
class Car():
def __init__(self,name):
self.name = name
接下来我们实例化这个类,并打印这个实例。
A = Car('BNW')
print(A)
我们一般就能看到这样的结果:
<__main__.Car object at 0x000002B249DD4E20>
这个结果主要是告诉我们这个A是哪一个类(Car类),还有所在内存位置(0x000002B249DD4E20)
下面我们在Car类中重写__str__方法,再打印这个A,看看会有什么差别。
class Car():
def __init__(self, name):
self.name = name
def __str__(self) -> str:
text = f'这是一辆车,名字是{self.name}'
return text
A = Car('BNW')
print(A)
这是一辆车,名字是BNW
可以看到,这个时候print(实例),将会出现我们指定好的str内容。这就是__str__()方法的用处,不过要注意,这个方法必须要保证返回的是一个str。
对一个对象打印时,自动执行 str 方法
class A:
def __init__(self, name, age):
self.name = name
self.age = age
self.sex = "男"
def __str__(self):
print(555)
return "abc"
a1 = A("尘世风", 18)
# 对一个对象打印时,自动执行 __str__ 方法
print(a1)
# 运行结果:
# 555
# abc
__len__()
方法
len()可以检测对象中某个数据得信息,只有一个参数self,用于接收当前对象,它必须有返回值,返回值必须是整数;
当我们不使用__len__()方法检测对象时,会报TypeError: object of type ‘UseLen’ has no len()错误
class UseLen(object):
def __init__(self, age):
self.age = age
self.li = ['a', 'v', 's']
U = UseLen(12)
print(len(U))
Traceback (most recent call last):
File "D:\code\xmczapitest\test.py", line 7, in <module>
print(len(U))
TypeError: object of type 'UseLen' has no len()
当我们使用__len__方法检测对象时,需要注意的是必须有返回值,方法中只有一个self参数
class UseLen(object):
def __init__(self, age):
self.age = age
self.li = ['a', 'v', 's']
def __len__(self):
return len(self.__dict__)
U = UseLen(12)
print(len(U)) # 2
__call__
方法
__call__可以使得方法变成可被调用对象
class Foo:
def __init__(self):
print("实例化一个对象时自动执行 __init__ 方法")
def __call__(self, *args, **kwargs):
print('调用实例化对象时自动触发 __call__ 方法')
obj = Foo() # 实例化一个对象时自动执行 __init__ 方法
obj() # 调用实例化对象时自动触发 __call__ 方法
new() 方法
当Python实例化一个对象时,首先调用__new__()方法构造一个类的实例,并为其分配对应类型的内存空间,该实例的内存地址就是它的唯一标识符。然后再调用__init__()方法对实例进行初始化,通常是对该实例的属性进行初始化
以下用几个实例来说明:
实例1:先调用__new__()方法再调用__init__()方法
class Person(object):
def __new__(cls):
print("__new__ called")
return super().__new__(cls)
def __init__(self):
print("__init__ called")
a = Person()
结果
__new__ called
__init__ called
实例2:new()方法构造一个类实例,并将该实例传递给自身的__init__()方法,即__init__()方法的self参数。
class Person(object):
def __new__(cls):
print("__new__ called")
instance = super().__new__(cls)
print(type(instance))
print(instance)
print(id(instance))
return instance
def __init__(self):
print("__init__ called")
print(id(self))
b = Person()
结果
__new__ called
<class '__main__.Person'>
<__main__.Person object at 0x0000026D76844DC0>
2669163072960
__init__ called
2669163072960
实例3:如果__new__()方法不返回任何实例的话,init()方法将不会被调用。
class Person(object):
def __new__(cls):
print("__new__ called")
def __init__(self):
print("__init__ called")
c = Person()
结果:
__new__ called
实例4:如果__new__()方法返回一个其他类的实例的话,那它自身的__init__()方法将不会被调用。而且,new()方法将会初始化一个其他类的对象。
class Animal(object):
def __init__(self):
pass
class Person(object):
def __new__(cls):
print("__new__ called")
return Animal()
def __init__(self):
print("__init__ called")
d = Person()
print(type(d))
print(d)
结果:
__new__ called
<class '__main__.Animal'>
<__main__.Animal object at 0x0000022BDDEEF400>
实例5:如果重写__new__()方法时,除了cls参数外不再设置其他参数的话,将无法用__init__()方法来设置初始化参数。
class Person(object):
def __new__(cls):
print("__new__ called")
instance = super().__new__(cls)
return instance
def __init__(self, name):
print("__init__ called")
self.name = name
e = Person("Alice")
print(e.name) # TypeError: Person.__new__() takes 1 positional argument but 2 were given
实例6:在重写__new__()方法时,需要在参数中加入*args,**kwargs,或者显式地加入对应的参数,才能通过__init__()方法初始化参数。
class Person(object):
def __new__(cls, *args,**kwargs): # Or def __new__(cls, name)
print("__new__ called")
instance = super().__new__(cls)
return instance
def __init__(self, name):
print("__init__ called")
self.name = name
e = Person("Alice")
print(e.name)
结果:
__new__ called
__init__ called
Alice