python面向对象OOP入门

 一、面向对象简介

面向对象编程不是python独有,几乎所有高级语言都支持;面向对象不管在那个语言中都有三大特性:即:封装、继承、多态;具体的本文主要讲python面向对象--类及三大特性的具体实现;

二、面向对象之python类特性一:封装

python通过类实现面向对象的编程;编程大致分为面向过程式的函数式编程,和面向对象编程;

类(Class)和实例(Instance)是面向对象最重要的概念。

1、类的简单定义与使用

class ‘类名‘:
    语句块

如:

class Foo:
    def bar(self):
        print("Foo.bar")
        
        
obj = Foo()   #obj即是Foo类的实例
obj.bar()     #通过实例去调用调用Foo类中的方法

结果输出Foo.bar

以上就是最简单的类定义与使用;

2、self是什么?

我们注意到以上的示例中除了class关键字用来定义类,def定义方法(类中的函数我们称方法,可以理解为类中封装的函数就是方法)后面有一个self参数,那么 这个self参数是什么?先来一个例子:

class Foo:
    def bar(self,arg):
         print(self,arg)
         
z1 = Foo()
print(z1)
z1.bar(11)

输出结果:

以上结果可以看到z1是Foo实例打印出内存地址和self的内存地址一样,这说明self就代指实例本身;

因此self就是类实例化出来的对象(实例 ),通俗的讲,就是那个实例对象调用,就代指那个实例对象

3、实例出对象

实例对象是从类实例化而来obj = 类名([参数....]),拥有自己的作用域命名空间,就是拥有自己的内存地址空间;同时可以对实例对象添加赋值;用于保存实例自己的数据;同时可以调用类中封装好的方法或数据;

class Foo:
    def bar(self,arg):
        print(self.name,self.age,arg)

obj = Foo()      #实例化obj对象
obj.name = "san"   #向实例中添加对象name并赋值
obj.age = 18        #向实例中添加对象age并赋值
obj.bar(666)        #调用类方法并传入参数6666

输出结果:

(‘san‘, ‘18‘, 666)

从上面的示例可以看出类在定义时并没有创建name 和age ;obj实例对象创建后通过赋值

让obj拥有了name和age;因此实例obj在调用类中bar方法时可以获取自身命名空间中name

和age值;实际上实例化后的对象如果没有做出限制(__slots__),可以向对象中保存添加任意多的值;

4、通过__slots__限制姨实例对象添加赋值

通过以上示例我们了解到,在从类实例化对象后,可以往对象中添加任意多的值,只要内存足够大;然而任何无节制的增加,都有可能带来隐患,所以我们通过__slots__功能来限制实例对象的赋值;

class Foo:
    __slots__ = ("name","age")    #只允许往实例赋name,age
    def bar(self,arg):
        print(self.name,self.age,arg)
    def Other(self):      
        print(self.other)
  
z = Foo()          #实例化z
z.name = "san"     #向z对象赋值name
z.age = 18         #向z对象赋值age
z.bar("6666")
z.other = "othter"   #向z对象赋值other
z.Other()

运行结果如图:

这次没有赋值成功,被限制了提示:“AttributeError: ‘Foo‘ object has no attribute ‘other‘“;这正是我们所要的。

5、构造函数__init__

对于以上的示例我们往实例化后的对象中赋值也可以限制能赋的值,如果要实例化出多个类对象,每个类对象有共同的属性值,如name,age,sex等,那么我们可以通过构造函数__init__方法来实现,即在实例化创建对象时传入name,age,来达到类似obj.name ="san" obj.age = 18这样的效果:

class Foo:
    def __init__(self,name,age):   #构造方法,这里有几个参数,实例化对象时就要传递对应的参数
        self.name = name
        self.age = age
        print("__init__ is start.")   #对象实例化时自动执行
    def foo(self,arg):
        print(self.name,self.age,arg)
        
obj = Foo("san",18)
obj.bar("good")

运行结果如图:

从运行结果中可以看出 只要实例化出对象obj = Foo(["参数...."])时就执行__init__方法中的内容;利用这个功能,我们给各实例传入name,age参数时自动赋值;这就是构造方法的功能;其中参数可选,有无参数在于你设计类时是否需要。

三、类特性二:继承

继承民是面向对象的特性之一,即子类(又叫派生类)继承父类(又叫基类或超类)的特性(属性,方法等);同时子类可以重写父类中的方法或属性。说到继承这时提一嘴,python2.x和python3.x继承有点区别,python2.x是经典类,通过class 类名(object)变成新式类,python3.x默认是新式类;新式类和经典类的区别在于,多继承时,继承顺序不一样;经典类采用”深度优先“方式 查找;而新式类则是广度优先去查找;这里就不详述,以下的示例在python 2.7中所以你会看到类名后有一个object,python3.x下可以不用object。关于深度优先和广度优先这里先不详述,下面有示例:

1、简单继承

示例:

class F(object):           #父类F
    def f1(self):
            print("F.f1")
    def f2(self):        
            print("F.f2")
class S(F):                #子类S
    def s1(self):
            print("s.s1")
            
son = S()    #从S类实例化对象son
son.s1()     #调用S类的s1方法
son.f1()     #由于在S类中没有找到f2,所以到父类F中找到f1

运行结果如图:

说明:虽然S类中没有f2方法,但由于S类继承了F类,而F类中有f1方法,因此可以调用F中的f1方法。

2、重写

有时候我们在继承了父类后,父类中的方法可能并不能满足需求,直接修改父类中的方法又破坏了原类,可能影响到其他引用,此时可以通过在子类中定义一个父类中同名的方法,就可以达到重写父类方法的目的。

示例:

class F(object):
    def f1(self):
        print("F.f1")
    def f2(self):
        print("F.f2")
class S(F):
    def s1(self):
        print("s.s1")
    def f2(self):  # 不继承,重写
        print("S.f2")
son = S()
son.s1()  #S类的s1方法
son.f1()  #继承F类的f1方法
son.f2()  #S自己的f2方法,重写(覆盖)F类的f2方法

运行结果:

3、子类中调用超类方法

虽然上面的例子中重写了父类中的同名方法,满足了需求,但能否在重写的基础上,引用超类中的方法呢?即先运行超类中的同名方法,再定义自己的同名方法?答案是必须可以啊!

这里有两种方法,一起列举,现实中只用其中的一种,建议使用super:

class F(object):
    def f1(self):
        print("F.f1")
    def f2(self):
        print("F.f2")
class S(F):
    def s1(self):
        print("s.s1")
    def f2(self):  # 不继承,重写
        print("S.f2")
        super(S,self).f2()    #调用父类f2方法一: super(子类,self).父类中的方法(...)
        F.f2(self)            #调用父类f2方法二:父类.方法(self,....)
        
son = S()
son.s1()  #S类的s1方法
son.f1()  #继承F类的f1方法
son.f2()  #S自己的f2方法,重写(覆盖)F类的f2方法

运行结果:

由于S类中的f2方法除了输出自己的功能S.f2外还通过两种调用父类F中的f2方法,所以输出了两次F.f2;

注意这里为了演示只调用了父类中的f2方法,达到继承和重写优化父类中的f2方法,也可以通过这两种方法中的一种调用父类中的其他方法;

4、类多继承

类可以继承多个类,即在class 类名(父类1,父类2,...)那么问题来,如果所继承的类都有一个同名的方法,那调用时如何选择?上面提到了经典类是深度优先,新式类时广度优先,本文不做深度优先和广度优先查找比较,只讲新式类的广度优先;有兴趣的可以自行查找资料。

示例:

class Base(object):
    def a(self):
        print("Base.a")
class F1(Base):
    def a1(self):
        print(‘F1.a‘)
    def a11(self):
        print("F1.a11")
        
class F2(Base):
    def a2(self):
        print(‘F2.a‘)
    def a11(self):
        print("F2.a11")
class S(F1,F2):
    pass
class S2(F2,F1):
    pass
obj = S()
obj.a11()
obj2 = S2()
obj2.a11()

运行结果:

obj继承顺序是F1,F2   结果是F1.a11

obj2继承顺序是F2,F1 结果是F2.all

5、有交集的多继承查找

obj对象从A类实例化而来,A类继承了B和C类,B类继承D,C类也继承D类;baba方法在C类和D类中都有,此时obj.baba()方法结果是怎样?

示例:

class D:
    def bar(self):
        print(‘D.bar‘)
    def baba(self):
        print("D.baba")
class C(D):
    def bar(self):
        print(‘C.bar‘)
    def baba(self):
        print("C.baba")
class B(D):
    def bar(self):
        print(‘B.bar‘)
class A(B, C):
    def bar(self):
        print(‘A.bar‘)

obj = A()
obj.bar()
obj.baba()

运行结果:

# 执行bar和baba方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

同样的例子我们调回python2.7作为经典类执行,看结果。

执行bar和baba方法时
首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
 所以,查找顺序:A --> B --> D --> C
 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

这里的baba方法在D中找到,所以显示为D.baba

深度优先和广度优先查找顺序如图:

6、多继承之__init__执行顺序

以下是一个模拟实践中多继承情况下__init__构造方法的执行,有利于我们阅读项目源码。

示例:

class BaseRequest:    #(3)
   def __init__(self):
       print("BaseRequest.init")
class RequestHandler(BaseRequest):  #(2)
    def __init__(self):
        print("RequestHandler.init")
        BaseRequest.__init__(self)   #调用父类的__init__方法
    #     super(RequestHandler,self).__init__()

    def serve_forever(self):     #(5)
        print("RequestHandler.serve_forever")
        self.process_request()

    def process_request(self):
        print(‘RequestHandler.process_request‘)
class Minx:
    def process_request(self):   #(6)
        print("Minx.process_request")

class son(Minx,RequestHandler):
    pass

obj = son()     #(1)
obj.serve_forever()    #(4)

以上的注释后的数字是执行的流程。obj = son()的作用:

实例化出obj对象;

执行__init__构造方法,在多继承环境 下,和上面讲的调用其他类方面查找一致,首先查找 son类中的__init__如果没有按新式类的方度优先顺序查找所继承类中的__init__,这里首先找到Minx,没有,再找到RequestHandler类,执行打印“RequestHandler.init”,里的__init__再次执行了父类中的__init__方法,因此又打印出"BaseRequest.init";

执行obj.serve_forever()时,同样的查找,打印出“RequestHandler.serve_forever”,注意这里又调用 了self.process_request()方法,由于self指的就是所调用的对象obj即obj.process_request()方法,因此重新从son(Minx,RequestHandler)中按顺序查找,而不是RequestHandler类下的 process_reques方法。因此找到Minx下的process_request方法,得到结果:“Minx.process_request”


执行结果如下:


四、python面向对像之多态

多态简单的理解就是同一个方法在不现的对象调用时显示出的效果不一样,如+ 在整形数字相加时是数学运算,在字符串相加时加是连接符;

python的面向对象原生支持多态,不像java等强类型语言,传递参数时必须指定类型,而python没有此此限制,这也是python原生动支持多态的原因之一。

本文主要说明了python面向对象的三大特性,封装,继承及多态,继承有多继承,新式继承与经典类继承的区别。个人总结,如有不当之处欢迎指正。

时间: 2024-11-13 08:17:37

python面向对象OOP入门的相关文章

python 面向对象oop

1 oop 对象世界观  -- oop是目前人类认知最接近实际生活的语言 一切事务皆对象 对象有运动规律和内部状态 对象之间可以相互调用 2.面向对象 唯一性:对象具有唯一性,不存在两个相同的对象,除非他们是同一个对象 可以分类性 : 对象可以分类 3.oop 分类 封装 继承 多态 具体类: 结构 classs 类名: 类体 创建对象使用类名(__init__ 函数除第一个参数外的参数列表) 创建对象的时候 实际执行了 __init__函数, __init__ 并不会创建对象,但会初始化对象

Python面向对象OOP

一 OOP     与C++和Java一样,Python同样具有OOP设计. 过程式:从前到后,一条一条,机器能接受的顺序性方式:方式大概为"首先你应该做什么,第二应该做什么,高级点的做点假设如果遇到什么情况要做什么,或者一件事情要做多少多少遍,- -," OOP式:从"类与对象"方式来抽象和理解世界.例如首先物体(Object)大概可以分为"生物"与"非生物","生物"又能分为"人.动物.植物&

C#面向对象(OOP)入门—第二天—多态和继承(继承)

介绍: 第一天的内容主要是不同情形下的方法重载.这一部分则主要讲面向对象中继承的概念.首先用一个要点图形来定义继承. 继承 一个简单的例子: ClassA: class ClassA:ClassB { public void Display1() { Console.WriteLine("ClassA Display1"); base.Display1(); } } ClassB: class ClassB { public int x = 100; public void Displ

python面向对象编程入门

一.定义一个只包含一个成员变量a.一个构造函数.一个get.一个set函数的类 ? 1 2 3 class ClassA(object):     def __init__(self):         self._a = 0<br> def get_a(self):<br> return self._a<br> def set_a(self, value):<br> self._a = value 可以看到

python面向对象之类成员

一.概述 上篇<python面向对象OOP>介绍了python面向对象的基础初级入门部分,提到了类的定义,使用,类的三大特性;经典类,新式类在查找时的区别等,有了前面的基础,本文接着描述面向对象中类成员;先整体描述下,类中的成员分以下几部分: #类成员  #字段(属性):      普通字段  属于对象,保存在对象中,只能通过对象访问      静态字段  属于类,保存(一份)在类中(所有对象共享的字段属性),执行时可以是类访问也可以是对象访问  #方法:      普通方法  保存在类中,又

PHP面向对象(OOP)编程入门教程

面向对象编程(OOP)是我们编程的一项基本技能,PHP5对OOP提供了良好的支持.如何使用OOP的思想来进行PHP的高级编程,对于提高 PHP编程能力和规划好Web开发构架都是非常有意义的.下面我们就通过实例来说明使用PHP的OOP进行编程的实际意义和应用方法. 我们通常在做一个有数据库后台的网站的时候,都会考虑到程序需要适用于不同的应用环境.和其他编程语言有所不同的是,在PHP中,操作数据库的 是一系列的具体功能函数(如果你不使用ODBC接口的话).这样做虽然效率很高,但是封装却不够.如果有一

python面向对象编程(OOP)

python作为一种解释性语言,其主要的编程方式就是面向对象,而且python的框架django也是主要面向对象的编程. 类(class)和对象(object) 类(class)是用来描述具有相同属性(attribute)和方法(method)对象的集合.对象(object)是类(class)的实例.比如学生都有名字和分数,他们有着共同的属性.这时我们就可以设计一个学生类,用来记录学生的名字和分数,并自定义打印出来. 属性(attribute):类里面用于描述所有对象共同特征的变量或数据.比如此

PHP面向对象(OOP)编程入门教程链接

PHP官方学习OOP: http://php.net/manual/zh/oop5.intro.php 以下链接来源: http://blog.snsgou.com/post-41.html PHP面向对象(OOP)编程完全教程:1.什么是面向对象? PHP面向对象(OOP)编程完全教程:2.什么是类,什么是对象,类和对象这间的关系 PHP面向对象(OOP)编程完全教程:3.什么是面向对象编程呢? PHP面向对象(OOP)编程完全教程:4.如何抽象出一个类? PHP面向对象(OOP)编程完全教程

python面向对象笔记

Python之路,Day6 - 面向对象学习 本节内容: 面向对象编程介绍 为什么要用面向对象进行开发? 面向对象的特性:封装.继承.多态 类.方法. 引子 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战>的游戏,你就思考呀,人狗作战,那至少需要2个角色,一个是人, 一个是狗,且人和狗都有不同的技能,比如人拿棍打狗, 狗可以咬人,怎么描述这种不同的角色和他们的功能呢? 你搜罗了自己掌握的所有技能,写出了下面的代码来描述这两个角色 + 上面两个方法相当于造了两个模子,游戏开始,