魔术方法和反射

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__': '\n
# 成员属性:salary\n    成员方法:play() learn()  bank()\n
# 功能: 计算工资的分配\n    ',
# '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("这个不存在")

 

posted on 2020-05-29 19:43  fdsimin  阅读(138)  评论(0编辑  收藏  举报