Python学习_12_方法和类定制
方法
在上一篇随笔中,简单提到了类的某些方法:__init__()等的调用,并简要说明方法和函数的区别。
方法是在类内部定义的函数,方法也是对象,所以方法是类的属性,这就是为什么说实例的方法存在于类定义中。而在ruby中,方法肯定是存在于类中的,实例的单件方法就存在于单件类中,python中并没有单件类,并且方法本质也是变量,任何对象在调用方法时,遵循命名空间的查找顺序,不论是对象还是类,其方法不过是对函数对象的引用。但是方法和一般是属性任然存在区别:
from types import MethodType
class MyClass:
#@staticmethod
def my_method(self):
print("This is a class method")
obj = MyClass()
print('obj_m',id(obj.my_method))
#obj2 = MyClass()
#print('obj2_m',id(obj2.my_method))
#a = obj.my_method
print('cls_m',id(MyClass.my_method))
def my_method(self):
print("This is a obj method")
obj.my_method = MethodType(my_method,obj)
print('obj_m',id(obj.my_method))
print('cls_m',id(MyClass.my_method))
def my_method(self):
print("This is a obj method2")
obj.my_method = MethodType(my_method,obj)
print('obj_m',id(obj.my_method))
得到的结果为:
obj_m 4337531000
cls_m 4337792688
obj_m 4337531000
cls_m 4337792688
obj_m 4337531792
可以看到,一开始设定了一个普通函数,结果发现在类中该函数的引用和对象中函数的引用并不相同,而在对象中对该函数进行修改时,第一次修改并没有改变引用,第二次修改时,引用却发生改变了,而类对函数的引用当然是不会变的。由于第二次修改确实是改变了引用,说明函数确实是不可更改类型(这一点可以通过更加简单的实验得到),那第一次对对象改变函数为什么并没有改变其引用呢?其实是因为在这里对象的函数和类的函数并不是同一个引用,当第一次改变对象的函数时,原来的对象的函数引用次数就变为0,地址被系统回收,当我们给对象定义一个同名函数时,又分到了同样的地址,实际上是改变了引用了。可以通过增加该方法的引用次数来验证(第四处注释,如果去掉注释,引用将会不同)。
好了,绕了很多的弯路又回到原点:对象的函数和类的函数一开始就不是同一个引用,这是因为,在对象调用函数(这里强调函数是因为就算去掉self也是一样)时,会给函数传递该对象的绑定,所以对象调用的函数是有绑定的函数,而类调用的是没有绑定的函数,所以他们的引用不一样。方法的引用仅仅是因为调用了一个绑定而变得不同,绑定不同的对象对函数的引用没有影响(去掉第二、三行的注释可以实验)。
为了验证,可以实验以下代码:
class MyClass:
pass
class MyClass2:
pass
print(id(MyClass2.__new__))
print(id(MyClass.__new__))
print(id(type.__new__))
静态方法和类方法
在上述代码的第一行注释中,有@staticmethod装饰器,如果去掉该注释,则会发现类和对象对函数的引用是一样的,这就是静态方法,静态方法对类和对象是平等的,但是并不表示完全相同,因为类对函数的调用仍然不会附带绑定:如果在静态方法中调用self,那么对于对象而言,仍然不需要传入自身,而对于类而言,必须传入一个对象以供调用(可以传入MyClass),因为此时只是调用了MyClass命名空间中的一个函数,并没有获得MyClass的绑定。
之所以对象调用方法时,不用显式传入自身,是因为方法在类中定义时,self的含义就是类实例化后的对象,对象在调用自己类的方法时,解释器会帮助将该对象传给方法。静态方法的区别就是解释器在对象和类调用方法的过程中引用同一个函数对象,而如果是一般的方法,则解释器认为对象调用和类调用往往是不同的,就从一开始就引用了不同的函数对象。(以上推测没有实验验证)
类方法则指的是第一个参数为类本身,没有像self那样的名字,但是一般使用cls作为变量名:
class MyClass:
@classmethod
def a_method(cls):
print(cls)
MyClass.a_method()
此时,也可以不用显式地传入对象。
类定制
python中所谓的类定制,就是为类实现某一些特定的方法,使其具有一些特定的属性,或者可以对其进行一些特定操作。这些特殊的方法以双下划线开头并且以双下划线结尾。其实__init__方法就是最基本的定制类的特殊方法,通过__init__方法可以定制类实例的实例化过程。
其中一些可能比较常用的定制有:
1. 定制__str__方法,可以使类的实例可以通过str()转换为字符串,并且由于print打印时其实是调用了str(),所以可以自定义打印的格式;
2. 定制__len__方法,可以自定义调用len()时,返回的值;
3. 定制__iter__方法,可以使类的实例成为一个迭代对象,此时,需要实现__next__方法(python2中为next方法),使迭代过程完整执行,在__next__方法中,指定StopIteration错误,以终止迭代。
4. 定制__cmp__方法,__lt__、__le__、__gt__、__ge__、__eq__、__ne__等方法可以自定义比较大小的规则;
5. 定制__*add__、__*sub__等等数值操作的方法,可以自定义类实例的+-*/等操作,*表示存在__add__、__radd__、__iadd__等多种方法,默认方法从左往右计算,r开头的方法从右往左计算,i开头的表示左结合操作符和赋值的组合,类似于+=
6. 定制__call__方法可以使类的实例能够被调用
等等
如果想得到更加具体的例子,以下文章应该会由很大帮助:
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013946328809098c1be08a2c7e4319bd60269f62be04fa000
Python学习_12_方法和类定制的更多相关文章
- Python学习笔记总结(三)类
一.类简单介绍 1.介绍 类是Python面向对象程序设计(OOP)的主要工具,类建立使用class语句,通过class定义的对象. 类和模块的差异,类是语句,模块是文件. 类和实例 实例:代表程序领 ...
- Python学习总结19:类(二)
参考:http://python.jobbole.com/82308/ 继承和__slots__属性 1. 继承 在Python中,同时支持单继承与多继承,一般语法如下: class SubCl ...
- Python学习总结19:类(一)
在Python中,可以通过class关键字定义自己的类,通过类私有方法“__init__”进行初始化.可以通过自定义的类对象类创建实例对象. class Student(object): count ...
- python学习小结4:类
虽然Python是解释性语言,但是它是面向对象的,能够进行对象编程. 类和对象是面向对象编程的两个主要方面.类:创建一个新类型,而对象是这个类的实例,类使用class关键字创建.类的域和方法被列在一个 ...
- Python属性、方法和类管理系列之----描述符类
什么是描述符类? 根据鸭子模型理论,只要具有__get__方法的类就是描述符类. 如果一个类中具有__get__和__set__两个方法,那么就是数据描述符,. 如果一个类中只有__get__方法,那 ...
- Python学习日记(二十三) 类命名空间和组合
类命名空间 在一个类中它的函数(方法)属于动态属性,直接定义的变量属于静态属性 首先先定义一个类,并在这个类里面加入静态变量.属性等然后将一个对象实例化 class Fighter: #定义一个战机的 ...
- python学习-65 继承2-子类中调用父类的方法
子类中调用父类的方法 1.子类继承了父类的方法,然后想进行修改,那么就需要在子类中调用父类的方法. 2.方法一:父类名 class School: Country = 'china' def __in ...
- python 学习笔记7(类/对象的属性;特性,__getattr__)
27. 属性的__dict__系统 1)对象的属性可能来自: 其类的定义,叫做类属性 继承父类的定义 该对象实例定义(初始化对象时赋值),叫做对象属性 2)对象的属性存储在对象的 __dict__ 属 ...
- Python属性、方法和类管理系列之----属性初探
在学习dict的时候,肯定听过dict是Python中最重要的数据类型,但是不一定知道为什么.马上你就会明白原因了. Python中从模块.到函数.到类.到元类,其实主要管理方法就是靠一个一个的字典. ...
随机推荐
- hiho-1015- KMP算法
#1015 : KMP算法 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在 ...
- 调试和运行matlab代码(源程序)的技巧和教程
转载请标明出处:专注matlab代码下载的网站http://www.downma.com/ 本文主要给大家分享使用matlab编写代码,完成课程设计.毕业设计或者研究项目时,matlab调试程序的技巧 ...
- “use strict” 严格模式使用(前端基础系列)
ECMAscript5添加一种严格模式的运行模式("use strict"),让你的js语句在更加严格的环境下进行运行: 一.主要作用: 消除版本javascript中一些不合理及 ...
- java 后台代码调用接口
import com.jiuqu.jollykeys.common.util.JsonUtil;import java.io.UnsupportedEncodingException;import j ...
- day1-Python入门
百度云有关文档资料链接 链接:https://pan.baidu.com/s/1pLighnX 密码:j69s
- Java 面试宝典
1. 类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,他们的执行顺序 答:先静态.先父后子. 先静态:父静态 > 子静态 优先级:父类 > 子类 静态代码块 ...
- Python之编程基础(编程语言分类)
一.编程语言简介 编程语言主要从以下几个角度进行分类,编译型和解释型.静态语言和动态语言.强类型定义语言和弱类型定义语言. 1.编译型跟解释型 编译型,其实他和汇编语言是一样的,也是有一个负责翻译的程 ...
- mysql 基本语法
################################################################# #author: 陈月白 #_blogs: http://www.c ...
- WIN7下安装SVNserver端及client搭建协作环境
一.客户场景: 客户现场须要在虚拟机上封闭开发,所以须要搭建一个SVN协作开发环境.客户提供了一台全新的裸机安装的操作系统是WIN7旗舰版64位. 二.SVNserver搭建 1. SVNserver ...
- 《Effective Modern C++》翻译--简单介绍
北京时间2016年1月9日10:31:06.正式開始翻译.水平有限,各位看官若有觉得不妥之处,请批评指正. 之前已经有人翻译了前几个条目,有些借鉴出处:http://www.cnblogs.com/m ...