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

时间: 2024-10-25 15:32:21

Python学习_12_方法和类定制的相关文章

python学习笔记☞方法

方法: 类的功能有一个更通俗的名字叫方法.在python中,方法定义在类定义中,但只能被实例调用.也就是说,调用一个方法的最终途径必须是这样的:(1)定义类(和方法);(2)创建一个实例:(3)最后一步,用这个实例调用方法. 例如" class mydatawithmethod(object): #定义类 def printFoo: #定义方法 print 'you invoked printFoo()!'

Python学习笔记总结(三)类

一.类简单介绍 1.介绍 类是Python面向对象程序设计(OOP)的主要工具,类建立使用class语句,通过class定义的对象. 类和模块的差异,类是语句,模块是文件. 类和实例 实例:代表程序领域中具体的元素. 类是生产实例的工厂,实例就像带有“数据"的记录,而类是处理这些记录的“程序”. 类是实例工程,类的属性提供行为(数据以及函数[方法]),所有从类产生的实例都继承该类的属性. 类的一个实例可以通过:实例.属性,实例.方法,获得类的属性和方法调用.类支持继承,当我们对class语句产生

Python 学习笔记 - 面向对象(类成员)

上一篇学习了Python面向对象的3大特性,封装,继承和多态,这一篇继续学习类成员,包括字段,方法,属性以及他们的修饰符. 1.字段 字段分为静态字段和普通字段.静态字段属于类,而普通字段属于对象,因此静态字段在内存中只保存一份,而普通字段在每个对象中都保存了一份.定义的时候静态字段定义在类的范围里面,而普通字段定义在方法里面. 例如: >>> class Foo:     # 字段(静态字段)     CC = 123     def __init__(self):         #

Python学习总结19:类(一)

在Python中,可以通过class关键字定义自己的类,通过类私有方法“__init__”进行初始化.可以通过自定义的类对象类创建实例对象. class Student(object): count = 0 books = [] def __init__(self, name, age): self.name = name self.age = age pass 1. 数据属性 在上面的Student类中,”count””books””name”和”age”都被称为类的数据属性,但是它们又分为类

python学习小结4:类

虽然Python是解释性语言,但是它是面向对象的,能够进行对象编程. 当一个类定义完之后,就产生了一个类对象.类对象支持两种操作:引用 和 实例化. 引用操作是通过类对象去调用类中的属性或者方法,而实例化是产生出一个类对象的实例,称作实例对象. class people: # 定义了一个类 name = 'jack' # 定义了一个属性 age = 12 # 如果想定义成私有的,则需在前面加2个下划线 '__' p = people() # 实例化了一个对象 p print p.name,p.a

Python学习————绑定方法

一:Python多继承的正确打开方式:minins机制 Mixins核心:在多继承背景下,尽可能地提升多继承的可读性 让多继承满足人的思维习惯 ==> 什么 是 什么 class Vehicle: # 交通工具 def fly(self): print("I am flying") class CivilAircraft(Vehicle): # 民航飞机 pass class Helicopter(Vehicle): # 直升飞机 pass class Car(Vehicle):

Python学习笔记__7.3章定制类

1.概览 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函数. 除此之外,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类. 1.1.__str__()  和 __repr__() 1.__str__() 修改print(instance) 显示的值 # 正常打印instance >>> p

python 学习笔记 函数和类

与java类似 python的函数也是出于可以复用才使用的 如果一段代码没有复用的价值就可以不用函数 一般的函数可以定义成这样: def func(a,b=123,*arg,**args): for x in arg:#arg是一个list print x for x,y in args.items():#args是一个dict print x,y print 'a:',a print 'b:',b func(1,1,2,3,4,c=1,d=2) 结果: 2 3 4 c 1 d 2 a: 1 b

python学习day11 面向对象编程 类和实例

class Student(object): #class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的.通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类. def __init__(self,name,score): #通过定义一个特殊的__init__方法,在创建实例的时候,就把类的name,score等属性绑上去,__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__