1.魔术方法 __new__
'''
触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
功能:控制对象的创建过程
参数:至少一个cls接受当前的类,其他根据情况决定
返回值:通常返回对象或None
'''
注意:python3.x 新式类 python2.x 旧式类, 新式类不需要每次都写一次object,默认继承控制创建的对象。
class MyClass2(): abc = 1 obj2 = MyClass2() class MyClass(object): def __new__(cls): print(cls) # <class '__main__.MyClass'>
# 借助object父类方法里面__new__ 来为本类创建一个对象
# return object.__new__(cls) # 返回一个本类对象
# return None # 返回一个空对象
return obj2 # 返回的是一个其他类的对象
pass
# 实例化对象obj
obj = MyClass() print(obj) print(obj.abc)
执行结果如下:
1.1.对比__new__和 __init__的触发时机
__new__ 魔术方法是用来创建对象的 __init__魔术方法是用来初始化对象的 得现有对象,才能够初始化,没有对象初始化谁? __new__ 的触发时机要快于__init__ __new__ __init__ 这两个方法的参数要一一匹配.
1.2.__new__ __init__这两个方法中的参数一一匹配
#(1)一个参数的类型
class Boat(): def __new__(cls, name): print(1) return object.__new__(cls) def __init__(self, name): self.name = name obj = Boat("大锤") #(2)无限个参数
class Boat(): def __new__(cls, *args, **kwargs): print(1) return object.__new__(cls) def __init__(self, *args, **kwargs): strvar = ""
for i in args: strvar += i + " "
print("小船的贡献者有:", strvar) print("小船的名字是{}".format(kwargs['name'])) obj = Boat("王俊文", "舒畅", "境泽年", "五金玲", name="Anglelababy")
代码运行结果:
注意:如果通过__new__返回的是其他类的对象,不会触发到自己的__init__ ,因为__init__初始化的是本类的对象。
例:
class Boat(): def __new__(cls, *args, **kwargs): return obj2 #返回的是MyClass()类中产生的对象 def __init__(self): print("init调用了") obj = Boat() print(obj.abc)
代码运行结果为:
即是1.中我们定义的对象obj2 = MyClass2()中的属性,即是输出123,实际 def __init__()
这初始化函数没有运行,因为我们定义__new__返回的是MyClass2()类中产生的对象obj2,
obj2调用类中的公有属性最后输出结果为123
2.单态模式
无论实例化多少次,都有且只有一个对象.最终目的:为了节省内存空间.应用的场景是只调用相关的成员属性或方法,而不用动态
添加成员属性方法的环境中。
2.1 基本用法
class Singleton(): __obj = None def __new__(cls): if cls.__obj is None: # 借助父类创建对象
obj = object.__new__(cls) # 把这个对象赋值给类中成员属性__obj
cls.__obj = obj return cls.__obj
# 第一次创建时,因为cls.__obj 是None 所以创建一个对象
obj = Singleton() print(obj) # 第二次实例化时,因为cls.__obj 不是None ,直接返回上一次创建的那个对象
obj = Singleton() print(obj) # 第三次实例化时,同第二次
obj = Singleton() print(obj) obj = Singleton() print(obj) obj = Singleton() print(obj).
代码运行结果:
总结:可以借助创建一个私有属性,默认为None,那么第一次实例化会利用__new__创建一个Singleton类的
对象,通过cls.__obj = obj赋值把已创建的对象赋值给cls.__obj。假使是第二次实例化的时,我们发现
Singleton有这属性(或者这个属性不是空),那么我们就不用用__new__创建对象这样就能达到单态,即是
只有一个内存空间的办法,从而节省内存空间。
对上面的代码就行稍作改造:
lass Singleton(): __obj = None def __new__(cls,*args,**kwargs): if cls.__obj is None: cls.__obj = object.__new__(cls) return cls.__obj def __init__(self,name): self.name = name obj1 = Singleton("王波") obj2 = Singleton("方真强") print(obj1.name) print(obj2.name)
运行结果:
总结:创建的obj1、obj2对象同时指向了Singleton类,所以最后访问的是obj2的name属性。
详解:
第一次是创建对象,并且通过init初始化对象,为该对象赋值成员属性name
self.name = 王波
第二次是直接返回上一个对象,然后对他进行初始化,为该对象赋值成员属性name
self.name = 方真强
两个不同的变量名指向的是同一个对象
而此时该对象的成员属性name 这个值是方真强
print(obj1.name)
print(obj2.name)
打印的都是方真强
3.__del__析构方法 __init__构造方法
触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候] 功能:对象使用完毕后资源回收 参数:一个self接受对象 返回值:无
3.1页面执行完毕回收所有变量:
class LangDog(): def __init__(self,name): self.name = name def eat(self,something): print("可爱的小狼{},喜欢吃{}".format(self.name,something)) def __del__(self): print("__del__方法被触发") # (1) 1.页面执行完毕回收所有变量 obj = LangDog("詹姆斯·狗蛋") obj.eat("屎") print("<===>")
代码执行结果:
3.2 触发__del__机制中的第二点所有对象被del删除时候。
所有对象被del的时候只有当所有指向该对象的变量都删除的时候,才算真正的删除该对象。
class LangDog(): def __init__(self,name): self.name = name def eat(self,something): print("可爱的小狼{},喜欢吃{}".format(self.name,something)) def __del__(self): print("__del__方法被触发") # (1) 1.页面执行完毕回收所有变量 obj = LangDog("詹姆斯·狗蛋") obj.eat("屎") print("<===>") # (2) 2.所有对象被del的时候 ''' 只有当所有指向该对象的变量都删除的时候,才算真正的删除该对象 ''' obj2 = obj print("<==start===>") del obj del obj2 print("<==end===>")
代码执行结果:
3.3 用类来模仿文件的写操作
一个普通文件的写入和读写操作如下:
# fp = open("ceshi111.txt",mode="w",encoding="utf-8") # fp.write("sfdsdf") # fp.close()
# fp = open("ceshi111.txt",mode="r",encoding="utf-8") # res = fp.read() # fp.close() # print(res)
总结:打开 -写入文件内容/读出文件内容-关闭文件
用面对对象的写法如下:
import os class MyFile(): # 判断是否创建MyFile该对象 def __new__(cls,filename): if os.path.exists(filename): return object.__new__(cls) return print("该文件不存在") # 产生文件对象 def __init__(self,filename): self.fp = open(filename,mode="r",encoding="utf-8") # 读取文件 def readfile(self): res = self.fp.read() return res def __del__(self): print(0) # 自动触发__del__ ,帮助我们关闭文件 self.fp.close() obj = MyFile("ceshi222.txt") res = obj.readfile() print(res) 代码输出: 即是文件的内容结果,需要传入MyFile类中一个参数即是文件("ceshi222.txt")
4.魔术方法
4.1__call__的魔术方法
触发时机:把对象当作函数调用的时候自动触发
功能: 模拟函数化操作
参数: 参数不固定,至少一个self参数
返回值: 看需求
基本语法:
class MyClass(): def __call__(self): print("__call__方法被调用") return "done" obj = MyClass() res = obj()#也就是函数在调用的时候触发__call__ print(res)
代码执行结果如下:
4.2利用__call__这个特性写一个洗衣服的流程
如下:
class Wash():
# 使用call方法,进行统一的调用 def __call__(self, something): self.something = something print("以下是洗{}的过程:".format(something)) self.step1() self.step2() self.step3() def step1(self): print("第一步放水,把{}扔盆里".format(self.something)) def step2(self): print("第二部导入洗衣液,金纺,蓝月亮,吊牌洗衣皂扔盆里搓") def step3(self): print("第三部晒一下,穿上")
obj = Wash() #用户使用Wash类的时候,只需要调用Wash就可以了,不用利用创建的obj对象依次调用洗衣的步骤,简单方便
obj("裤衩")
代码运行结果:
# 如果用户不采用内部写一个__call__方法的话,会一直用对象去调用,导致非常的不方便。
# 一边写一边骂街
# obj.step1()
# obj.step2()
# obj.step3()
4.2.1 利用__call__的触发机制(把对象当函数调用的时候会自动触发),写一个模拟内置int方法实现myint
代码如下:
import math class MyInt(): def stoi(self, n, sign=1): res = n.lstrip("0") if res == "": return 0 num = eval(res) * sign return num def __call__(self, n): # 判断的是布尔类型 if isinstance(n, bool): if n == True: return 1 else: return 0 # 判断的是整型 elif isinstance(n, int): return n # 判断的是浮点型 elif isinstance(n, float): if n < 0: return math.ceil(n) else: return math.floor(n) # 判断的是字符串 elif isinstance(n, str): if (n[0] == "-" or n[0] == "+") and n[1:].isdecimal(): if n[0] == "+": sign = 1 elif n[0] == "-": sign = -1 return self.stoi(n[1:], sign) elif n.isdecimal(): # 如果能够走到这个条件,一定没有带任何正负号 return self.stoi(n) else: return "对不起,老弟,这个算不了" else: print("对不起,老哥,这个算不了")
myint = MyInt()
res = myint("12233")
print(res)
print(myint("+000000000333333"))
print(myint("00000000000"))
print(myint("-0000000000078"))
print(myint(-7.6))
print(myint(8.8))
print(myint(False))
print(myint(True))
print(myint(4))
print(myint([1, 3, 4]))
代码执行结果:
可以说我们这个功能比内置的int还牛逼!
4.3 __str__方法
触发时机: 使用print(对象)或者str(对象)的时候触发
功能: 查看对象
参数: 一个self接受当前对象
返回值: 必须返回字符串类型
class Cat(): gift = "抓老鼠" def __init__(self,name): self.name = name def cat_info(self): strvar = "这个对象的名字{},这个对象的天赋:{}".format(self.name,self.gift) return strvar def __str__(self): return self.cat_info() tom = Cat("汤姆") # (1) 打印对象触发__str__方法 # print(tom) # (2) str强转对象时候触发__str__方法 res = str(tom) print(res)
代码执行结果如下:
4.4 __repr__ 方法
触发时机: 使用repr(对象)的时候触发
功能: 查看对象,与魔术方法__str__相似
参数: 一个self接受当前对象
返回值: 必须返回字符串类型
例:
class Mouse(): gift = "打洞" def __init__(self,name): self.name = name def mouse_info(self): strvar = "该对象的名字{},它的天赋是{},龙胜龙,凤生凤,老鼠的儿子会打洞".format(self.name,self.gift) return strvar def __repr__(self): return self.mouse_info() # 在系统的底层加了如下一句话:如果存在__repr__ 这个方法,就把它赋值给__str__ # __str__ = __repr__ jerry = Mouse("杰瑞") # res = repr(jerry) # print(res) print(jerry)
代码运行结果:
4.5 __bool__ 方法
触发时机:使用bool(对象)的时候自动触发 功能:强转对象 参数:一个self接受当前对象 返回值:必须是布尔类型 类似的还有如下等等(了解): __complex__(self) 被complex强转对象时调用 __int__(self) 被int强转对象时调用 __float__(self) 被float强转对象时调用
代码:
class MyBool(): def __bool__(self): print(122) # return True return False
运行结果如下:
4.6__add__ 方法
触发时机:使用对象进行运算相加的时候自动触发 功能:对象运算 参数:二个对象参数 返回值:运算后的值
类似的还有如下等等(了解):
__sub__(self, other) 定义减法的行为:-
__mul__(self, other) 定义乘法的行为:
__truediv__(self, other) 定义真除法的行为:/
例:
class MyAdd(): def __init__(self, num): self.num = num # 对象+数值,并且对象在+加号的左边,自动触发__add__方法 def __add__(self, other): # self.num => 3 + 56 => 59 return self.num + other def __radd__(self, other): # self 接受b, other 接受33 return self.num + other * 10 # 1.当对象在加号的左侧 自动触发add 方法 a = MyAdd(3) res = a + 56 print(res) # 2.当对象在加号的右侧 自动触发radd 方法 b = MyAdd(5) res = 33 + b print(res) # 3 a+b =? res = a + b print(res) ''' a在加号的左侧,触发add魔术方法 self.num + other => 3 + b b在加号的右侧,触发radd魔术方法 res = 3+b self.num + other * 10 => 5 + 3 *10 => 35
代码运行结果如下:
*4.7 __len__方法
触发时机:使用len(对象)的时候自动触发
功能:用于检测对象中或者类中某个内容的个数
参数:一个self接受当前对象
返回值:必须返回整型
用len(对象)方式,算出该对象所归属的类有多少自定义成员
class MyLen(): pty1 = 1 pty2 = 2 __pty3 = 3 def func1(): pass def func2(): pass def __func3(): pass def __func4(): pass def __func5(): pass def __len__(self): # print(MyLen.__dict__) 打印结果如下分析 dic = MyLen.__dict__ lst = [i for i in dic if not(i.startswith("__") and i.endswith("__"))] num = len(lst) return num obj = MyLen() res = len(obj) print(res) """分析 {'__module__': '__main__', 'pty1': 1, 'pty2': 2, '_MyLen__pty3': 3, 'func1': <function MyLen.func1 at 0x7f10880d9620>, 'func2': <function MyLen.func2 at 0x7f10880d96a8>, '_MyLen__func3': <function MyLen.__func3 at 0x7f10880d9730>, '__len__': <function MyLen.__len__ at 0x7f10880d97b8>, '__dict__': <attribute '__dict__' of 'MyLen' objects>, '__weakref__': <attribute '__weakref__' of 'MyLen' objects>, '__doc__': None} """
运行代码结果如下: