• day20-面向对象编程、继承


    一、面向对象编程

    1、简介
      面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
    面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。
      而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
      在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。

    2、类的构成
    类Class由3部分构成
    类的名称:类名
    类的属性:一组数据
    类的方法:允许对类进行操作的方法(行为)

    类里面的变量可以叫做静态属性、静态变量、静态字段
    类里面的函数一般叫做方法

    3、定义类
    定义一个类,格式如下:
    class 类名:
      静态属性
      动态方法


    4、举例:

    class Person:   #定义一个人类
        role = 'person'  #人的角色属性都是人
        def walk(self):  #人都可以走路,也就是有一个走路方法
            print("person is walking...")
    
    print(Person.role)  #查看人的role属性
    print(Person.walk)  #引用人的走路方法,注意,这里不是在调用

    5、__init__方法
      由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name,score等属性绑上去:

    class Student:
        def __init__(self, name, score):
            self.name = name
            self.score = score

    注意:特殊方法“init”前后有两个下划线!!!
    注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
    有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去。

    6、实例化对象
    类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征

    实例化对象的过程:
    1)在内存中创建了一个内存空间,存储类
    2)在这个类内存空间中创建静态变量和特殊方法__init__的内存地址,和动态方法的内存地址
    3)在内存中创建了一个内存空间,存储这个变量

    一般情况下:
    类中的静态属性通过类名去调用或修改
    类中的动态方法通过对象去调用执行

    class 类名:
        def __init__(self,参数1,参数2):
            self.对象的属性1 = 参数1
            self.对象的属性2 = 参数2
    
        def 方法名(self):pass
        def 方法名2(self):pass

    对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西
             #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
            #括号里传参数,参数不需要传self,其他与init中的形参一一对应
            #结果返回一个对象
    对象名.对象的属性1#查看对象的属性,直接用 对象名.属性名 即可

    对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可

    例子:

    class Person:   #定义一个人类
        role = 'person'  #人的角色属性都是人
        def __init__(self,name):
            self.name = name  # 每一个角色都有自己的昵称;
            
        def walk(self):  #人都可以走路,也就是有一个走路方法
            print("person is walking...")
    
    p1 = Person('Mike')  #实例化人p1
    print(p1.role)  #查看人的role属性
    print(p1.name)  #查看人的name属性
    p1.walk()  #引用人的走路方法

    实例化的过程就是类——>对象的过程

    7、self
    self:在实例化时自动将对象/实例本身传给__init__的第一个参数,你也可以给他起个别的名字,但是约定俗成都这么写。

    8、类属性的补充

    8.1、我们定义的类的属性到底存到哪里了?有两种方式查看
    dir(类名):查出的是一个名字列表
    类名.__dict__:查出的是一个字典,key为属性名,value为属性值

    print(dir(Person))
    #['__class__', '__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__', 'role', 'walk']
    
    print(Person.__dict__)
    #{'__module__': '__main__', 'role': 'person', '__init__': <function Person.__init__ at 0x0054FA98>,
    # 'walk': <function Person.walk at 0x0054FA50>, '__dict__': <attribute '__dict__' of 'Person' objects>,
    #  '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

    8.2、特殊的类属性
    类名.__name__# 类的名字(字符串)
    类名.__doc__# 类的文档字符串
    类名.__base__# 类的第一个父类(在讲继承时会讲)
    类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
    类名.__dict__# 类的字典属性
    类名.__module__# 类定义所在的模块
    类名.__class__# 实例对应的类(仅新式类中)


    9、类名称空间与对象的名称空间
    创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性

    而类有两种属性:静态属性和动态属性

    静态属性就是直接在类中定义的变量
    动态属性就是定义在类中的方法

    其中类的数据属性也叫静态属性是共享给所有对象的,通过id可以看出在内存中的地址是一样的

    print(id(Person.role))
    #31924864
    print(id(p1.role))
    #31924864

    而类的动态属性是绑定到所有对象的,通过引用类的动态方法可以看出方法在内存中的地址是不一样的

    print(Person('Tom').walk)
    #<bound method Person.walk of <__main__.Person object at 0x01E83050>>
    print(p1.walk)
    #<bound method Person.walk of <__main__.Person object at 0x01E72F70>>

    创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
    在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常

    二、面向对象的三大特性:继承,多态,封装

    2.1继承

    继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
    python中类的继承分为:单继承和多继承

    2.2、单继承
    比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印:

    class Animal:
        def run(self):
            print('Animal is running...')

    当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:

    class Dog(Animal):
        pass
    class Cat(Animal):
        pass

    对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。Cat和Dog类似。

    继承有什么好处?最大的好处是子类获得了父类的全部功能。
    由于Animial实现了run()方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了run()方法:

    dog = Dog()
    dog.run()
    
    cat = Cat()
    cat.run()
    
    运行结果如下:
    Animal is running...
    Animal is running...

    继承的第二个好处需要我们对代码做一点改进。你看到了,无论是Dog还是Cat,它们run()的时候,显示的都是Animal is running...,符合逻辑的做法是分别显示Dog is running...和Cat is running...,因此,对Dog和Cat类改进如下:

    class Dog(Animal):
        def run(self):
            print('Dog is running...')
    
    class Cat(Animal):
        def run(self):
            print('Cat is running...')
    
    再次运行,结果如下:
    Dog is running...
    Cat is running...

    在单继承中,如果只想执行父类的属性或方法,那么子类的属性名或方法不能与父类中的属性名或方法名重复,否则只会执行子类中的属性或方法,相当于重写
    如果既想执行子类的方法,又想执行父类中的方法,有2种方法:
    方法1、使用super

    class A:
        def func(self):
            print('in A')
    
    class B(A):
        def func(self):
            super().func()
            print('in B')
    
    b1 = B()
    b1.func()
    结果:
    in A
    in B

    方法2、方法内调用

    class A:
        def func(self):
            print('in A')
    
    class B(A):
        def func(self):
            A.func(self)
            print('in B')
    
    b1 = B()
    b1.func()    
    结果:
    in A
    in B

    2.3、多继承
    继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。比如如下的继承树:

    class Base:
        def test(self):
            print('---Base---')
    
    class A(Base):
        def test(self):
            print('---A---')
        def testA(self):
            print('---A---')
    
    class B(Base):
        def test(self):
            print('---A---')
        def testB(self):
            print('---B---')
    
    class C(A, B):
        pass
    
    c = C()
    c.test()

    类A和类B都继承类Base,类C继承类A和B
    调用类C的test方法时,依次查看的顺序是类A,类B,类Base
    如果定义类C时写成class C(B, A):,则先查看B,再查看A

    print(C.__mro__)  #在Python3中可以查看C类的对象搜索方法时的先后顺序。
    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)

    2.3、查看继承

    >>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    (<class '__main__.ParentClass1'>,)
    >>> SubClass2.__bases__
    (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

    提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

    >>> ParentClass1.__bases__
    (<class 'object'>,)
    >>> ParentClass2.__bases__
    (<class 'object'>,)

    当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态。

    继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。

    2.4、重写
    就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法

    class Cat:
            def sayHello(self):
                    print("halou...")
    class Bosi(Cat):
            def sayhello(self):
                    #调用父类的方法sayHello,在python2和3中都可以用,在参数中需要加self
                     Cat.sayHello(self)
                     #调用父类的方法sayHello,在python3中可以用,参数不需要加self,2种方法都可以
                     #super().sayHello()
                     print("hello...")
    bosi = Bosi()
    bosi.sayhello()
    
    halou...
    hello...

    2.5、私有属性不会被继承,公有属性会被继承

    私有属性和私有方法只有在同一个类内部才能够继承,在外部不能继承

    class 类1:
        def 方法1(self):
            self.属性1
            self.__属性2
        def __方法2(self):
            self.方法1() #在相同类中的不同方法中,属性1可以继承,属性2也可以继承
        def 方法3(self):
            self.方法1() #因为是在同一个类中,所以方法1可以继承,包括公有方法1中的公有属性1和私有属性2
            self.__方法2() #因为是在同一个类中,方法2可以继承
    
    class 类2(类1):  #继承类1
        def 方法1(self):
            self.属性1  #在不同类中公有属性1可以继承
            self.__属性2 #在不同类中私有属性2不能继承
        def 方法3(self):
            self.方法1() #在不同类中公有方法1可以继承,包括公有方法1中的公有属性1和私有属性2
            self.__方法2() #在不同类中私有方法2不能继承
    
    aa = 类1()
    bb = 类2()

    类1中
      方法1是公有方法
        属性1是公有属性,在不同的方法和不同的类中都可以继承
        属性2是私有属性,在不同的类中不可以继承,在同一个类中不同方法中可以继承
      __方法2是私有方法,在同一个类中可以继承,在不同的类中不可以继承

  • 相关阅读:
    代码分层之模拟servlet调用dao
    Request对象和Response对象
    jquery-动画
    jquery-easyui
    phpcms
    Ajax做分页
    phpcms安装
    cms替换主页的步骤
    php 复习
    登录验证——————生成随机数
  • 原文地址:https://www.cnblogs.com/dxnui119/p/9967928.html
Copyright © 2020-2023  润新知