项目地址:https://git.io/pytips

本篇主要关于三个常用内置方法:property()staticmethod()classmethod()

在 Python 语言的设计中,通常的语法操作最终都会转化为方法调用,例如:

a = 1
b = 2
print("a + b = {}".format(a+b))# 相当于
print("a.__add__(b) = {}".format(a.__add__(b)))
a + b = 3
a.__add__(b) = 3

Python 中的描述符(Descriptor)就是将对象属性的获取、赋值以及删除等行为转换为方法调用的协议:

descr.__get__(self, obj, type=None) --> valuedescr.__set__(self, obj, value) --> Nonedescr.__delete__(self, obj) --> None

例如我们要获取一个对象的属性,可以通过o.x的方式取得:

class Int:ctype = "Class::Int"def __init__(self, val):self._val = vala = Int(1)
print(a.ctype)
Class::Int

而通过.的方式寻找属性的值实际上调用了object.__getattribute__(self, name)方法:

class Int:ctype = "Class::Int"def __init__(self, val):self._val = valdef __getattribute__(self, name):print("? doesn't want to give `{}' to you!".format(name))return "?"
a = Int(2)
print(a.ctype)
? doesn't want to give `ctype' to you!
?

而这里的__getattribute__(self, name)方法实际上就是将.的属性获取方法转化为描述符协议定义的descr.__get__(self, key)

class Str:def __init__(self, val):self._val = valdef __get__(self, name, ctype=None):print("You can __get__ anything from here!")return self._val
class Int:ctype = Str("Class::Int")def __init__(self, val):self._val = valdef __getattribute__(self, name):return type(self).__dict__[name].__get__(None, type(self))
a = Int(2)
print(a.ctype)
You can __get__ anything from here!
Class::Int

这里的 a.ctype = (Int.__dict__['ctype']).__get__(None, Int),即通过描述符的方式获取了 ctype 属性的值。同样的道理,你也可以通过 descr.__set__(self, obj, val) 设置属性的值:

class Str:def __init__(self, val):self._val = valdef __get__(self, name, ctype=None):print("You can __get__ anything from here!")return self._valdef __set__(self, name, val):print("You can __set__ anything to me!")self._val = val
class Int:ctype = Str("Class::Int")def __init__(self, val):self._val = val
a = Int(3)
print(a.ctype)
a.ctype = "Class::Float"
print(a.ctype)
You can __get__ anything from here!
Class::Int
You can __set__ anything to me!
You can __get__ anything from here!
Class::Float

将这些取值、赋值的操作转换为方法调用让我们有办法在做这些操作的过程中插入一些小动作,这么好用的东西自然是已加入豪华内置函数阵容,正是我们常见的

  • property()

  • classmethod()

  • staticmethod()

property

property(fget=None, fset=None, fdel=None, doc=None) 方法简化了上面的操作:

class Int:def __init__(self, val):self._val = valself._ctype = Nonedef get_ctype(self):print("INFO: You can get `ctype`")return self._ctypedef set_ctype(self, val):print("INFO: You're setting `ctype` =", val)self._ctype=valctype = property(fget=get_ctype, fset=set_ctype, doc="Property `ctype`")a = Int(4)
print(a.ctype)
a.ctype = "Class::Int"
print(a.ctype)
INFO: You can get `ctype`
None
INFO: You're setting `ctype` = Class::Int
INFO: You can get `ctype`
Class::Int

显然,更方便一些的用法是将 property 当做修饰器:

class Int:_ctype = Nonedef __init__(self, val):self._val = val@propertydef ctype(self):print("INFO: You can get `ctype` from me!")return self._ctype@ctype.setterdef ctype(self, val):print("INFO: You're setting `ctype` =", val)self._ctype = val
a = Int(5)
print(a.ctype)
a.ctype = "Class::Int"
print(a.ctype)
INFO: You can get `ctype` from me!
None
INFO: You're setting `ctype` = Class::Int
INFO: You can get `ctype` from me!
Class::Int

staticmethod & classmethod

顾名思义,property 是关于属性的全部操作,如果是要获取类中的方法,则需要用到 staticmethodclassmethod。顾名思义,staticmethod 将方法变成静态方法,即类和实例都可以访问,如果不用 staticmethod 我们可以用下面这种别扭的方法实现:

class Int:def __init__(self, val):self._val = valdef _get_ctype(self=None):print("INFO: You can get `ctype` from here!")return "Class::Int"@staticmethoddef get_ctype():print("INFO: You can get `ctype` from here!")return "Class::StaticInt"       a = Int(6)
print(a._get_ctype())
print(Int._get_ctype())print(a.get_ctype())
print(Int.get_ctype())
INFO: You can get `ctype` from here!
Class::Int
INFO: You can get `ctype` from here!
Class::Int
INFO: You can get `ctype` from here!
Class::StaticInt
INFO: You can get `ctype` from here!
Class::StaticInt

可以看到,静态方法与类和实例无关,也就不再(不能)需要 self 关键词;与之相反,当我们需要在方法中保留类(而非实例)的引用时,则需要用 classmethod

class Int:_ctype = ""def __init__(self, val):self._val = val@classmethoddef set_ctype(klass, t):klass._ctype = treturn "{}.ctype = {}".format(klass.__name__, t)
a = Int(7)
print(a.set_ctype("Class::Int"))
print(Int.set_ctype("Class::Float"))
b = Int(8)
print(b._ctype)
Int.ctype = Class::Int
Int.ctype = Class::Float
Class::Float

总结

Python 的描述符给出一种通过方法调用来实现属性(方法)获取、赋值等操作的规则,通过这一规则可以方便我们深入程序内部并实施操控,因此 property/staticmethod/classmethod 在 Python 是通过底层(如 CPython 中的 C)实现的,如果想要进一步深入了解其实现原理,可以访问参考链接的教程,其中包括了这三个内置方法的 Python 实现版本,我也把它们 copy 过来方便查看。


欢迎关注公众号 PyHub 每日推送

参考

  1. Descriptor HowTo Guide

class Property(object):"Emulate PyProperty_Type() in Objects/descrobject.c"def __init__(self, fget=None, fset=None, fdel=None, doc=None):self.fget = fgetself.fset = fsetself.fdel = fdelif doc is None and fget is not None:doc = fget.__doc__self.__doc__ = docdef __get__(self, obj, objtype=None):if obj is None:return selfif self.fget is None:raise AttributeError("unreadable attribute")return self.fget(obj)def __set__(self, obj, value):if self.fset is None:raise AttributeError("can't set attribute")self.fset(obj, value)def __delete__(self, obj):if self.fdel is None:raise AttributeError("can't delete attribute")self.fdel(obj)def getter(self, fget):return type(self)(fget, self.fset, self.fdel, self.__doc__)def setter(self, fset):return type(self)(self.fget, fset, self.fdel, self.__doc__)def deleter(self, fdel):return type(self)(self.fget, self.fset, fdel, self.__doc__)class StaticMethod(object):"Emulate PyStaticMethod_Type() in Objects/funcobject.c"def __init__(self, f):self.f = fdef __get__(self, obj, objtype=None):return self.fclass ClassMethod(object):"Emulate PyClassMethod_Type() in Objects/funcobject.c"def __init__(self, f):self.f = fdef __get__(self, obj, klass=None):if klass is None:klass = type(obj)def newfunc(*args):return self.f(klass, *args)return newfunc

PyTips 0x14 - Python 描述符相关推荐

  1. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过 ...

  2. python有哪些作用-python描述符有什么作用

    python描述符的作用:代理一个类的属性,让程序员在引用一个对象属性时自定义要完成的工作:它是实现大部分Python类特性中最底层的数据结构的实现手段,是使用到装饰器或者元类的大型框架中的一个非常重 ...

  3. Python描述符是什么?

    在Python中,通过使用描述符,程序员可以在引用对象属性时定制要完成的工作,接下来我们一起来聊聊Python描述符相关的知识. 本质上,描述符是一个类,但它定义了另一个类中属性的访问模式.换句话说, ...

  4. python描述符详解_Python描述符 (descriptor) 详解

    1.什么是描述符? python描述符是一个"绑定行为"的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__de ...

  5. python 描述符类_python的黑魔法--描述符

    python的黑魔法 描述符 官方定义:python描述符是一个"绑定行为"的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 get(), set(), 和de ...

  6. python 描述符有什么用_介绍python描述符的意义

    你也许经常会听到「描述符」这个概念,但是由于大多数的程序员很少会使用到他,所以可能你并不太清楚了解它的原理,python视频教程栏目将详细介绍 推荐(免费):python视频教程 但是如果你想自己的事 ...

  7. 技术图文:Python描述符 (descriptor) 详解

    背景 今天在B站上学习"零基础入门学习Python"这门课程的第46讲"魔法方法:描述符",这也是我们组织的 Python基础刻意练习活动 的学习任务,其中有这 ...

  8. python 描述符参考文档_python 描述符详解

    Python中包含了许多内建的语言特性,它们使得代码简洁且易于理解.这些特性包括列表/集合/字典推导式,属性(property).以及装饰器(decorator).对于大部分特性来说,这些" ...

  9. python描述符与实例属性_Python 中的属性访问与描述符

    在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个name属性,那便可以使用foo.name对此属性进行访问.一般而言,点(. ...

  10. python描述符详解

    什么是描述符 数据描述符data descriptor和非数据描述符non-data descriptors 如何检测一个对象是不是描述符 描述符有什么用和好处 例子 总结 本文主要介绍描述符的定义, ...

最新文章

  1. 面向完全初学者的Unity和C#游戏开发学习教程
  2. django html菜单,django实现动态菜单的方式
  3. 7 成中国职场人厌班,我们为什么会陷入职业倦怠?
  4. CSS 实现左侧固定,右侧自适应两栏布局的方法
  5. Oracle_杂货箱_不定期更新
  6. U3D-LookAt插值动画
  7. cauchy problem of 1st order PDE from Partial Differential Equations
  8. 错误记录集锦(遇到则记下)
  9. Oracle数据库配置方案,oracle数据库各项参数参考配置方案
  10. (二)使用预定义模型 QStringListModel例子
  11. oracle 10g 创建只读用户语法
  12. java 传绝对路径无效_又传噩耗!知名主持人小济南因突发肺栓塞不幸去世,享年36岁...
  13. tomcat的服务器目录在哪个文件夹,Tomcat目录结构详细介绍
  14. windows开启远程Wmi服务支持
  15. shiro原理_java:shiro高级篇——4
  16. 爬取当当网评论(1)
  17. 怎么单凭手机进行低成本制作网页?今日让我分享一下经验
  18. 【Python 项目】02 微信定时发送消息
  19. 适合新手玩的游戏APP
  20. 【转】appStore上传苹果应用程序软件发布流程

热门文章

  1. 【VS2010学习笔记】【函数学习】一(VC6.0和VS2010主函数的不同)
  2. 【VC++类型转换】string转换为CString
  3. 激光雷达点云数据处理一(Terrasolid软件安装)
  4. curl header设置参数
  5. 算法笔记-------基数排序
  6. java并发编程实战读书笔记之FutureTask
  7. Android 自定义View关于measure流程的基本思路整理
  8. Hudi on Flink 快速上手指南
  9. MMP,我兄弟转正前一天,一个垃圾公司把他辞退了!
  10. 宝塔建站 mysql在哪_宝塔面板安装LAMP,创建网站,创建数据库