鱼C论坛

 找回密码
 立即注册
查看: 402|回复: 8

[已解决]装饰器题目的理解

[复制链接]
发表于 2024-1-27 20:47:58 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
def type_check(correct_type):
    def outer(func):
        def inner(arg):
            if(type(arg) == correct_type):
                return func(arg)
            else:
                return "参数类型错误!"
        return inner
    return outer
   
   
print("<<<--- 测试整数 --->>>")
   
@type_check(int)
def double(x):
    return x * 2
   
print(double(2))      # 这里打印结果应该是 4
print(double("2"))    # 这里打印结果应该是 “参数类型错误”
   
print("\n<<<--- 测试字符串 --->>>")
   
@type_check(str)
def upper(s):
    return s.upper()
   
print(upper('I love FishC.'))   # 这里打印结果应该是 I LOVE FISHC
print(upper(250))               # 这里打印结果应该是 “参数类型错误”


这段代码如何直白的理解,看不懂执行的逻辑
最佳答案
2024-1-27 21:56:32
本帖最后由 jackz007 于 2024-1-27 22:34 编辑
  1. def type_check(correct_type) :              # 闭包,完成预设指定类型 (int、str) 的传递
  2.     def outer(func):                        # 闭包,完成被装饰函数(在本例中是 double()、upper())的传递                       
  3.         def inner(arg):                     # 内嵌函数,当以参数 arg 调用 double()、upper() 时,调用被转向到本函数,
  4.                                             # 并会以 arg 为参数调用本函数
  5.             if(type(arg) == correct_type):  # 检查参数 arg 的类型是否符合预设的参数类型(int、str)
  6.                 return func(arg)            # 如果符合,就返回对 double(arg) 或 upper(arg) 的调用结果
  7.             else:                           # 否则
  8.                 return "参数类型错误!"      # 给出参数类型错误,并不执行被装饰函数 double() 或 upper()
  9.         return inner                        # 内层闭包,主要负责传递被装饰函数 double()、upper() 调用句柄以及内嵌函数 inner() 的调用句柄
  10.     return outer                            # 外层闭包,主要负责传递预设参数类型及内嵌闭包 outer() 调用句柄
  11.    
  12. @type_check(int)                            # 声明函数 type_check() 用于装饰函数 double(),以便在代码中调用
  13.                              # 函数 double() 时,由 type_check() 的内嵌函数 inner() 获得控制
  14.                                             # 并由 inner() 完成对原始函数 double() 的调用。type_check(int)
  15.                                             # 中的形式参数 int 是要求的参数类型,就是 double(arg) 中所要求的
  16.                                             # 输入参数 arg 的类型
  17. def double(x):
  18.     return x * 2
  19.    
  20. @type_check(str)                            # 声明函数 type_check() 用于装饰函数 upper(),以便在代码中调用
  21.                              # 函数 upper() 时,由 type_check() 的内嵌函数 inner() 获得控制
  22.                                             # 并由 inner() 完成对原始函数 upper() 的调用。type_check(str)
  23.                                             # 中的形式参数 str 是要求的参数类型,就是 upper(arg) 中所要求的
  24.                                             # 输入参数 arg 的类型   
  25. def upper(s):
  26.     return s . upper()


  27. print("<<<--- 测试整数 --->>>")
  28. print(double(2))
  29. print(double("2"))
  30. print("<<<--- 测试字符串 --->>>")  
  31. print(upper('I love FishC.'))
  32. print(upper(250))
复制代码

        不用装饰器的等效代码是这样的,希望能帮助楼主理解到装饰器的作用机理:
  1. def type_check(correct_type) :
  2.     def outer(func):                    
  3.         def inner(arg):
  4.             if(type(arg) == correct_type):
  5.                 return func(arg)
  6.             else:
  7.                 return "参数类型错误!"
  8.         return inner
  9.     return outer
  10.    
  11. def double(x):
  12.     return x * 2
  13.    
  14. def upper(s):
  15.     return s . upper()

  16. print("<<<--- 测试整数 --->>>")
  17. print(type_check(int)(double)(2))                 # 重点关注这里
  18. print(type_check(int)(double)("2"))               # 重点关注这里
  19. print("<<<--- 测试字符串 --->>>")
  20. print(type_check(str)(upper)('I love FishC.'))    # 重点关注这里
  21. print(type_check(str)(upper)(250))                # 重点关注这里
复制代码

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-1-27 20:51:06 | 显示全部楼层
这段代码是一个装饰器的例子,用于检查函数参数的类型是否符合要求。让我逐步解释一下。

首先,定义了一个装饰器函数`type_check`,它接受一个参数`correct_type`,表示期望的参数类型。这个装饰器函数返回一个内部函数`outer`。

然后,在`type_check`函数内部,定义了另一个装饰器函数`outer`,它接受一个参数`func`,表示要被装饰的函数。这个装饰器函数返回一个内部函数`inner`。

接着,在`outer`函数内部,定义了最终要执行的函数`inner`,它接受一个参数`arg`,表示被装饰函数的参数。

在`inner`函数中,通过`type(arg) == correct_type`判断参数的类型是否与期望的类型`correct_type`相同,如果相同,则调用被装饰的函数`func(arg)`并返回结果。否则,返回字符串"参数类型错误!"。

最后,在`outer`函数内部,返回了函数`inner`。

接下来,使用这个装饰器装饰具体的函数,并测试它们的运行结果。

对于第一个示例,使用`@type_check(int)`装饰函数`double`,表示`double`函数的参数应该为整数类型。当传入整数2时,输出结果为4;当传入字符串"2"时,输出结果为"参数类型错误"。

对于第二个示例,使用`@type_check(str)`装饰函数`upper`,表示`upper`函数的参数应该为字符串类型。当传入字符串"I love FishC."时,输出结果为"I LOVE FISHC";当传入整数250时,输出结果为"参数类型错误"。

这样,使用装饰器就可以在函数调用之前检查参数类型,增加代码的健壮性。希望这个解释能帮助你理解代码的执行逻辑。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-1-27 20:56:01 | 显示全部楼层
FishC 发表于 2024-1-27 20:51
这段代码是一个装饰器的例子,用于检查函数参数的类型是否符合要求。让我逐步解释一下。

首先,定义了一 ...

第一个示例的double(x)到底是传到哪个参数里去了呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-1-27 20:56:50 | 显示全部楼层
yuanbb0820 发表于 2024-01-27 20:56
第一个示例的double(x)到底是传到哪个参数里去了呢?


在第一个示例中,`double(x)`其实是传递给了被装饰的函数`inner`的参数`arg`。让我们逐个解释一下代码的执行过程:

1. 首先,在`@type_check(int)`这行代码下面,定义了被装饰的函数`double(x)`。
2. 然后,使用`@type_check(int)`装饰函数`double`,相当于执行了 `double = type_check(int)(double)` 这行代码。
3. 在 `type_check(int)` 中,返回了一个装饰器函数`outer`,然后 `double` 变量指向了这个装饰器函数。
4. 当调用 `double(2)` 时,实际上是调用了 `outer(2)`,也就是执行了装饰器函数`outer`。
5. 在 `outer` 函数内部,定义了装饰器函数`inner`,然后将这个函数返回。
6. 在 `inner` 函数内部,对参数进行了类型检查,如果参数的类型符合要求(即为整数类型),则调用被装饰的函数`func(arg)`,也就是 `func(2)`。
7. 在这里,`func` 就是被装饰的函数`double`,而`arg` 则是 `inner` 函数接收到的参数,也就是 `2`。
8. 最终,被装饰的函数`double`被执行,并返回结果`4`。

所以,当调用 `double(2)` 时,`x` 就是传递给了被装饰的函数`double`的参数。而装饰器的作用是在函数调用之前进行类型检查,并根据检查结果来决定是否执行被装饰的函数或返回错误提示信息。希望这个解释能帮助你理解代码的执行过程。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-1-27 21:19:17 | 显示全部楼层
可以将这段代码不使用装饰器写出来吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-1-27 21:20:28 | 显示全部楼层
yuanbb0820 发表于 2024-01-27 21:19
可以将这段代码不使用装饰器写出来吗?


当然可以!下面是不使用装饰器的方式来实现同样的功能:

  1. def type_check(correct_type):
  2.     def type_checker(func):
  3.         def inner(arg):
  4.             if type(arg) == correct_type:
  5.                 return func(arg)
  6.             else:
  7.                 return "参数类型错误!"
  8.         return inner
  9.    
  10.     return type_checker

  11. def double(x):
  12.     return x * 2

  13. def upper(s):
  14.     return s.upper()

  15. # 手动进行类型检查
  16. type_check_int = type_check(int)
  17. type_check_str = type_check(str)

  18. double = type_check_int(double)
  19. upper = type_check_str(upper)

  20. print(double(2))      # 这里打印结果应该是 4
  21. print(double("2"))    # 这里打印结果应该是 “参数类型错误”

  22. print(upper('I love FishC.'))   # 这里打印结果应该是 I LOVE FISHC
  23. print(upper(250))               # 这里打印结果应该是 “参数类型错误”
复制代码


在这个版本中,我们手动进行了类型检查。首先,我们创建了两个装饰器实例`type_check_int`和`type_check_str`,分别指定了期望的参数类型为整数和字符串。然后,我们将这两个装饰器应用到相应的函数上,得到了经过类型检查的新函数`double`和`upper`。最后,我们直接调用这两个新函数并打印结果。这样,就实现了与使用装饰器相同的效果。希望这个代码示例对你有帮助!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-1-27 21:56:32 | 显示全部楼层    本楼为最佳答案   
本帖最后由 jackz007 于 2024-1-27 22:34 编辑
  1. def type_check(correct_type) :              # 闭包,完成预设指定类型 (int、str) 的传递
  2.     def outer(func):                        # 闭包,完成被装饰函数(在本例中是 double()、upper())的传递                       
  3.         def inner(arg):                     # 内嵌函数,当以参数 arg 调用 double()、upper() 时,调用被转向到本函数,
  4.                                             # 并会以 arg 为参数调用本函数
  5.             if(type(arg) == correct_type):  # 检查参数 arg 的类型是否符合预设的参数类型(int、str)
  6.                 return func(arg)            # 如果符合,就返回对 double(arg) 或 upper(arg) 的调用结果
  7.             else:                           # 否则
  8.                 return "参数类型错误!"      # 给出参数类型错误,并不执行被装饰函数 double() 或 upper()
  9.         return inner                        # 内层闭包,主要负责传递被装饰函数 double()、upper() 调用句柄以及内嵌函数 inner() 的调用句柄
  10.     return outer                            # 外层闭包,主要负责传递预设参数类型及内嵌闭包 outer() 调用句柄
  11.    
  12. @type_check(int)                            # 声明函数 type_check() 用于装饰函数 double(),以便在代码中调用
  13.                              # 函数 double() 时,由 type_check() 的内嵌函数 inner() 获得控制
  14.                                             # 并由 inner() 完成对原始函数 double() 的调用。type_check(int)
  15.                                             # 中的形式参数 int 是要求的参数类型,就是 double(arg) 中所要求的
  16.                                             # 输入参数 arg 的类型
  17. def double(x):
  18.     return x * 2
  19.    
  20. @type_check(str)                            # 声明函数 type_check() 用于装饰函数 upper(),以便在代码中调用
  21.                              # 函数 upper() 时,由 type_check() 的内嵌函数 inner() 获得控制
  22.                                             # 并由 inner() 完成对原始函数 upper() 的调用。type_check(str)
  23.                                             # 中的形式参数 str 是要求的参数类型,就是 upper(arg) 中所要求的
  24.                                             # 输入参数 arg 的类型   
  25. def upper(s):
  26.     return s . upper()


  27. print("<<<--- 测试整数 --->>>")
  28. print(double(2))
  29. print(double("2"))
  30. print("<<<--- 测试字符串 --->>>")  
  31. print(upper('I love FishC.'))
  32. print(upper(250))
复制代码

        不用装饰器的等效代码是这样的,希望能帮助楼主理解到装饰器的作用机理:
  1. def type_check(correct_type) :
  2.     def outer(func):                    
  3.         def inner(arg):
  4.             if(type(arg) == correct_type):
  5.                 return func(arg)
  6.             else:
  7.                 return "参数类型错误!"
  8.         return inner
  9.     return outer
  10.    
  11. def double(x):
  12.     return x * 2
  13.    
  14. def upper(s):
  15.     return s . upper()

  16. print("<<<--- 测试整数 --->>>")
  17. print(type_check(int)(double)(2))                 # 重点关注这里
  18. print(type_check(int)(double)("2"))               # 重点关注这里
  19. print("<<<--- 测试字符串 --->>>")
  20. print(type_check(str)(upper)('I love FishC.'))    # 重点关注这里
  21. print(type_check(str)(upper)(250))                # 重点关注这里
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-1-28 12:02:47 | 显示全部楼层
本帖最后由 阿奇_o 于 2024-1-28 12:06 编辑

其实理解装饰器的关键,就是 理解“函数对象”、“函数的调用”、函数的输入和输出等核心概念 。。

比如这样   type_check(correct_type)(func)(arg)    懂?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-1-28 14:27:32 | 显示全部楼层
阿奇_o 发表于 2024-1-28 12:02
其实理解装饰器的关键,就是 理解“函数对象”、“函数的调用”、函数的输入和输出等核心概念 。。

比 ...

明白了,谢谢!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-4 15:34

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表