Python 进阶 魔术方法 __call__

本贴最后更新于 387 天前,其中的信息可能已经水流花落

实践是检验真理的唯一标准:拷贝到pycharm一试便知。

.

一、__call__使用

1、callable(对象) 判断对象是否可调用:==> 调用 函数() 对象()
callable() 进入函数内部查看,本质是判断类是否拥有__call__方法。

2、实现类创建出来的实例对象可调用 def __call __(self, *args, **kwargs):
实例对象+() 会自动调用__call__方法

没用__call__


# 方法
def work():
    pass


# 类
class TestClass:
    pass


# callable(对象) 判断对象是否可调用:==> 调用  函数()  对象()
print('函数是可调用对象么?', callable(work))
print('类是可调用对象么?', callable(TestClass))
# 函数是可调用对象么? True
# 类是可调用对象么? True

# 创建实例对象
noCallObj = TestClass()
print('类创建的实例对象是可调用对象么?', callable(noCallObj))
# 类创建的实例对象是可调用对象么? False

# 类的实例对象加括号是调用,但调用会报错:
noCallObj()
# 报错 TypeError: 'TestClass' object is not callable

用了__call__


# 需求:实现类创建出来的实例对象可调用???
# 给类实现一个__call__方法
class Demo:
    def __call__(self, *args, **kwargs):
        print('Demo类__call__:实现对象可调用')
        """
        :param args:
        :param kwargs:
        :return:
        """
        print("----call---方法执行了")


# 需求:实现类创建出来的实例对象可调用???
obj = Demo()
print('添加了__call__方法的类,它的实例对象是可调用对象么?', callable(obj))
# 添加了__call__方法的类,它的实例对象是可调用对象么? True

# 类的实例对象加括号是调用,类添加了__call__方法,实例对象调用成功:
obj()  # ===> obj.__call__
# Demo类__call__:实现对象可调用
# ----call---方法执行了

# 再掉一遍
obj()
# Demo类__call__:实现对象可调用
# ----call---方法执行了

.

二、通过__call__实现需求

通过__call__实现用类做装饰器

需求:通过类实现一个计时装饰器

1、装饰器不带参数 @CountTime


# -----------------1、装饰器不带参数 @CountTime-------------------------------
import time


# 1、装饰器不带参数 CountTime
class CountTime:

    def __init__(self, func):
        # func:是被装饰的函数,传入进来之后保存为func属性
        self.func = func

    def __call__(self, *args, **kwargs):
        st = time.time()
        # 调用原功能函数
        res = self.func(*args, **kwargs)
        et = time.time()
        print("函数执行的耗时为:", et - st)
        return res


@CountTime  # ==> work = CountTime(work) # 实例化对象
def work(a, b):
    print('这里是函数work')
    time.sleep(2)
    res_work = a + b
    return res_work


work(1, 2)
# 这里是函数work
# 函数执行的耗时为: 2.0064079761505127

print('work(1, 2)执行结果:', work(1, 2))
# 这里是函数work
# 函数执行的耗时为: 2.000722646713257
# work(1, 2)执行结果: 3

2、装饰器带参数 @CountTime(666)


# -----------------2、装饰器带参数 @CountTime(666)-------------------------------
import time


class CountTime:

    def __init__(self, n):
        self.n = n

    def __call__(self, func):
        self.func = func
        return self.run

    def run(self, *args, **kwargs):
        print("装饰器的功能代码:函数执行前内容")
        st = time.time()
        # 调用原功能函数
        res = self.func(*args, **kwargs)
        print("装饰器的功能代码:函数执行后内容")
        et = time.time()
        print("函数执行的耗时为:", et - st)
        return res


@CountTime(666)  # ==> work = CountTime(3)(work) # 实例化对象
def work():
    time.sleep(2)
    print('---work---')
    return '这是函数work的返回值'


work()
# 装饰器的功能代码:函数执行前内容
# ---work---
# 装饰器的功能代码:函数执行后内容
# 函数执行的耗时为: 2.004631996154785

print(work())
# 装饰器的功能代码:函数执行前内容
# ---work---
# 装饰器的功能代码:函数执行后内容
# 函数执行的耗时为: 2.0007331371307373
# 这是函数work的返回值

3、装饰器带参数 @CountTime(888) 闭包函数实现


# -----------------3、装饰器带参数 @CountTime(888) 闭包函数实现-------------------------------
import time


class CountTime:
    def __init__(self, n):
        self.n = n

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print("装饰器的功能代码:函数执行前内容")
            st_time = time.time()
            res = func(*args, **kwargs)
            print("装饰器的功能代码:函数执行后内容")
            ed_time = time.time()
            print('函数执行耗时为:', ed_time - st_time)
            print('装饰器传入的参数为:', self.n)
            return res

        return wrapper


@CountTime(888)  # ==> work = CountTime(3)(work) # 实例化对象
def work():
    time.sleep(2)
    print('---work---')


work()
# 装饰器的功能代码:函数执行前内容
# ---work---
# 装饰器的功能代码:函数执行后内容
# 函数执行耗时为: 2.0053937435150146
# 装饰器传入的参数为: 888

print(work())
# 装饰器的功能代码:函数执行前内容
# ---work---
# 装饰器的功能代码:函数执行后内容
# 函数执行耗时为: 2.000443458557129
# 装饰器传入的参数为: 888
# None

6 操作
qq5942527 在 2023-04-07 00:29:16 更新了该帖
qq5942527 在 2023-04-06 18:08:10 更新了该帖
qq5942527 在 2023-04-06 18:07:34 更新了该帖
qq5942527 在 2023-04-06 18:06:32 更新了该帖 qq5942527 在 2023-04-06 18:01:34 更新了该帖 qq5942527 在 2023-04-06 17:50:36 更新了该帖
回帖
请输入回帖内容 ...