一、面向对象
面向对象程序设计(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__之前创建对象 |
转载于:https://blog.51cto.com/yinsuifeng/1912543