面向对象程序设计(Object-oriented programming,OOP)是一种程序设计范式,也是一种程序开发方
法。对象指的是类的实例,类是创建对象的模板,一个类可以创建很多个对象,每个对象都是类类型
的一个变量;创建对象的过程也叫做类的实例化。编程方法主要可以分为两类:面向过程与面向对
象,他们的主要区别在于:
面向过程编程:以指令为核心,围绕“正在发生什么”进行编写,程序具有一系列线性步骤,主体思想是代码作用于数据。 面相对象编程(OOP):以数据为核心,围绕“将影响谁”进行编写,围绕数据及为数据严格定义的接口来组织程序, 用数据控制对代码的方向。 |
面向对象编程种主要有以下几个主要概念:
类:定义了被多个同一类型对象共享的结构和行为(数据和代码)。 对象:类的实例。既包含数据(变量,也称属性),也包含代码(函数,也称方法)。 封装:隐藏实现方案细节;将代码及处理的数据绑定在一起的一种编程机制,用于保证程序和数据不受外部干扰且不会被误用。 |
二、类的创建
-
使用class关键字创建类
超类是一个或多个用于继承的父类的集合类体中可以包含:声明语句、类成员定义、数据属性、方法。
Class ClassName(bases): #不存在继承关系时,可以不提供bases 'class documentation string' #类文档可选 Data = value #定义数据属性 def method(self , ...) #定义方法属性 self.member = value class MyClass(): """A simple example class""" i = 12345 def f(self): return 'hello world'
-
类方法及调用
实例(对象)通常包含属性和方法。
数据属性:即变量 可调用的方法:object.method(),即函数
在OOP中,实例就像是带有”数据”的记录,而类是处理这些记录的”程序”。通过实例调用方法相
当于调用所属类的方法来处理当前实例,类似obj.method(arg...)自动转为class.method(instance,
args...);因此在类中每个方法必须具有 self 参数,它隐含当前实例之意;在方法内对self属性做
赋值运算会产生每个实例的属性;没有实例,方法就不允许调用。
In [1]: class MyClass(): ...: """A simple example class""" ...: i = 12345 ...: def f(self): ...: return 'hello world' ...: In [2]: x=MyClass() #实例化一个类 In [3]: x.f() #调用类的方法 Out[3]: 'hello world' In [4]: x.i Out[4]: 12345 In [5]: x.i=23456 #修改成员变量 In [6]: x.i Out[6]: 23456
-
构造函数与析构函数
构造函数:创建实例时,python 会自动调用类中的__init__方法,以隐性的为实例提供属性
__init__方法被称为构造器,如果类中没有定义__init__方法,实例创建之初仅是一个简单的名称空间。构造函数不能有返回值。
In [8]: class Myclass(object): ...: message='Hello,Developer' ...: def show(self): ...: print(self.message) ...: In [9]: class Myclass(object): ...: message='Hello,Developer' ...: def show(self): ...: print(self.message) ...: def __init__(self): #构造函数 ...: print('Constructor is called') ...: In [10]: inst=Myclass() #当Myclass类实例化时,自动执行了构造函数 Constructor is called In [11]: inst.show() Hello,Developer
析构函数:__del__方法被称为析构函数,在销毁(释放)对象时将调用它们。析构函数往往用来
做"清理善后"工作,如数据库链接对象可以在析构函数中释放对数据库资源的占用。
In [17]: class Myclass1(object): ...: message='Hello,Developer' ...: def show(self): ...: print(self.message) ...: def __init__(self): ...: print('Constructor is called') ...: def __del__(self): ...: print('Destructor is called!') ...: In [18]: inst1=Myclass1() #实例化类 Constructor is called In [19]: inst1.show() Hello,Developer In [20]: del inst1 #析构函数 Destructor is called!
类的特殊属性:可以使用类的__dict__字典属性或内置的 dir()函数来获取类的属性。
In [27]: dir(Myclass1) #查看类所拥有的属性和方法 Out[27]: ['__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'message', 'show']
-
实例属性(成员变量)
实例仅拥有数据属性(方法是类属性),通常通过构造器”__init__”为实例提供属性;这些数据属
性独立于其他实例或者类;实例释放时,其属性也将被清除。内建函数 dir()或者实例的特殊属性
__dict__可用于查看实例属性。
In [31]: class Myclass2(object): ...: message='Hello,Developer' #类成员属性 ...: def show(self): ...: print(self.message) #实例成员变量 ...: print('Here is %s in %s' %(self.name,self.color)) ...: def __init__(self,name='unset',color='black'): ...: print('Constructor is called with parms:',name,'',color) ...: self.name=name ...: self.color=color ...: In [32]: Myclass2.message #输出类变量 Out[32]: 'Hello,Developer' In [33]: Myclass2.message='Hello Python' #更改类成员变量 In [34]: Myclass2.message Out[34]: 'Hello Python' In [35]: init3=Myclass2() #实例化类Myclass2 Constructor is called with parms: unset black In [36]: init3.message #访问类成员变量 Out[36]: 'Hello Python' In [37]: init3.message='Hello' #更改类成员变量 In [39]: Myclass2.message #可以发现,实例对象无法更改类成员对象 Out[39]: 'Hello Python'
-
类方法中的可用变量
实例变量:指定变量名称及示例自身进行引用;self.变量名 |
-
类成员的修饰符
公有成员,在任何地方都能访问
私有成员,只有在类的内部才能方法
class C: classname = '公有变量' #类的公有字段,即变量 __classfoo = "私有变量" #类的私有字段,使用__开头声明的变量为私有变量 def __init__(self): self.name = '公有变量' #对象的公有字段,即变量 self.__foo = "私有变量" #对象的私有字段,使用__开头声明的变量为私有变量
静态字段(属于类)
公有静态变量:类可以访问;类内部可以访问;派生类中可以访问
私有静态变量:仅类内部可以访问
普通字段(属于对象)
公有普通变量:对象可以访问;类内部可以访问;派生类中可以访问
私有普通变量:仅类内部可以访问
In [42]: class Myclass2(object): ...: message='Hello,Developer' #类成员 ...: __classname='Python' ...: def show(self): ...: print(self.message) ...: print('Here is %s in %s' %(self.name,self.color)) ...: def __init__(self,name='unset',color='black'): ...: print('Constructor is called with parms:',name,'',color) ...: self.name=name ...: self.__color=color In [43]: inst4=Myclass2() #实例化类 Constructor is called with parms: unset black In [44]: inst4.message #实例化的对象可以访问类的公有变量 Out[44]: 'Hello,Developer' In [45]: inst4.__classname #实例化的对象无法访问类的私有变量 -------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-45-379f39c829cf> in <module>() ----> 1 inst4.__classname In [47]: inst4.name #实例对象可以访问对象公有变量 Out[47]: 'unset' In [48]: inst4.__color #实例对象无法外部访问对象私有变量 -------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-48-5db61d225aac> in <module>() ----> 1 inst4.__color AttributeError: 'Myclass2' object has no attribute '__color'
o 静态函数和类函数
Python中支持两种基于类名访问成员的函数:静态函数和类函数,它们的不同点是类函数有一个隐
性参数cls可以用来获取信息,而静态函数没有该参数。静态函数使用装饰器@staticmethod定义,类
函数使用装饰器@classmethod定义。
class Myclass(object): message='Hello,Developer' def show(self): print('self.message') print('Here is %s in %s !' %(self.name,self.color)) @staticmethod #定义静态函数,可以访问类成员变量 def printMessage(): print('print Message is called ') print(Myclass.message) @classmethod #定义类函数,第一个参数必须是cls def creatobj(cls,name,color): print('Object will be created: %s(%s,%s)' %(cls.__name__,name,color)) return cls(name,color) def __init__(self,name='unset',color='black'): print('Constructor is called with params:',name,'',color) self.anme=name self.color=color def __def__(self): print('Destructor is called for %s' %self.name) Myclass.printMessage() #直接调用静态函数 inst=Myclass.creatobj('Toby', 'Red') print(inst.message) 输出结果: print Message is called #静态函数输出结果 Hello,Developer Object will be created: Myclass(Toby,Red) #类函数输出结果 Constructor is called with params: Toby Red #构造函数 Hello,Developer #print输出
三、继承与多态
类之间的继承是面向对象的设计的重要方法,通过继承可以达到简化代码和优化设计模式的目的。
Python类在定义时可以在小括号中指定基类。所有Pyhon类都是object类型的子类。
class BaseClass(object) #父类定义 block_class class SubClass(BaseClass) #子类定义 block_class
-
新式类与经典类
在Python中存在两种类,经典类与新式类,它们的区别在于:
1)写法不一样
class A: #经典类 pass class B(object): #新式类 pass
Python 2.x中默认都是经典类,只有显式继承了object才是新式类 Python 3.x中默认都是新式类,不必显式的继承object 2)在多继承中,继承搜索的顺序发生了改变,经典类多继承属性搜索顺序: 先深入继承树左侧,再 返回,开始找右侧;新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动 3)新式类更符合OOP编程思想,统一了python中的类型机制。
新式类对象可以直接通过__class__属性获取自身类型:type 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中 新式类增加了__getattribute__方法 |
class BaseA(object): def move(self): print('move called in BaseA') class BaseB(object): def move(self): print('move called in BaseB') class BaseC(BaseA): def move(self): print('move called in BaseC') class Sub(BaseC,BaseB): def move(self): print('move called in Sub') inst=Sub() inst.move()
在此新式类的多重继承当中,当子类继承了多了父类并且调用共有的方法时,Python解释器会选择最近的一个基类成员方法。上面的例子move()搜索顺序为Sub、BaseC、BaseA、BaseB。
-
类与实例的内建函数
issubclass() | 布尔函数,判断一个类是否由另一个类派生。issubclass(sub,sup) |
isinstance() | 布尔函数,判断一个对象是否是给定类的实例。isinstance(obj1,class_obj2) |
hasattr() | 布尔函数,判断一个对象是否拥有指定的属性,hasattr(obj , ‘attr’) 同类的函数还有 getattr()、setattr()、delattr() |
super() | 在子类中找出其父类以便于调用其属性;一般情况下仅能采用非绑定方式调用祖先方法;super()可用于传入实例或类型对象,super(type[,obj ]) |
In [1]: class Person(): ...: def __init__(self,name): ...: self.name=name ...: In [2]: class EmailPerson(Person): ...: def __init__(self,name,email): ...: super.__init__(name) ...: self.email=email
上例中,子类EmailPerson通过super()方法获取了父类Person的定义,子类的__init__()调用了
Person.__init__()方法。它会自动将self参数传递给父类。这样不仅可以继承父类中的定义方法,还
可以创建子类独有的属性。
-
运算符重载
在方法中拦截内置的操作——当类的实例出现在内置函数中,Python 会自动调用自定义的方法,并
且返回自定义方法的操作结果。运算符重载让类拦截常规的 Pyhton 运算:类可以重载所有表达式
运算符;类也可以重载打印、函数调用、属性点运算等内置操作;载使类实例的行为项内置类型,重
载通过提供特殊名称的类方法实现。
-
特殊方法制定类
除了__init__和__del__之外,Python 类支持许多特殊方法,特殊方法都是以双下划线开头和结尾, 有些特殊方法有默认行为,没有默认行为的是为了留到需要的时候再实现.这些特殊的方法是python
中用来扩充类的强大工具, 他们可以实现: 模拟标准类型,重载操作符特殊方法允许类通过重载标
准操作符+,*甚至包括下标及映射操作[]来模拟标准类型.
方法 | 重载 | 调用 |
__init__ | 构造函数 | 对象建立:x=class(args) |
__del__ | 析构函数 | x对象对象 |
__add__ | 运算符+ | 如果没有_iadd_,x+y,x+=y |
__or__ | 运算符:(位OR) | 如果没有_ior_,x|y,x|=y |
__repr__,__str__ | 打印,转换 | print(x),repr(x),str(x) |
__call__ | 函数调用 | x(*args,**kargs) |
__getattr__ | 点运算符 | x.undefined |
__setattr__ | 属性赋值语句 | x.any=value |
__delattr__ | 属性删除 | del x.any |
__getattribute__ |
属性获取 | x.any |
__getitem__ |
索引运算 | x[key],x[i:j],没有__iter__时的for循环 |
__setitem__ |
索引赋值运算 | x[key]=value,x[i:j]=sequence |
__delitem__ |
索引和切片删除 | del x[key],del[i:j] |
__len__ |
长度 | len(x),如果没有__bool__真值测试 |
__bool__ |
布尔测试 | bool(x),真测试 |
__lt,__gt__ |
特定的比较 | x<y,x>y,x<=y,x>=y,x==y,x!=y |
__le__,__ge__ |
||
__eq__,__ne__ |
||
__radd__ | 右侧加法 | other+x |
__iadd__ |
实地(增强的)加法 | x+=y |
__iter__,__next__ |
迭代环境 | I=iter(x),next(I) |
__contains__ |
成员关系测试 | item in x |
__index__ |
整数值 | hex(x),bin(x),oct(x),o[x] |
__enter__,__exit__ |
上下文管理器 | with obj as var: |
__get__,__set__ |
描述运算符 | x.attr,x.attr=value,del x.attr |
__delete__ |
删除 | 在__del__之后删除对象 |
__new__ |
创建 | 在__init__之前创建对象 |
本文转自 梦想成大牛 51CTO博客,原文链接:http://blog.51cto.com/yinsuifeng/1912543,如需转载请自行联系原作者