Python 面向对象
一、面向对象技术简介
- 类(Class): 用来描述具有相同的属性(变量)和方法(函数)的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 实例变量:定义在方法中的变量,只作用于当前实例的类。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟”是一个(is-a)”关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
对于类、对象、实例三者之间的联系:类—>对象—>实例
- 对象 、实例两者之间的概念非常模糊,大多数理解为对象就是实例,但是对象似乎是一个抽象的群体名,而实例是群体中实实在在的个体。
- 实例对象:相当于赋值,将实例赋给对象
- 实例化:具体到个体。
http://www.blogjava.net/dreamstone/archive/2007/03/04/101733.aspx
二、创建类
1、类定义
使用 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-8
class 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.b
Myclass.a=6
print Myclass.a
#创建实例对象
#实例化
x=Myclass(1,8,7)
print x.a
print x.fun()
print x.i
print x.c
#访问的还是函数外部的a(即类变量)
print Myclass.a
实例变量与类变量(属性):
1. 访问权限
类变量通过类名点操作访问也可以通过实例点操作访问className.varobjectName.var
实例变量只可以通过实例名点操作访问objectName.var
2. 类变量修改后的表现
通过className.var修改类变量,该类和所有实例所共享的数据将被修改,再次通过类或实例访问得到的将是新的数据。
通过objectName.var修改类变量,其效果将仅仅作用在该实例上,再次通过类或其它实例访问得到的仍然是旧的数据。但这一修改方式将对该类变量实例化,其结果是该实例将得到一个单独的该变量拷贝,此后此对象不再与类共享该名称的变量
3、创建实例对象
实例化类其他编程语言中一般用关键字 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=10
print Myobj1.d
#删除属性
del Myobj1.d
也可以使用以下函数的方式来访问属性:
- getattr(obj, name[, default]) : 访问对象的属性。
- hasattr(obj,name) : 检查是否存在一个属性。
- setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
delattr(obj, name) : 删除属性。
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’)
Python内置类属性
- __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
- __doc__ :类的文档字符串
- __name__: 类名
- __module__: 类定义所在的模块(类的全名是’__main__.className’,如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
__bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
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
print “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 使用了引用计数这一简单技术来跟踪和回收垃圾。
在 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中继承中的一些特点:
- 1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
- 2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别在于类中调用普通函数时并不需要带上self参数
- 3: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()
Obj1=Myclass1()
Obj1.func()
#
单下划线、双下划线、头尾双下划线说明:
- __foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的。
- _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
- __foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。
八、属性函数(property)
Python中有一个被称为属性函数(property)的小概念(即可将函数变成属性一样进行操作)。
作用:
- 将类方法转换为只读属性
- 重新实现一个属性的setter和getter方法
使用属性函数的最简单的方法之一是将它作为一个方法的装饰器来使用。这可以让你将一个类方法转变成一个类属性。
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=val2
obj=Myclass(6,8)
print obj.getVal()
obj.set(2,1)
print obj.getVal()
但也可使用Python property取代set和get方法
如果你想添加可以使用正常点符号访问的属性,而不破坏所有依赖于这段代码的应用程序,你可以通过添加一个属性函数非常简单地改变它:
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属性设置并获取值本身而不破坏原有代码(相当于调用函数,未修改原值)。
使用属性装饰器来重写这段代码,看看是否能得到一个允许设置的属性值。
Python
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被调用:
Python
1 2 | >>> f = Fees ( ) >>> f . fee = “1” |
属性函数的说明,它有fget, fset, fdel和doc几个参数。如果对属性使用del命令,可以使用@fee.deleter创建另一个装饰器来装饰相同名字的函数从而实现删除的同样效果。
参考:
http://www.runoob.com/python/python-object.html
http://python.jobbole.com/80955/
还没有评论,来说两句吧...