目录
1.若没创建过类,就创建一个,并保存起来,再修改类属性的值。
1.内置函数str(),print(),format()处理对象时,都会触发对象对应的__str__方法。
2.内置函数repr()处理对象时,会触发对象对应的__repr__方法。
1.如果想类创建出来的对象可以像函数一样+()就能被调用,就需要在类中定义__call__方法
魔术方法(魔法方法,特殊方法):
魔术方法都是Python内部定义的,不用自己去定义的类似__init__()这种双下划线开头或结尾的方法。
一。__new__方法和__init__:
__new__方法在父类object中已经实现,若子类中再出现,就属于重写父类中的方法; new方法是用来创建对象的,应该返回一个对象,若不return一个对象,init方法无法执行,没有对象可初始化。 创建对象是Python中内置实现的, 我们无法实现,此时重写new方法时,可以直接通过: 1.super().方法名; 2.父类名.方法名; 来调用父类中的方法,通过父类的new方法创建对象并返回给我们
在创建对象的时候自动调用__init__()方法内部的代码,对创建的对象进行初始化设置。
class MyClass(object):
def __init__(self, name):
"""创建对象时会自动初始化对象属性"""
print('这是init方法')
self.name = name
print("__init__的self.name", self.name)
def __new__(cls, *args, **kwargs):
"""
new一个对象,比__init__方法先执行
__new__方法在父类object中已经实现,若子类中再出现,就属于重写父类中的方法;
new方法是用来创建对象的,应该返回一个对象,创建对象是Python中内置实现的,
我们无法实现,此时重写new方法时,可以直接通过:
1.super().方法名;
2.父类名.方法名;
来调用父类中的方法,通过父类的new方法创建对象并返回给我们
"""
print('这是new方法')
# 此处若不return一个对象,init方法无法执行,因为没有对象可初始化
# return object.__new__(cls)
return super().__new__(cls)
if __name__ == '__main__':
m = MyClass('春田')
# 输出:
这是new方法
这是init方法
__init__的self.name
春田
二。重写__new__()方法的应用场景:单例模式
比如我们有个配置类,不管哪里调用用的都是同一个配置,我们不管在哪个模块中导入这个类,在创建对象的时候,用的都是之前创建的同一个配置类的对象,不会在不同的地方单独创建对象了,所以可用单例模式实现类,这样就可以节省内存空间。
思路:
1.定义一个类属性,用来记录该类是否被创建过对象。
2.在__new__()方法中对类属性做判断:
1.若没创建过类,就创建一个,并保存起来,再修改类属性的值。
2.若创建过了,就将之前创建的返回出去。
单例模式:
class Test(object):
"""
如果类属性 __instance为None,则创建一个对象,并且将 __instance赋值为这个对象的引用,
保证下次调用这个方法能知道这个类已经创建过对象了,这样就保证了始终只有1个对象。
"""
__instance = None # 设置一个类属性,用来记录该类有没有创建过对象
def __new__(cls, *args, **kwargs):
if not cls.__instance: # 如果没有对象(cls就是类本身)
# if Test.__instance is None: # 效果同上
# 创建一个,并赋值给cls.__instance保存
cls.__instance = super().__new__(cls)
# 返回对象
return cls.__instance
else:
# 返回对象
return cls.__instance
if __name__ == '__main__':
a = Test()
b = Test()
print(id(a)) # 输出:140505293127392
print(id(b)) # 输出:140505293127392
a.name = "春田"
print(b.name) # 输出:春田
3.装饰器实现单例模式
被装饰器装饰的类,是单例类。
# 装饰器实现单例模式,被装饰的类,无论实例化多少次都只有一个对象。
def single(func):
__instance = {} # __instance 用来记录是否存在对象
def wrapper(*args, **kwargs):
if func not in __instance: # 判断是否存在对象
__instance[func] = func(*args, **kwargs)
return __instance[func]
else:
return __instance.get(func)
return wrapper
@single
class Test(object):
def add(self):
print('方法名是:add')
if __name__ == '__main__':
t = Test()
print(t)
print(id(t)) # 输出:4517363520
t2 = Test()
print(id(t2)) # 输出:4517363520
t.add() # 输出:方法名是:add
三。__str__()方法和__repr__()方法:
1.内置函数str(),print(),format()处理对象时,都会触发对象对应的__str__方法。
使用str,print,format处理对象会优先触发__str__方法,在没定义__str__方法时,
再去找__repr__方法,如果都没有,会再去找父类的__str__方法。
2.内置函数repr()处理对象时,会触发对象对应的__repr__方法。
使用repr方法或在交互环境下输入变量,会先找自身的__repr__方法,自身没有__repr__方法
时,再去找父类的__repr__方法。
class MyClass(object):
def __init__(self, name):
self.name = name
def __str__(self):
print('---str---方法触发了')
return self.name # __str__方法必须返回字符串,否则type错误。
def __repr__(self):
print('---repr---方法触发了')
return '对象类型是{}'.format(self.name) # __repr__方法必须返回字符串,否则type错误。
if __name__ == '__main__':
m = MyClass('春田')
# print,str,format函数会触发对象的__str__方法
print(m) # 输出:
# ---str - --方法触发了
# 春田
# repr函数会触发对象的__repr__方法
res = repr(m)
print(res) # 输出:
# ---repr - --方法触发了
# 对象类型是春田
四。__call__()方法
1.如果想类创建出来的对象可以像函数一样+()就能被调用,就需要在类中定义__call__方法
class MyClass(object):
def __init__(self, name):
self.name = name
def __call__(self, *args, **kwargs):
print('---call--方法触发了') # 对象在像函数一样被调用时触发__call__方法。
if __name__ == '__main__':
m = MyClass("春田")
m() # 像函数一样调用对象。
# 输出: ---call--方法触发了
2. 通过类来实现装饰器:
在类中实现__call__()方法
import time
class Timer(object):
"""通过类实现装饰器"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
st = time.time()
time.sleep(2)
self.func(*args, **kwargs)
time.sleep(2)
et = time.time()
print('{}函数执行耗时:{}'.format(self.func.__name__, et - st))
@Timer
def func(a, b):
return a + b
if __name__ == '__main__':
func(1, 2) # 输出:func函数执行耗时:4.010028839111328