Python面向对象编程

简介:

 面向对象程序设计(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,如需转载请自行联系原作者

相关文章
|
2月前
|
Python
你真的会面向对象吗!解密Python“魔术方法”
你真的会面向对象吗!解密Python“魔术方法”
25 0
|
4月前
|
Python
Python进阶第一篇(Python的面向对象)
Python进阶第一篇(Python的面向对象)
|
6天前
|
前端开发 Python
Python编程的面向对象(二)—类的多态
Python编程的面向对象(二)—类的多态
13 7
|
5天前
|
IDE Java 开发工具
Python类与面向对象
Python类与面向对象
|
6天前
|
存储 Java 程序员
30天拿下Python之面向对象编程
30天拿下Python之面向对象编程
|
15天前
|
Java Python
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
【9月更文挑战第18天】在 Python 中,虽无明确的 `interface` 关键字,但可通过约定实现类似功能。接口主要规定了需实现的方法,不提供具体实现。抽象基类(ABC)则通过 `@abstractmethod` 装饰器定义抽象方法,子类必须实现这些方法。使用抽象基类可使继承结构更清晰、规范,并确保子类遵循指定的方法实现。然而,其使用应根据实际需求决定,避免过度设计导致代码复杂。
|
18天前
|
Python
全网最适合入门的面向对象编程教程:Python函数方法与接口-函数与方法的区别和lamda匿名函数
【9月更文挑战第15天】在 Python 中,函数与方法有所区别:函数是独立的代码块,可通过函数名直接调用,不依赖特定类或对象;方法则是与类或对象关联的函数,通常在类内部定义并通过对象调用。Lambda 函数是一种简洁的匿名函数定义方式,常用于简单的操作或作为其他函数的参数。根据需求,可选择使用函数、方法或 lambda 函数来实现代码逻辑。
|
2月前
|
Python
Python 中的面向对象编程 (OOP)
【8月更文挑战第29天】
25 7
|
2月前
|
机器学习/深度学习 PHP 开发者
探索PHP中的面向对象编程构建你的首个机器学习模型:以Python和scikit-learn为例
【8月更文挑战第30天】在PHP的世界中,面向对象编程(OOP)是一块基石,它让代码更加模块化、易于管理和维护。本文将深入探讨PHP中面向对象的魔法,从类和对象的定义开始,到继承、多态性、封装等核心概念,再到实战中如何应用这些理念来构建更健壮的应用。我们将通过示例代码,一起见证PHP中OOP的魔力,并理解其背后的设计哲学。
|
2月前
|
Python
下一篇
无影云桌面