zoukankan      html  css  js  c++  java
  • 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是私有方法,在同一个类中可以继承,在不同的类中不可以继承

  • 相关阅读:
    c语言结构体数组引用
    c语言结构体数组定义的三种方式
    如何为SAP WebIDE开发扩展(Extension),并部署到SAP云平台上
    SAP SRM ABAP Webdynpro和CFCA usb key集成的一个原型开发
    使用SAP API portal进行SAP SuccessFactors的API测试
    SAP UI5应用里的页面路由处理
    在SAP WebIDE Database Explorer里操作hdi实例
    如何使用SAP事务码SAT进行UI应用的性能分析
    使用SAP WebIDE进行SAP Cloud Platform Business Application开发
    SAP CRM WebClient UI ON_NEW_FOCUS的用途
  • 原文地址:https://www.cnblogs.com/dxnui119/p/9967928.html
Copyright © 2011-2022 走看看