前言

跟着一个有强迫症的老板干活是一件极其幸福的事情(你懂的)。最近碰到一个问题,简单的说就是对一个对象做出部分修改后仍然返回此对象,于是我就写了一个方法,老板看了之后只有一句话:不雅观,改成直接对此对象调用此方法。我脑海里千万个不情愿,然而没有办法,不得不低头,精通C#、Java、Scala等多种语言HelloWorld的我,一想便知这是扩展方法。于是开始Google之,看似简单的问题,其实里面也有一些细节需要注意,在此记录之。

Level 1

原理很简单,将方法的第一个对象改成self(self即为需要扩展方法的对象的实例),其余不变,无需返回此对象,在此方法外部将此方法赋给此类。当需要调用的时候引入此包即可。大致如下:

class A():
def m2():
... ... def m1(self):
// TODO: Do sth to this instance.
... A.m1 = m1 a = A()
a.m1()

当然m1方法也可以添加其他参数,只需要放在self后面即可。

Level 2

过了几天,老板又提了一个新的需求:某个类有一个m1方法,但是老板想修改此方法,使其更加完善。看上去没有什么难的吗,同样是个扩展方法,于是我写代码如下:

class A():
def m1():
... def m2():
...
... def m1(self):
// TODO: Do sth to this instance.
self.m1()
... A.m1 = m1 a = A()
a.m1()

满心欢喜本以为这么简单的就解决了问题。调试,悲剧的是直接报错,错误为递归调用。细细想来确实如此,在此作用域内直接对self对象调用m1方法,应当是已经扩展后的方法,那么当然会产生循环调用的问题。

我想到应当可以通过先修改类中m1方法名称来解决此问题,但是具体不知道如何操作,于是在StackOverflow中提了个问题,很快就有老外大牛回复了。见https://stackoverflow.com/questions/46460250/how-to-call-a-method-that-has-been-overridden-by-an-extension-method#。所以问题的核心在于我们可以通过下述代码定义一个类的方法:

_m1 = A.m1

同样调用的时候将实例作为第一个参数传入。于是代码进行如下改造即可:

class A():
def m1():
... def m2():
...
... _m1 = A.m1 def m1(self):
// TODO: Do sth to this instance.
_m1(self)
... A.m1 = m1 a = A()
a.m1()

这样即解决了递归调用的问题,但是此处有一个细节需要注意,_m1必须定义在m1方法上部,由于_m1是定义在m1扩展方法之上的,所以此处仍是A类中的m1方法,若是定义在m1扩展方法中,则又会出现递归调用的问题。

Level 3

下午看了一下上面在StackOverflow中提的问题,又有一个新的答案,分析了一下他主要介绍了两点知识,覆盖类的方法和覆盖实例的方法,即扩展方法对整个类生效和只对某个实例生效。

对整个类扩展

除了直接写A.plot = plot外,还可以写成:

setattr(A, 'plot', plot)

A代表需要扩展的类,'plot'为扩展后的方法名,plot为重写的扩展方法。当然如果扩展后的方法名在原类中已有,则覆盖之;若无则为新的方法。

对具体实例扩展

让我比较意外的是python可以对某个实例进行方法扩展,这在其他语言中似乎是基本没有的。

当然我们不能用a.plot = plot的形式为a这个A的实例扩展方法,但是可以通过下述方式对a扩展方法:

a.plot = types.MethodType(plot, a)

这样只有a有此扩展方法,或者是只有a的此方法被修改了,其他实例并不受影响。

总结

本文简单记录了Python扩展方法实现方式、类的方法的重定义、实例方法扩展等细节,供需查看。

Python扩展方法一二事的更多相关文章

  1. python扩展实现方法--python与c混和编程 转自:http://www.cnblogs.com/btchenguang/archive/2012/09/04/2670849.html

    前言 需要扩展Python语言的理由: 创建Python扩展的步骤 1. 创建应用程序代码 2. 利用样板来包装代码 a. 包含python的头文件 b. 为每个模块的每一个函数增加一个型如PyObj ...

  2. python扩展实现方法--python与c混和编程

    前言 需要扩展Python语言的理由: 创建Python扩展的步骤 1. 创建应用程序代码 2. 利用样板来包装代码 a. 包含python的头文件 b. 为每个模块的每一个函数增加一个型如PyObj ...

  3. C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理

    C#编译器优化那点事   使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...

  4. 为IEnumerable<T>添加RemoveAll<IEnumerable<T>>扩展方法--高性能篇

    最近写代码,遇到一个问题,微软基于List<T>自带的方法是public bool Remove(T item);,可是有时候我们可能会用到诸如RemoveAll<IEnumerab ...

  5. .NET中那些所谓的新语法之二:匿名类、匿名方法与扩展方法

    开篇:在上一篇中,我们了解了自动属性.隐式类型.自动初始化器等所谓的新语法,这一篇我们继续征程,看看匿名类.匿名方法以及常用的扩展方法.虽然,都是很常见的东西,但是未必我们都明白其中蕴含的奥妙.所以, ...

  6. 【开源】OSharp框架解说系列(3):扩展方法

    OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...

  7. Python基础+Pythonweb+Python扩展+Python选修四大专题 超强麦子学院Python35G视频教程

    [保持在百度网盘中的, 可以在观看,嘿嘿 内容有点多,要想下载, 回复后就可以查看下载地址,资源收集不易,请好好珍惜] 下载地址:http://www.fu83.cc/ 感觉文章好,可以小手一抖 -- ...

  8. Python list方法总结

    1. 向列表的尾部添加一个新的元素 append(...) L.append(object) -- append object to end 1 2 3 4 >>> a = ['sa ...

  9. 23.C#Queryable的扩展方法(十二章12.1-12.2)

    今天要写的知识还真心有点绕呢,对于第一节的内容,其实是把原先在内存中的数据源,换成了从数据库中提取出来的数据.从代码的使用方式上是一样的,直接跳过,来看看IEnumerable和IQueryable的 ...

随机推荐

  1. 纹理混合遇到的问题 pre-multiplying OpenGL Android iOS

    纹理混合遇到的问题 pre-multiplying OpenGL Android iOS Alpha-blending pre-multiplying of texture OpenGL Androi ...

  2. node.js后台快速搭建在阿里云(一)(express篇)

    前期准备 阿里云服务器 node.js pm2 express nginx linux(推荐教程:鸟哥的私房菜) 简介 嗯……我只是个前端而已 前段时间写过一个.net mvc的远程发布,关于.net ...

  3. linux Module驱动开发-一切刚刚开始

    linux内核是可以高度定制的,通过配置编译选项达到定制的目的. 在配置kernel编译选项时驱动程序的编译选项一般有三种,不编译.编译为内核驱动.编译为模块驱动.所以linux驱动一般分为两类,内核 ...

  4. 分布式测试工具Beetle.DT的部署并进行HTTP,SQL,TCP压测

    由于Beetle.DT是一个分布式压力测试工具,所以在使用上并不像普通工具那样安装运行这么简单:由于工具涉及到测试管理中心,节点和管理端等工具: 所以必须要进行相应的部署才能运行.接下来详解一下如果安 ...

  5. HTTP协议知多少-关于http1.x、http2、SPDY的相关知识

    作为网站开发的基础协议,我们知道浏览器上都有输出http这四个字母,这意味着什么呢? 这就是最基础的HTTP协议. 逐浪君今天为各位大人准备了一些HTTP技术的知识,来和大家分享. 以下图为例: 这一 ...

  6. css中使用变量

    2017年3月,微软宣布 Edge 浏览器将支持 CSS 变量.这个重要的 CSS 新功能,所有主要浏览器已经都支持了. 声明css变量的时候,变量名前面要加两根连词线(--).变量名大小写敏感,-- ...

  7. js 对于回车时间的监听,提交表单

    // ------ 监听回车事件 -----------------// document.onkeydown=keyDownSearch; function keyDownSearch(e) { / ...

  8. Java之JMX 详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt194 一.JMX简介 JMX是一种JAVA的正式规范,它主要目的是让程序有被 ...

  9. 百度AI开放平台- API实战调用

    百度AI开放平台- API实战调用 一.      前言 首先说一下项目需求. 两个用户,分别上传了两段不同的文字,要计算两段文字相似度有多少,匹配数据库中的符合条件的数据,初步估计列出来会有60-1 ...

  10. MIT6.828课程JOS在macOS下的环境配置

    本文将介绍如何在macOS下配置MIT6.828 JOS实验的环境. 写JOS之前,在网上搜寻JOS的开发环境,很多博客和文章都提到"不是32位linux就不好配置,会浪费大量时间在配置环境 ...