Python 基础之面向对象之常用魔术方法

一.__init__魔术属性

触发时机:实例化对象,初始化的时候触发
功能:为对象添加成员,用来做初始化的
参数:参数不固定,至少一个self参数
返回值:

1.基本用法

#例:
class MyClass():
    def __init__(self):
        #print(111)
        self.name = "one"
#实例化对象 [类的实例化]
obj = MyClass()
print(obj.name)

2.__init__可以传递多个参数

#例:
class MyClass():
    def __init__(self,name):
        #self.name 这个name是成员输出name
        #self.name = name 后面的name是传进来的参数
        self.name = name

#类的实例化 实例化对象
#把参数传递到MyClass 后面的这个括号里
obj = MyClass("TWO")
print(obj.name)

3.综合案例

类可以是一个,但对象可以是多个,对象之间彼此独立
#例:
class Children():
    def __init__(self,name,eyes_color):
        self.name = name
        self.eyes_color = eyes_color
    def eat(self):
        print("小孩子生下来的时候,饿了就会吃东西")
    def drink(self):
        print("小孩子生下来的时候,渴了就会喝东西")

def smile(self):
        print("小孩在只要不饿不渴就会经常笑")
    def obj_info(self):
        print("小孩的姓名:{},小孩的眼睛的颜色:{}".format(self.name,self.eyes_color))
'''
同一个类产生三个对象,但是每个对象彼此都是堵路的
而且都可以调用类中的公有成员属性方法
'''
child1 = Children("ONE","blue")
child1.obj_info()
child1.eat()
print("====================")
child2 = Children("two","blown")
child2.obj_info()
child2.smile()
print("3======================")
child3 = Children('three','red')
child3.obj_info()
child3.drink()

二.__new__

触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
#自己理解:只要有实例化那个类,类里面的new
功能:控制对象的创建过程
参数:至少一个cls接受当前的类,其他根据情况决定
返回值:通常返回对象或None

1.基本用法

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(obj2.abc)

2.对比__new____init__的触发时机

__new__ 魔术方法是用来创建对象的
__init__ 魔术方法是用来初始化对象的
得现有对象,才能初始化,没有对象初始化谁?
__new__的触发时机要快于__init__
__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("one", "two", "three", "four", name="five")
#运行结果:

1

小船的贡献值有:  one two three four

小船的名字是: five

#因为调用了Boat即触发new 和 init魔术属性,init对类进行初始化

(3)如果通过__new__返回的是其他类的对象,不会触发自己本类的__init__

#因为__init__初始化的是本类对象
#例:

class MyClass2():
    abc = 3
obj2 = MyClass2()
class Boat():
    def __new__(cls,*args,**kwargs):
        return obj2  #返回的是最上面的obj2
    def __init__(self):
        print("init调用了")
obj = Boat()
print(obj.abc)

#运行结果为:

3

#因为__new__在__init__创建之前调用,而new里调用的是MyClass的对象,所有输出3,而并没有调用本类的对象,__new__返回的是其他类的对象,不会触发自己本类的__init__

3.单态模式(单例模式)

无论实例化多少次,都有且只有一个对象
最终目的:为了节省内存空间,应用的场景是只调用相关的成员属性或方法,而不用动态添加成员属性方法的环境中'''
__obj 变成私有,控制不让用户在类外直接获取obj,而是用__new__来控制返回的逻辑
先判断cls.__obj 是不是None
如果是None,代表是一个空的对象,那么就利用父类的__new__方法来创建对象
如果不是一个空对象,代表先前早已实例化过一个对象
就把这个对象给他返回

(1)基本用法

class Singleton():
    __obj = None
    def __new__(cls, *args, **kwargs):
        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)

(2)改造

class 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("one")
obj2 = Singleton("two")
print(obj1.name)
print(obj2.name)

#解析:
第一次是创建对象,并且通过init初始化对象,为该对象赋值成员属性name
self.name = one
第二次是直接返回上一次对象,然后对他进行初始化,为该对象赋值成员属性name
self.name = two
两个不同的变量名指向的是同一个对象
而此时该对象的成员属性name 这个值是two
print(obj1.name)
print(obj2.name)
打印的都是two

三.__del__ 析构方法 __init__ 构造方法

触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候]
功能:对象使用完毕后资源回收
参数:一个self接受对象
 返回值:
#例:
class Dog():
    def __init__(self,name):
        self.name = name

def eat(self,something):
        print("可爱的小狗{},喜欢吃{}".format(self.name,something))

def __del__(self):
        print("__del__方法被触发")

1.页面执行完毕回收所有变量

obj = Dog("Lwhite")
obj.eat("bone")
print("=======")

2.所有对象被del的时候

#只有当所有指向该变量都删除的时候,才算删除单位对象
obj2 = obj
print("=========start=============")
del obj
del obj2
print("=============end==============")

3.用类来模拟文件读和写的操作

#例1:例1使用的是文件操作的方法
# fp = open("ceshi222.txt",mode="w",encoding="utf-8")
# fp.write("ewqeqwqewqqeqeq")
# fp.close()
#
# fp = open("ceshi222.txt",mode="r",encoding="utf-8")
# res = fp.read()
# fp.close()
# print(res)
print("=================")
#例2:例2是用类来模拟文件的读的操作

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)

#例3是用来模拟文件读和写的操作

#以下代码的功能是将内容写入到一个文件中在读取这个文件中的内容
#例:

import os
class MyFile():
    #产生文件对象
    def __init__(self,filename):
        self.filename = filename
        self.fp = open(filename,mode="w+",encoding="utf-8")
    #写入文件
    def writefile(self,content):
        self.fp.write(content)
    #读取文件
    def readfile(self):
        #self.fp = open(self.filename, mode="r+", encoding="utf-8")
        self.fp.seek(0)
        res = self.fp.read()
        #print(res)
        return res
    def __del__(self):
        #print(0)
        #自动触发__del__,帮助我们关闭文件
        self.fp.close()
file_name = input("请输入您写入的文件名:")
obj = MyFile(file_name)
content = input("请输入您要输入的内容:")
obj.writefile(content)
res = obj.readfile()
print(res)

#例3的效果是,让你输入内容的文件名,如果这个文件名存在,继续输入内容,如果不存在会自动创建一个并

让其输入内容,输入后返回输出输入的内容结果,也可以在文件中进行查看,内容已经写到文件中.

四.__call__ 魔术方法
触发时机: 把对象当作函数调用的时候自动触发
功能:模拟函数化操作
参数:参数不固定,至少一个self参数
返回值:看需求

1.基本语法

class MyClass():
    def __call__(self):
        print("__call方法被调用了")
        return "done"
obj = MyClass()
res = obj()
print(res)

2.模拟洗衣服的过程

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()
#面向客户的代码形式
# obj.step1()
# # obj.step2()
# # obj.step3()
#call 魔术用法
obj("袜子")

3.模拟内置int方法实现myint

#例:

import math
class MyInt():
    def stoi(self,n,sign=1):
        res = n.lstrip("0")
        if res == "":
            return 0
        num = eval(res) * sign  #eval 将字符串当代码运行
        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
                else:
                    sign = -1
                return self.stoi(n[1:],sign)
            elif n.isdecimal():
                #如果能够走到这个条件,一定没有带任何正负号
                return self.stoi(n)
            else:
                return "对不起,老弟,这个算不了"

else:
            print("对不起,老哥,这个算不了")
myint = MyInt()
res = myint(False)
print(res)
res = myint(5)
print(res)
res = myint(-5.5)
print(res)
res = myint(-000000000)
print(res)
res = myint("00000123456")
print(res)
res = myint("-231312")
print(res)
res = int(5+6)
print(res)
res = myint(0b11)
print(res)

五.__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)

六.__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)

七.__bool__ 魔术方法

触发时机:使用bool (对象)的时候自动触发
功能:强转对象
参数:一个self接受当前对象
返回值:必须是布尔类型
类似的还有如下等等(了解):
    __complex__     complex强转对象时调用
    __int__(self)   int强转对象时调用
    __float__(self) float强转对象时调用
    ...
    ...
#例:
class MyBool():
    def __bool__(self):
        print(222)
        #return True
        return False

obj = MyBool()
res = bool(obj)
print(res)

八.__add__魔术方法 (与之相关的 __radd__ 反向加法)

触发时机: 使用对象进行运算相加的时候自动触发
功能:对象运算
参数:二个对象参数
返回值:运算后的值
类似的还有如下等等(了解):
        __sub__(self,other)     定义减法的行为: -
        __mul__(self,other)     定义乘法的行为:
        __truediv__(self,other) 定义真除法的行为: /
        ...
        ...
#例1:

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(5)
res = a + 56
print(res)
#2.当对象在加号的右侧 自动触发radd方法
b = Myadd(5)
res = 33 + b
print(res)

##代码解析:

有点像:

a + b = ?
res = a+b
print(res)
#代码步骤解析
a在几号的左侧,触发add魔术方法
self.num + other => 3 + b
b在加号的右侧,触发add魔术方法
res = 3 + b
self.num + other * 10 => 5 + 3*10 => 35

九. __len__ 魔术方法

触发时机:使用len(对象)的时候自动触发
功能:用于检测对象中或者类中某个内容的个数
参数:一个self接收当前对象
返回值:必须返回整型
#len(对象)方式,算出该对象所归属的类有多少自定义成员
#例:

class MyLen():
    pty1 = 1
    pty2 = 2
    __pty3 = 3
    def func1(self):
        pass
    def func2(self):
        pass
    def func3(self):
        pass
    def func4(self):
        pass
    def __len__(self):
        #print(MyLen.__dict__)
        dic = MyLen.__dict__
        #print(dic)
        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)
"""

这个是 MyLen.__dict__里面的内容:
{'__module__': '__main__',
 'pty1': 1, 'pty2': 2,
 '_MyLen__pty3': 3,
 'func1': <function MyLen.func1 at 0x00000281A9871950>,
 'func2': <function MyLen.func2 at 0x00000281A98719D8>,
 'func3': <function MyLen.func3 at 0x00000281A9871A60>,
 'func4': <function MyLen.func4 at 0x00000281A9871AE8>,
  '__len__': <function MyLen.__len__ at 0x00000281A9871B70>,
  '__dict__': <attribute '__dict__' of 'MyLen' objects>,
  '__weakref__': <attribute '__weakref__' of 'MyLen' objects>,
  '__doc__': None}
"""

上一篇:python常用魔术方法概览


下一篇:家庭版记账本app之常用控件的使用方法