鱼C论坛

 找回密码
 立即注册
查看: 1795|回复: 2

[知识点备忘] 第076讲:类和对象(XIX)

[复制链接]
发表于 2022-10-12 23:32:01 | 显示全部楼层 |阅读模式

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

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

x
0. 本节视频




1. 温馨提示

如果在学习本节课的过程中遇到问题,可以在这个帖子下方提问哦~


小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2022-10-17 09:42:38 | 显示全部楼层
函数和方法如出一辙,实现对象绑定的函数叫方法,没有实现绑定的是普通的函数。本节基于对官方文档的解读,探究了函数、方法、静态方法、类方法的底层实现原理,“知其所以然”。Python底层通过描述符来辨别函数和方法,函数是一个非数据描述符,利用__get__()方法进行鉴别,instance参数为None的是函数,不为None的是方法。静态方法是StaticMethod类的对象,作为函数调用时直接调用传递进来的函数自身,故无需绑定类和对象;类方法是ClassMethod类的对象,将参数klass即owner调整为新函数的第一个参数,以此来绑定类。Python3.9还引入了串联装饰器的功能,仅通过访问属性便可得到与访问方法相同的结果,由新增的hasattr()条件分支来实现。
通过本节课富有深度的学习,我们进一步体会到了描述符的强大功效,如此之多的便捷机制背后都是描述符的功劳!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2023-1-10 14:00:28 | 显示全部楼层
函数、方法、静态方法、类方法的底层实现原理
  1. # 函数和方法
  2. class C:
  3.     def func(self, x):
  4.         return x

  5. c = C()
  6. print(c.func)# <bound method C.func of <__main__.C object at 0x000001C5EE4ECFD0>>
  7. print(C.func)# <function C.func at 0x000001C5EE4D48B0>
  8. # 函数和方法本质上是一个东西,python在底层分辨函数和方法的原理 -> 描述符
  9. # 官方文档:
  10. # class Function:
  11. #     ...
  12. #     def __get__(self, obj, objtype=None):
  13. #         '''Simulate func_descr_get() in Objects/funcobject.c'''
  14. #         if obj is None:
  15. #             return self
  16. #         return MethodType(self, obj)
  17. # 当定义函数时,其实是实例化了一个叫做Function的类(底层为C语言形式实现),包含一个__get__()方法。
  18. # 当数定义一个类,再在类里边定义一个函数的时候,就会用到__get__()方法(obj对应instance,objtype对应owner)
  19. # 先判断第二个参数obj是否为None,是则返回自己,否则返回MethodType
  20. # 官方代码相当于:
  21. class D:
  22.     def __get__(self, instance, owner):
  23.         if instance is None:
  24.             print('函数~')
  25.         else:
  26.             print('方法~')

  27. class C:
  28.     x = D()

  29. c = C()
  30. c.x# 方法~
  31. C.x# 函数~
  32. # MethodType其实也是一个类,其官方文档:
  33. # class MethodType:
  34. #     '''Emulate PyMethod_Type in Objects/classobject.c'''
  35. #     def __init__(self, func, obj):
  36. #         self.__func__ = func
  37. #         self.__self__ = obj
  38. #     def __call__(self, *args, **kwargs):
  39. #         func = self.__func__
  40. #         obj = self.__self__
  41. #         return func(obj, *args, **kwargs)
  42. # 当它的实例化对象被当做函数调用的时候,__call__()魔法方法就会被执行,将传递进去的func和obj两个参数进行整合并且返回,即将传递进来的第一个实参func作为函数名,第二个实参作obj为该函数的第一个参数,整合之后返回
  43. # 那么上边return MethodType其实就相当于return self(obj)。

  44. # 静态方法,官方文档:
  45. # class StaticMethod:
  46. #     '''Emulate PyStaticMethod_Type() in Objects/funcobject.c'''
  47. #     def __init__(self, f):
  48. #         self.f = f
  49. #     def __get__(self, obj, objtype=None):
  50. #         return self.f
  51. #     def __call__(self, *args, **kwargs):
  52. #         return self.f(*args, **kwargs)
  53. # 只要被StaticMethod装饰器碰过的对象就会变成StaticMethod类的对象,当这个对象被作为函数调用的时候,会直接调用传递进来的函数自身,省去类和对象的中间环节

  54. # 类方法,官方文档:
  55. # class ClassMethod:
  56. #     '''Emulate PyClassMethod_Type() in Objects/funcobject.c'''
  57. #     def __init__(self, f):
  58. #         self.f = f
  59. #     def __get__(self, obj, cls=None):
  60. #         if cls is None:
  61. #             cls = type(obj)
  62. #         if hasattr(type(self.f), '__get__'):
  63. #             return self.f.__get__(cls, cls)
  64. #         return MethodType(self.f, cls)
  65. # type()如果传入一个对象,那么他会返回该对象所属的类
  66. class C:
  67.     pass

  68. c = C()
  69. print(type(c))# <class '__main__.C'>
  70. print(type(c) is C)# True
  71. # 代码hasattr(type(self.f), '__get__')为的是让类方法能够和其他装饰器串联起来使用,如;
  72. class C:
  73.     @classmethod
  74.     def __doc__(cls):
  75.         return f'i love you -- from class {cls.__name__}'

  76. c = C()
  77. print(c.__doc__())# i love you -- from class C
  78. print(C.__doc__())# i love you -- from class C
  79. # 调用方法的形式

  80. class G:
  81.     @classmethod
  82.     @property
  83.     def __doc__(cls):
  84.         return f'A doc for {cls.__name__!r}'

  85. g = G()
  86. print(g.__doc__)# A doc for 'G'
  87. print(G.__doc__)# A doc for 'G'
  88. # 属性访问的形式

  89. #将官方文档复制下来,并添加一些print语句
  90. class MethodType:
  91.     def __init__(self, func, obj):
  92.         self.__func__ = func
  93.         self.__self__ = obj
  94.     def __call__(self, *args, **kwargs):
  95.         func = self.__func__
  96.         obj = self.__self__
  97.         print('小白')
  98.         return func(obj, *args, **kwargs)

  99. class ClassMethod:
  100.     def __init__(self, f):
  101.         self.f = f
  102.     def __get__(self, obj, cls=None):
  103.         if cls is None:
  104.             print('旺财')
  105.             cls = type(obj)
  106.         if hasattr(type(self.f), '__get__'):
  107.             print(f'来福,type(self.f) -> {type(self.f)}')
  108.             return self.f.__get__(cls, cls)
  109.         return MethodType(self.f, cls)

  110. class D:
  111.     @ClassMethod# 注意不是classmethod
  112.     @property
  113.     def __doc__(cls):
  114.         return  f'i love you. -- from class {cls.__name__}'

  115. d = D()
  116. d.__doc__# 来福,type(self.f) -> <class 'property'>
  117. # 如果多个装饰器串联,那么传入这个参数的类type(self.f)就是property,相当于
  118. # __doc__是property的实例对象__doc__ = property(__doc__),然后到@ClassMethod,运行到hasattr分支,type(self.f)运行的结果是property类,包含'__get__'方法,然后if里对__get__进行改造
  119. # self.f.__get__(cls, cls)调用的是propert类里的__get__方法,并将instance对象参数的位置替换成了cls类参数

  120. class D:
  121.     @ClassMethod# 注意不是classmethod
  122.     def __doc__(cls):
  123.         return  f'i love you. -- from class {cls.__name__}'

  124. d = D()
  125. d.__doc__# 来福,type(self.f) -> <class 'function'>
  126. # python万物皆对象,函数也是对象,这里type(self.f)指的是<class 'function'>类
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 3 反对 0

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-5-5 14:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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