本文共 10356 字,大约阅读时间需要 34 分钟。
使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:
class ClassName: '类的帮助信息' #类文档字符串 class_suite #类体
类的帮助信息可以通过ClassName.__doc__查看。
class_suite 由类成员,方法,数据属性组成。
2、类对象
Python
中一切皆对象;类定义完成后,会在当前作用域中定义一个以类名为名字,指向类对象的名字。
会在当前作用域定义名字ClassName,指向类对象ClassName。
类对象支持的操作:
总的来说,类对象仅支持两个操作:instance_name = class_name()
的方式实例化,实例化操作创建该类的实例。class_name.attr_name
的方式引用类属性。self代表类的实例,而非类在类中定义函数时,函数参数列表中会自动默认带有一个self参数。
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self,代表当前对象的地址。
self 不是 python 关键字.
此处有几种潜在含义:
1.这里的自己,指的是,实例Instance本身。
2.同时, 由于说到“自己”这个词,都是和相对而言的“其他”而说的;而此处的其他,指的是,类Class,和其他变量,比如局部变量,全局变量等。
__init__()方法是一种特殊的方法,被称为 类的构造函数或初始化方法 ,当创建了这个类的实例时就会调用该方法
属性访问:
#coding:utf-8class Myclass: #变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 a=1 b=11 #初始化方法,且所有参数都要初始化
# def __init__(self,i,b,d): #实例变量 self.i=2 #self.b和b的区别. self.b=b self.d=7 #实例化后覆盖外部的a self.a=100 self.c='a' #访问外部的a Myclass.a+=1 def fun(self): #访问的都是__init__中变量 print self.a print self.i print self.b print self.c return 'fun'#属性引用print Myclass.bMyclass.a=6print Myclass.aprint#创建实例对象#实例化x=Myclass(1,8,7)print x.aprint x.fun()print x.iprint x.cprint#访问的还是函数外部的a(即类变量)print Myclass.a实例变量与类变量(属性):
1. 访问权限
类变量通过类名点操作访问也可以通过实例点操作访问className.varobjectName.var
实例变量只可以通过实例名点操作访问objectName.var
2. 类变量修改后的表现
通过className.var修改类变量,该类和所有实例所共享的数据将被修改,再次通过类或实例访问得到的将是新的数据。
通过objectName.var修改类变量,其效果将仅仅作用在该实例上,再次通过类或其它实例访问得到的仍然是旧的数据。但这一修改方式将对该类变量实例化,其结果是该实例将得到一个单独的该变量拷贝,此后此对象不再与类共享该名称的变量
实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。
以下使用类的名称 Myclass 来实例化,并通过 __init__ 方法接受参数。
class Myclass: a=99 def __init__(self,a,b,c): self.a=a self.b=b self.c=c def Fun(self): print self.a print Myclass.a#创建实例对象Myobj1=Myclass(6,"ABC",9)Myobj2=Myclass('abc','dfs',22)#访问方法Myobj1.Fun()Myobj2.Fun()#添加一个新的属性Myobj1.d=10print Myobj1.d#删除属性del Myobj1.d
也可以使用以下函数的方式来访问属性:
class Myclass: a=99 def __init__(self,a,b,c): self.a=a self.b=b self.c=c def Fun(self): print self.a print Myclass.a#创建实例对象Myobj1=Myclass(6,"ABC",9)Myobj2=Myclass('abc','dfs',22)if hasattr(Myobj1,'f'): print getattr(Myobj1, 'f')else: Myobj1.f=100 setattr(Myobj1,'f','OK') print getattr(Myobj1,'f')delattr(Myobj1,'f')print getattr(Myobj1,'a')#无法删除初始化方法中的实例属性delattr(Myobj1,'a')print getattr(Myobj1,'a')
class Myclass: a=99 def __init__(self,a,b,c): self.a=a self.b=b self.c=c def Fun(self): print self.a print Myclass.aprint "Myclass.__doc__:", Myclass.__doc__print "Myclass.__name__:", Myclass.__name__print "Myclass.__module__:", Myclass.__module__print "Myclass.__bases__:", Myclass.__bases__print "Myclass.__dict__:", Myclass.__dict__
Python 使用了引用计数这一简单技术来跟踪和回收垃圾。
在 Python 内部记录着所有使用中的对象各有多少引用。
一个内部跟踪变量,称为一个引用计数器。
当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。
a = 40 # 创建对象 <40>b = a # 增加引用, <40> 的计数c = [b] # 增加引用. <40> 的计数del a # 减少引用 <40> 的计数b = 100 # 减少引用 <40> 的计数c[0] = -1 # 减少引用 <40> 的计数
垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。循环引用指的是,两个对象相互引用,但是没有其他变量引用他们。这种情况下,仅使用引用计数是不够的。Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。 在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环。
析构函数 __del__ ,__del__在对象销毁的时候被调用,当对象不再被使用时,__del__方法运行:
class Myclass: a=99 def __init__(self,a,b,c): self.a=a self.b=b self.c=c def Fun(self): print self.a print Myclass.a def __del__(self): classname=self.__class__.__name__ print classname,"销毁"Myobj=Myclass(1,2,3)del Myobj
三、类的继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。
需要注意的地方:继承语法 class 派生类名(基类名)://... 基类名写在括号里,基本类是在类定义的时候,在元组之中指明的。
在python中继承中的一些特点:
如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。
语法:
派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下声明:
class SubClassName (ParentClass1[, ParentClass2, ...]): 'Optional class documentation string' class_suite
#定义父类class parent: def __init__(self): print '调用父类构造函数' def parent_fun(self): return 'parent_Fun'#定义子类class child(parent): def __init__(self): print '调用子类构造函数' def child_fun(self): return 'child_Fun'c=child()c.child_fun()c.parent_fun()
kj如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法
下表列出了一些通用的功能,你可以在自己的类重写:
序号 | 方法, 描述 & 简单的调用 |
---|---|
1 | __init__ ( self [,args...] ) 构造函数 简单的调用方法: obj = className(args) |
2 | __del__( self ) 析构方法, 删除一个对象 简单的调用方法 : del obj |
3 | __repr__( self ) 转化为供解释器读取的形式 简单的调用方法 : repr(obj) |
4 | __str__( self ) 用于将值转化为适于人阅读的形式 简单的调用方法 : str(obj) |
5 | __cmp__ ( self, x ) 对象比较 简单的调用方法 : cmp(obj, x) |
Python同样支持运算符重载,
class MyC: def __init__(self,a,b): self.a=a self.b=b def __str__(self): return 'MyC(%d,%d)'%(self.a,self.b) def __add__(self, other): return MyC(self.a+other.a,self.b+other.b)a1=MyC(2,10)a2=MyC(1,1)print a1+a2
__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
在类的内部,使用 def 关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数
__private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用 self.__private_methods
class Myclass: _a=2 #受保护 __b=3#私有 c=6 #公有 def __init__(self,a,b,c): self._a=a self.__b=b self.c=c def fun(self): print self._a print self.__b print Myclass._a print Myclass.__b def _fun1(self):#受保护方法 print 'ABCD' def __fun2(self):#私有方法 print 'CSDSS'class Myclass1(Myclass): def __init__(self): self.a=1 def func(self): print self._a # print self.__b (私有变量不能继承) print Myclass._a # print Myclass.__b(私有不能继承) self._fun1() #继承protected方法 # self.__fun2()#私有方法不能继承Obj=Myclass(1,2,3)print Myclass._a# print Myclass.__b(私有)print Obj._a# print Obj.__b(私有)Obj.fun()printObj1=Myclass1()Obj1.func()
__foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的。
_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。
使用属性函数的最简单的方法之一是将它作为一个方法的装饰器来使用。这可以让你将一个类方法转变成一个类属性。
class person(object): def __init__(self,first_name,last_name): self.first_name=first_name self.last_name=last_name @property def full_name(self): return '%s,%s'%(self.first_name,self.last_name)people=person('Zhangsan','Lisi')print people.full_name#AttributeError: can't set attribute# people.full_name='Wangxiaoer'# print people.full_name#间接修改people.first_name='LiHua'print people.full_name
在上面的代码中,创建了两个类属性:self.first_name和self.last_name。创建了一个full_name方法,它有一个@property装饰器。
将方法变成了属性,我们可以使用正常的点符号访问它。但是,如果我们试图将该属性设为其他值,我们会引发一个AttributeError错误。改变full_name属性的唯一方法是间接这样做:
people.first_name='LiHua'
这是一种限制。
若要获得属性值或修改属性值,如下:
class Myclass: def __init__(self,Val1,Val2): self.Val1=Val1 self.Val2=Val2 def getVal(self): return '(Val1,Val2)=(%d,%d)'%(self.Val1,self.Val2) def set(self,val1,val2): self.Val1=val1 self.Val2=val2obj=Myclass(6,8)print obj.getVal()obj.set(2,1)print obj.getVal()
如果你想添加可以使用正常点符号访问的属性,而不破坏所有依赖于这段代码的应用程序,你可以通过添加一个属性函数非常简单地改变它:
class Myclass: def __init__(self,Val1,Val2): self.Val1=Val1 self.Val2=Val2 def getVal(self): return '(Val1,Val2)=(%d,%d)'%(self.Val1,self.Val2) def set(self,val1,val2): self.Val1=val1 self.Val2=val2 SetGet=property(getVal,set)obj=Myclass(6,8)print obj.getVal()obj.set(2,1)print obj.getVal()obj.SetGet=(5,0)print obj.SetGet#没有真正的改变原值print obj.getVal()
以这种方式使用属性函数时,它允许SetGet属性设置并获取值本身而不破坏原有代码(相当于调用函数,未修改原值)。
使用属性装饰器来重写这段代码,看看是否能得到一个允许设置的属性值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | from decimal import Decimal ######################################################################## class Fees ( object ) : """""" #---------------------------------------------------------------------- def __init__ ( self ) : """Constructor""" self . _fee = None #---------------------------------------------------------------------- @ property def fee ( self ) : """ The fee property - the getter """ return self . _fee #---------------------------------------------------------------------- @ fee . setter def fee ( self , value ) : """ The setter of the fee property """ if isinstance ( value , str ) : self . _fee = Decimal ( value ) elif isinstance ( value , Decimal ) : self . _fee = value #---------------------------------------------------------------------- if __name__ == "__main__" : f = Fees ( ) |
上面的代码演示了如何为fee属性创建一个setter方法。可以用一个名为@fee.setter的装饰器装饰第二个方法名也为fee的方法来实现这个。如下,setter被调用:
1 2 | >>> f = Fees ( ) >>> f . fee = "1" |
属性函数的说明,它有fget, fset, fdel和doc几个参数。如果对属性使用del命令,可以使用@fee.deleter创建另一个装饰器来装饰相同名字的函数从而实现删除的同样效果。
http://python.jobbole.com/80955/