• 魔术方法和反射


    1. __init__构造方法:  在实例化对象,初始化的时候触发,功能是可以为对象添加成员,参数至少有一个self,无返回值

    class Travel():
        def __init__(self,didian):
            self.didian = didian
    # 实例化
    obj = Travel("海南")
    print(obj.didian) # 海南
    
    # 可以通过一个类实例化不同的对象
    class Travel():
        def __init__(self,didian,time):
            self.didian = didian
            self.time = time
    
        def shan(self):
            print("山:{}去{}玩".format(self.time,self.didian))
    
        def shui(self):
            print("水:{}去{}玩".format(self.time, self.didian))
    
        def hai(self):
            print("海:{}去{}玩".format(self.time,self.didian))
    
    # 第一个对象:
    wudangshan = Travel("湖北","5月")
    wudangshan.shan() # 山:5月去湖北玩
    
    # 第二个对象:
    xihu = Travel("杭州","6月")
    xihu.shui() # 水:6月去杭州玩
    
    # 第三个对象
    dadonghai = Travel("三亚","7月")
    dadonghai.hai() # 海:7月去三亚玩

    2. __new__魔术方法:  触发时机: 实例化生成对象的时候触发,时间比__init__早

               功能: 控制对象的创建过程

               参数: 至少一个cls接收当前的类,其实的参数根据情况而定

               返回值: 通常返回对象或者None

    2. 1  __new__ 返回值的三种情况:

    class Tree(object):
        def __new__(cls):
            obj = object.__new__(cls)
            return obj
            # (1) 借助父类.方法(),返回本类自己的对象
    obj_tree = Tree()
    print(obj_tree) # <__main__.Tree object at 0x000002C288074208>
    
    class Tree(object):
        def __new__(cls):
            obj = object.__new__(cls)
            return None
            # (2) 不返回任何对象
    obj_tree = Tree()
    print(obj_tree) # None
    
    class Grass():
        name = "我是小草"
    obj_grass = Grass()
    
    class Tree(object):
        def __new__(cls):
            obj = object.__new__(cls)
            return obj_grass
            # (3) 返回别的类的对象
    obj_tree = Tree()
    print(obj_tree.name) # 我是小草

    2.2 __new__的使用方式:

    class Tree():
        def __new__(cls):
            print("第一个")
    
        def __init__(self):
            print("第二个")
    
    obj = Tree() # 第一个  证明__new__触发时间早于__init__,先创建对象,再初始化对象
    
    # new方法的参数要和init方法的参数保持一致,否则程序报错
    class Tree():
        def __new__(cls,name):
            print("第一个")
            return object.__new__(cls)
    
        def __init__(self,name):
            self.name = name
    
    obj1 = Tree("bob")
    print(obj1.name)
    
    # 优化:利用收集参数,无需再考虑new方法的参数是否保持了一致,也为后续类再添加参数提供了方便
    class Tree():
        def __new__(cls, *args, **kwargs):
            print("第一个")
            return object.__new__(cls)
    
        def __init__(self,name,age):
            self.name = name
            self.age = age
    obj666 = Tree("bob",18)
    print(obj666.name,obj666.age)
    
    # 注意点: 如果new方法返回的不是自身的对象,那么init方法不会被触发,init里面的代码也不会被执行
    class Tree():
        def __new__(cls, *args, **kwargs):
            print("第一个")
            return obj666
    
        def __init__(self,name):
            self.name = name
            print("第二个")
    obj_this = Tree("bob")
    print(obj_this.name)
    # 第一个
    # bob

    3.  __del__魔术方法: 也叫析构方法

            触发时机:当对象被内存回收的时候自动触发(1,页面执行完毕,回收所有变量 2,所有对象被del的时候)
            功能: 对象使用完毕后资源回收
            参数: 一个self接收对象
            返回值: 无
    3.1  触发情况:

    class Tree():
        def __init__(self,name):
            self.name = name
    
        def __del__(self):
            print("资源被回收")
    
    # 情况一: 页面执行完毕,系统自动调用__del__方法
    obj = Tree("大树")
    print(obj.name)
    # 大树
    # 资源被回收
    
    # 情况二: 所有对象被删除,如果有两个或以上的变量指向这个类的对象,必须是将这些变量都删除的情况下才会自动触发__del__方法
    print("开始")
    obj1 = Tree("大树")
    obj2 = obj1
    del obj1
    print("结束")
    # 开始
    # 结束
    # 资源被回收
    
    print("开始")
    obj1 = Tree("大树")
    obj2 = obj1
    del obj1
    del obj2
    print("结束")
    # 开始
    # 资源被回收
    # 结束

    3.2  用面向对象模拟文件操作小案例

    import os
    class ReadFile():
        # 判断文件是否存在
        def __new__(cls,filepath):
            if os.path.exists(filepath):
                return object.__new__(cls)
            else:
                print("此文件不存在")
    
         # 打开文件
        def __init__(self,filepath):
            self.f1 = open(filepath,mode="r+",encoding="utf-8")
    
        # 读取文件
        def readcontent(self):
            content = self.f1.read()
            return content
    
        # 关闭文件
        def __del__(self):
            self.f1.close()
    
    obj = ReadFile(r"D:python学习python代码练习每天代码练习111.txt")
    res = obj.readcontent()
    print(res)

    4.  __str__魔术方法:

            触发时机: 使用print(对象)或者str(对象)的时候
            功能: 查看对象
            参数: 一个self接收对象
            返回值: 必须返回字符串类型

    class Product():
        def __init__(self,name,time):
            self.name = name
            self.time = time
    
        def info(self):
            return "{}经过{}天,可以制成成品".format(self.name,self.time)
    
        def __str__(self):
            return self.info()
    obj = Product("橡胶",10)
    print(obj) # 橡胶经过10天,可以制成成品
    print(str(obj)) # 橡胶经过10天,可以制成成品

    5.  __repr__方法:

            触发时间: 使用repr(对象)的时候
            功能: 查看对象,与__str__方法类似
            参数: 一个self接收当前对象
            返回值:必须返回字符串类型
            在系统底层,如果定义了repr,自动默认将repr赋值给str,即__repr__ = __str__

    class Tree():
        def __init__(self,name,color):
            self.name = name
            self.color = color
    
        def __repr__(self):
            return "{}是{}的".format(self.name,self.color)
    obj = Tree("大树","绿色")
    print(repr(obj)) # 大树是绿色的
    print(obj) # 大树是绿色的
    print(str(obj)) # 大树是绿色的
    # repr可以赋值给str,但是str并不能赋值给repr

    6.  __call__方法:

            触发时机:把对象当做函数调用的时候触发
            功能: 模拟函数化操作
            参数: 至少一个self参数
            返回值: 根据需求而定

    class Cai():
        def __call__(self, *args, **kwargs):
            self.one()
            self.two()
            self.three()
            self.four()
    
        def one(self):
            print("先放一点油")
    
        def two(self):
            print("把菜倒进锅里")
    
        def three(self):
            print("放一点盐")
    
        def four(self):
            print("盛出来,装盘")
    obj = Cai()
    obj()
    """
    先放一点油
    把菜倒进锅里
    放一点盐
    盛出来,装盘
    """

    6.2  用__call__方法模拟int函数

    import math
    class Myint():
        def calc(self,num,sign=1):
            strvar = num.lstrip("0")
            if strvar == "":
                return 0
            return eval(strvar)*sign
    
        def __call__(self,num):
            # 如果是整型
            if isinstance(num,int):
                return num
            # 如果是bool值
            elif isinstance(num,bool):
                if num == True:
                    return 1
                else:
                    return 0
            # 如果是浮点型
            elif isinstance(num,float):
                if num >= 0:
                    return math.floor(num)
                else:
                    return math.ceil(num)
                # 也可以这样写: return math.floor(num) if num >= 0 else math.ceil(num)
            # 如果是字符串
            elif isinstance(num,str):
                if (num.startswith("+") or num.startswith("-")) and num[1:].isdecimal():
                    if num[0] == "+":
                        sign = 1
                    else:
                        sign = -1
                    return self.calc(num[1:],sign)
                elif num.isdecimal():
                    return self.calc(num)
                else:
                    return "这个字符串不能转为整型"
    obj = Myint()
    a = +---19
    res1 = obj(a)
    res2 = int(a)
    print(res1,  res2)

    7.  __bool__,  __complex__,  __float__,  __int__

            触发时机:使用bool(对象)的时候自动触发
            功能:强转对象
            参数: 一个self接收当前对象
            返回值: 必须是bool类型
            __complex__(self) __float__(self) __int__(self)使用方法与功能跟__bool__(self)一样
    class Tree():
        def __bool__(self):
            return True
    obj = Tree()
    print(bool(obj)) # True

    8.  __add__方法:

            触发时机: 使用对象进行运算相加的时候自动触发
            功能: 对象运算
            参数: 两个对象参数
            返回值: 运算后的值
            反向加法是__radd__
            __sub__是定义减法运算的,用法与__add__一样
            __mul__是定义乘法运算的,用法与__add__一样
            __truediv__是定义真除法运算的,用法与__add__一样...

    class YunSuan():
        def __init__(self,num):
            self.num = num
    
        def __add__(self, other):
            return self.num + other
    
        def __radd__(self, other):
            return self.num + other*2
    
    a = YunSuan(7)
    print(a+5) # 12
    
    b = YunSuan(3)
    print(5+b) # 13
    
    print(a+b) # 17
    """
    第一步: a+b 先触发add方法  num = 7 other= b
    第二步: 7+b 触发radd方法  num=3 other=7
    """

    9.  __len__方法:

            触发时机: 使用len(对象)的时候自动触发
            功能: 用于计算类中或者对象中的成员个数
            参数: 一个self接收对象
            返回值: 必须返回整型
            类似的还有如下等等(了解):
            __iter__(self) 定义迭代容器中的元素的行为
            __reversed__(self) 定义当被 reversed() 调用时的行为
            __contains__(self, item) 定义当使用成员测试运算符(in 或 not in)时的行为
    class Tree():
        a = 1
        b =2
        def jisuan(self):
            print("计算这个类中自定义成员的个数")
    
        def __len__(self):
            lst = [i for i in Tree.__dict__ if not (i.startswith("__") and i.endswith("__"))]
            return len(lst)
    
    obj = Tree()
    print(len(obj)) # 3

    10. 与类相关的魔术属性

    __dict__ ,   __doc__,    __name__ ,   __class__,    __bases__
    class Job():
        def __init__(self,salary):
            self.salary = salary
    
    class Money(Job):
        """
        成员属性:salary
        成员方法:play() learn()  bank()
        功能: 计算工资的分配
        """
        def play(self):
            print("工资{}的三分之一用于玩:{}".format(self.salary,self.salary*0.3))
    
        def learn(self):
            print("工资{}的三分之一用于学习:{}".format(self.salary,self.salary*0.3))
    
        def bank(self):
            print("工资{}的三分之一用于存储:{}".format(self.salary, self.salary * 0.3))
    
    obj1 = Money(20000)
    
    # (1)  __dict__ : 获取类或者兑现中的内部成员结构
    print(Money.__dict__)
    # {'__module__': '__main__', '__doc__': '
    
    # 成员属性:salary
        成员方法:play() learn()  bank()
    
    # 功能: 计算工资的分配
        ',
    # 'play': <function Money.play at 0x0000024E7EABC510>,
    # 'learn': <function Money.learn at 0x0000024E7EABC598>,
    # 'bank': <function Money.bank at 0x0000024E7EABC620>}
    print(obj1.__dict__) # {'salary': 20000}
    
    # (2) __doc__ 获取类或者对象内部的文档
    print(Money.__doc__)
    print(obj1.__doc__)
    """
        成员属性:salary
        成员方法:play() learn()  bank()
        功能: 计算工资的分配
    """
    
    # (3) __name__ 获取类名函数名
    print(Money.__name__) # Money
    
    # (4) __class__ 获取当前对象所属的类
    print(obj1.__class__) # <class '__main__.Money'>
    
    # (5) __bases__ 获取一个类直接继承的所有父类,返回元祖
    print(Money.__bases__) # (<class '__main__.Job'>,)

     11.  反射:针对于类对象或者模块,用字符串去操作类对象或者模块中的成员

    11.1  类或者成员中的反射应用:

    class Tree():
        name = "大树"
        __age = 18
        def grow(self):
            print("小树长成大树")
    
        def forest(self):
            print("树聚集成森林")
    obj = Tree()
    
    # (1) hasattr(): 检查类或者对象是否具有指定的成员
    res = hasattr(Tree,"name")
    print(res) # True
    res = hasattr(obj,"name")
    print(res) # True
    res = hasattr(obj,"__age")
    print(res) # False  私有成员时检测不到的
    
    res = hasattr(Tree,"grow")
    print(res) # True
    res = hasattr(obj,"grow11")
    print(res) # False
    
    # (2) getattr(): 获取类或者对象中的值
    func1 = getattr(Tree,"grow")
    func1("self")  # 小树长成大树  通过类获取的是普通方法,所以调用的时候需任意给一个参数
    res = getattr(Tree,"name")
    print(res) # 大树
    
    # 当获取的成员不存在时,可以设置默认值
    func1 = getattr(obj,"grow11","这个成员不存在")
    print(func1) # 这个成员不存在
    
    # 小案例
    strvar = input("请输入您要使用的方法:")
    if hasattr(obj,strvar):
        func = getattr(obj,strvar)
        func()
    
    # (3) setattr(): 设置对象或成员的值
    setattr(obj,"name","巨树人")
    print(obj.name) # 巨树人
    
    setattr(Tree,"green",lambda : print("成片的绿叶子"))
    Tree.green() # 成片的绿叶子
    
    # (4) delattr(): 删除类或者成员中的值
    delattr(obj,"name")
    delattr(Tree,"name")
    print(obj.name) # 报错
    
    delattr(Tree,"grow")
    obj.grow() # 报错

    11.2 模块中反射的应用:

    import sys
    selfmodules = sys.modules["__main__"] # 获取系统中本模块所包含的对象
    
    def one():
        print("第一个")
    def two():
        print("第二个")
    def three():
        print("第三个")
    
    while True:
        strvar = input("请输入您要反射的模块名称:")
        if hasattr(selfmodules,strvar):
            func = getattr(selfmodules,strvar)
            func()
        elif strvar.upper() == "Q":
            break
        else:
            print("这个不存在")
  • 相关阅读:
    MySQL中查询表及索引大小的方法
    转:一套大而全的系统架构体系与具体落地方案
    [转]1年时间业务量疯长40倍,谈人人车的平台架构演进之路
    [转]如何实现“持续集成”?闲鱼把研发效率翻了个翻
    微服务介绍
    Python2.X和Python3.X的w7同时安装使用
    黑客与画家阅读体会
    Open Source 开发工具集
    volatile和不加volatile的区别
    VMware改变硬盘空间大小的方法
  • 原文地址:https://www.cnblogs.com/fdsimin/p/12989310.html
Copyright © 2020-2023  润新知