大彩网走势图大全-高质量python代码:按需生成特点

写在前面:内容参照自《Effective Python》,其实你完全能够直接去看书,什么?你不想自己看书,那么大彩网走势图大全-高质量python代码:按需生成特点你也能够重视我,我会不定期从书中挑出常用到的有用办法共享出来,这样你就能够一边刷头条,一边学习常识,岂不美哉。

正文

其实这篇的标题应该为:用 __getattr__、__getattribute__ 和 __setattr__ 完结按需生成的特点,仅仅头条标题字数有约束,只能简略写了。个人觉得这篇内容很重要,像 Django 就许多运用元类编程方面的东西,还有些时分你阅览其他大佬写的代码,你会发现有许多运用到本篇所讲的内容,所以主张耐性阅览。

Python 言语供给了一些挂钩,使得开发者很简单就能编写出通用的代码,以便将多个体系黏合起来。例如,咱们要把数据库的行(row)表明为 Python 目标。由于数据库有自己的一套结构(schema),也称架构、形式、纲要、概要、纲要大彩网走势图大全-高质量python代码:按需生成特点,所以在操作与行相对应的目标时,咱们有必要知道这个数据库的结构。可是,把 Python 目标与数据库相连接的这些代码,却不需求知道行的结构,所以,这部分代码应该写得通用一些。

那么,怎么完结这种通用的代码呢?一般的实例特点、@property 办法和描述符,都不能完结此功用,由于它们都有必要预先界说好,而像这样的动态行为,则能够经过 Python 的__getattr__特别办法来做。假如某个类界说了__getattr__,一起体系在该类目标的实例字典中又找不到待查询的特点,那么,体系就会调用这个办法。

下面,拜访 data 目标所缺失的 foo 特点。这会导致 Python 调用方才界说的 __getattr__ 办法,然后修正实例的dict字典:

然后,给 LazyDB 增加记载功用,把程序对 __getattr__ 的调用行为记载下来。请注意,为了防止无限递归,咱们需求在 LoggingLazyDB 子类里边经过 super()__.getatr__() 来获取真实的特点值。

由于exists特点自身就在实例字典里边,所以拜访它的时分,绝不会触发 大彩网走势图大全-高质量python代码:按需生成特点__getattr__。而foo特点刚开始并不在实例字典中,所以初度拜访的时分会触发 __getattr__。由于 __getattr__ 又会调用 __setattr__ 办法,并把 foo 放在实例字典中,所以第2次拜访 foo 的时分,就不会再触发 __getattr__ 了。

这种行为十分合适完结无结构数据(schemaless data,无形式数据)的按需拜访。初度履行__ge大彩网走势图大全-高质量python代码:按需生成特点tattr__的时分进行一些操作,把相关的特点加载进来,今后再拜访该特点时,只需从现有的成果之中获取即可。

现在假定咱们还要在数据库体系中完结业务(transaction,买卖)处理。用户下次拜访某特点时,咱们要知道数据库中对应的行是否仍然有用,以及相关业务是否仍然处于敞开状况。这样的需求,无法经过__getattr__挂钩可靠地完结出来,由于 Python 体系会直接从实例字典的现存特点中敏捷查出该特点,并回来给调用者。

为了完结此功用,咱们能够运用 Python 中的别的一个挂钩,也便是__getatribute__。程序每次拜访目标的特点时,Python 体系都会调用这个特别办法,即便特点字典里边现已有了该特点,也仍然会触发 __getattribute__ 办法。这样就能够在程序每次拜访特点时,查看大局业务状况。下面界说的这个 ValidatingDB 类,会在 __getatribute__ 办法里边记载每次调用的时刻。

依照 Python 处理缺失特点的规范流程,假如程序动态地拜访了一个不应该有的特点,那么能够在 __getattr__ 和 __getattribute__ 里边抛出 AttributeError 反常。

完结通用的功用时,咱们常常会在 Python 代码里运用内置的 hasattr 函数来判别目标是否现已具有了相关的特点,并用内置的 __金红杨getattr__ 函数来获取特点值。这些函数会先在实例字典中查找待查询的特点,然后再调用 __getattr__。

现在,假定当程序把值赋给 Python 目标之后,咱们要以慵懒的办法将其推回数据库。此功用能够用 Python 所供给的 __setattr__ 挂钩来完结,它与前面所讲的那两个挂钩相似,能够阻拦对特点的赋值操作。可是与 __getattr__ 和 __getattribute__ 不同的当地在于,咱们不需求分红两个办法来处理。只要对实例的特点赋值,无论是直接赋值,仍是经过内置的 __setattr__ 函数赋值,都会触发 __setatr__ 办法。

下面界说的这个 LoggingSavingDB 类,是 SavingDB 的子类,每次对它的特点赋值时,都会触发 __setattr__ 办法。

运用 __getattribute__ 和 __setattr__ 挂钩办法时要注意:每次拜访目标特点时,它们都会触发,而这或许并不是你想要的作用。例如,咱们想在查询目标的特点时,从目标内部的一份字典里边,搜索与待查特点相关联的特点值。

上面这段代码,会在 __getattribute__ 办法里边拜访 self._data。试着运转一下,你就会发现:这段代码将导致 Python 程序重复递归,然后令其打破最大的栈深度并溃散。

问题在于,__getatribute__会拜访 self._data,而这就意味着需求再次调用__getattribute__,然后它又会持续拜访 self._data,并无限循环。解决办法是选用super().__getatribute__() 办法,从实例的特点字典里边直接获取 _data 特点值,以防止无限递归。

与之相似,假如要在 __setattr__ 办法中修正目标的特点,那么也需求经过 super().__setattr__() 来完结。

关键

  • 经过 __getattr__ 和 __setatr__,咱们能够用慵懒的办法来加载并保存目标的特点。
  • 要了解 __getattr__ 与 __getattribute__ 的差异:前者只会在待拜访的特点缺失时触发,而后者则会在每次拜访特点时触发。
  • 假如要在 __getattribute__ 和 __setattr__ 办法中拜访实例特点,那么应该直接经过super()(也便是object类的同名办法)来做,以防止无限递归。