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中从模块.到函数.到类.到元类,其实主要管理方法就是靠一个一个的字典. ...
随机推荐
- 室内地图1:从CAD到Map(画图,发布,路径导航)
首先这个教程整理,比较偏细节. 因为我本身不是做GIS,所以可能有点流水账,当然错漏难免,恳请指正. 当我们做定位的时候,想要可视化展示,室外当然可以直接使用google,百度的底图.对于室内,有两种 ...
- 毕达哥拉斯树(pythagorasTree)原理解析及canvas动画实现
以前就看到了这个东西,由于太忙了最近才有时间来实现这个; 该文章适合有一定 canvas 基础的人阅读; 首先说说他的原理: The construction of the Pythagoras tr ...
- java 可变參数
我们在某些特定的需求环境下,可能要对某一个方法中的參数进行一些操作,并且这些方法中的參数是不规定的,那么问题来了,我们该怎么办呢? java事实上就为我们考虑了这样的情况,那就是使用可变參数 可变參数 ...
- 重要经验五:block作为属性的注意事项
现代ios应用的开发.不使用GCD和block,效率会减少非常多,在今年3月份之前,我在block的学习和使用方面,精力和经验都明显不足,在SF有个牛逼同事.不仅自己积累了一套库,并且对这个库持续进行 ...
- CentOS6.5安装MySQL5.6
CentOS6.5安装MySQL5.6,开放防火墙3306端口,允许其他主机使用root账户密码访问MySQL数据库 查看操作系统相关信息 ** 该查看方法只适用于CentOS6.5 (lsb_rel ...
- Java SpringMVC 定时任务
1.web.xml 2.spring-mvc.xml <?xml version="1.0" encoding="UTF-8"?> <bean ...
- Intellij IDEA中使用Protobuf的正确姿势
一..proto文件语法高亮显示 需要安装Protobuf Support插件 依次点击Intellij中的"File"-->"Settings"--&g ...
- 【java设计模式】【行为模式Behavioral Pattern】迭代器模式Iterator Pattern
package com.tn.pattern; public class Client { public static void main(String[] args) { Object[] objs ...
- VM环境下Linux虚拟机扩展存储空间操作方法总结
用VMwareware虚拟机安装的 Linux 系统剩余空间不足,造成软件无法正常安装.如果重新装一遍系统就需要重新配置好开发环境和软件的安装配置. 一.空间扩展 (1)打开VMware,选择Edi ...
- Node.js前言
最近在学Node.js,所以学到一点东西就更新在上面吧,如果有错误,欢迎大家指正.