zoukankan      html  css  js  c++  java
  • Python3 面向对象

    1.面向对象

      把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

      面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。

    class Student(object):
    
        def __init__(self, name, score):
            self.name = name
            self.score = score
    
        def print_score(self):
            print('%s: %s' % (self.name, self.score))

      Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student,比如,Bart Simpson和Lisa Simpson是两个具体的Student。

    • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
    • 方法:类中定义的函数。
    • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
    • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
    • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
    • 局部变量:定义在方法中的变量,只作用于当前实例的类。
    • 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
    • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
    • 实例化:创建一个类的实例,类的具体对象。
    • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

    2.类和实例

      必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

    class Student(object):
        def __init__(self, name, score):  #构造方法
            self.name = name
            self.score = score
    
        def get_grade(self):
            if self.score >= 90:
                return 'A'
            elif self.score >= 60:
                return 'B'
            else:
                return 'C'
    
    bart = Student('Bart Simpson', 59)
    print(bart.get_grade())

      class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。

      注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。

      创建实例的时候,必须传入与__init__方法匹配的参数。

      要定义一个方法,除了第一个参数是self外,其他和普通函数一样。要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入:

    class Student(object):
        def __init__(self, name, score):  #构造方法
            self.__name = name
            self.__score = score
    
        def get_name(self):
            return self.__name
    
        def get_score(self):
            return self.__score
    
        def set_score(self, score):
            if 0 <= score <= 100:
                self.__score = score
            else:
                raise ValueError('bad score')
    
    bart = Student('Bart Simpson', 59)
    
    bart.set_score(100)
    
    print(bart.get_score(),bart.get_name())

    bart._Student__name  ###这样可以从外部访问了,但是不建议。

      内部属性不被外部访问,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。

      这样代码更健壮,可以对参数做检查,避免传入无效的参数

      在Python中,变量名类似__xxx__的,就是以双下划线开头,并且以双下划线结尾,是特殊变量,特殊变量可以直接访问,不是private变量,不能用__name____score__这样的变量名。  

      以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,把它当成私有变量。

      __private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。

    类的专有方法:可以对类的专有方法进行重载(用到具体的搜索吧)

    • __init__ : 构造函数,在生成对象时调用
    • __del__ : 析构函数,释放对象时使用
    • __repr__ : 打印,转换
    • __setitem__ : 按照索引赋值
    • __getitem__: 按照索引获取值
    • __len__: 获得长度
    • __cmp__: 比较运算
    • __call__: 函数调用
    • __add__: 加运算
    • __sub__: 减运算
    • __mul__: 乘运算
    • __truediv__: 除运算
    • __mod__: 求余运算
    • __pow__: 乘方

    3.继承和多态

      OOP程序设计中,我们定义class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

      子类获得了父类的全部功能,但当子类和父类有相同的方法时,子类覆盖了父类的该方法,先调用子类的相同方法。

      super() 函数是用于调用父类(超类)的一个方法super(dog, self).__init()__(name)

      基类可以定义在别的模块中,class DerivedClassName(modname.BaseClassName):         但是要导入该模块import。

      Python同样有限的支持多继承形式。需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,方法在子类中未找到时,从左到右查找父类中是否包含方法。

    class DerivedClassName(Base1, Base2, Base3):
        <statement-1>
        .
        .
        .
        <statement-N>

     继承示例代码:

    class Animal(object):
        def __init__(self):
            a = "animal"
    
        def run(self):
            print('Animal is running...')
    
    class Dog(Animal):
        def run(self):
            print('Dog is running...')
    
        def eat(self):
            print('Eating meat...')
    
    dog = Dog()
    print(isinstance(dog, Dog))

      Python中多态是指一类事物有多种形态。比如动物有多种形态,人,狗,猫,等等。文件有多种形态:文本文件,可执行文件。

      多态性:

      为什么要用多态性?

      ①增加了程序的灵活性

      以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)

      ②增加了程序额可扩展性

      通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用

    import abc
    
    
    class Animals(metaclass=abc.ABCMeta):
        @abc.abstractmethod
        def talk(self):
            pass
    
    
    class People(Animals):
        def talk(self):
            print('People is talking')
    
    
    class Cat(Animals):
        def talk(self):
            print('Cat is miaomiao')
    
    
    class Dog(Animals):
        def talk(self):
            print('Dog is wangwang')
    
    
    cat1 = Cat()
    dog1 = Dog()
    peo1 = People()
    # peo、dog、pig都是动物,只要是动物肯定有talk方法
    # 于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
    peo1.talk()
    dog1.talk()
    peo1.talk()
    
    
    # 定义一个统一的接口来访问
    def func(obj):
        obj.talk()
    
    
    func(cat1)

       动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

     4.获取对象信息

      判断对象类型,使用type()函数。如果要判断一个对象是否是函数等,可以使用types模块中定义的常量。

        isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。

      获得一个对象的所有属性和方法,可以使用dir()函数。

      通过内置的一系列函数,我们可以对任意一个Python对象进行剖析,拿到其内部的数据。要注意的是,只有在不知道对象信息的时候,我们才会去获取对象信息。

      配合getattr()setattr()以及hasattr(),我们可以直接操作一个对象的状态。参考菜鸟python3 内置函数。

     5. 实例属性和类属性

      直接在class中定义属性,这种属性是类属性,归类所有。类的所有实例都可以访问到。相同名称的实例属性将屏蔽掉类属性。

      访问类的变量是通过“类名.变量名”进行访问,而不是“self.变量名”进行访问。“self.变量名”访问的是实例对象的自身变量。

      下面例子中实例的变量被重新绑定,

    class ff:
        a = 5
    
        def aaa(self):
            print(ff.a)   #如果写成self.a,a1.a变量被重新绑定,a1.aaa()的值就是10. 就取不到类的变量。
    
    a1 = ff()
    a1.aaa()
    a2 = ff()
    a2.aaa()
    a1.a = 10
    print(a1.a)
    print(a2.a)
    ff.a = 100
    print(a1.a)
    print(a2.a)
    a1.aaa()
    a2.aaa()
    
    
    result:
    5
    5
    10
    5
    10
    100
    100
    100

    6.使用__slots__

       可以给一个实例绑定方法和属性,但对别的实例是不起作用的。

       只允许对Student实例添加nameage属性。

    class Student(object):
        __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    
    s = Student()
    s.name = "sss"
    s.score = 99

      使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

      在子类中也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

    7.使用@property

    读,写,删除的例子。三种操作对应了一个名字。

    class People(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
            # 私有属性
            self.__number = 0
        # 获取私有属性值  number = p1.number 会执行这个函数
        @property
        def number(self):
            # 返回私有属性值
            return self.__number
        # 设置私有属性值  p1.number = 666
        @number.setter
        def number(self, value):
            # 设置__number的值
            self.__number = value
     
        # 删除私有属性  del p1.number 会执行这个函数
        @number.deleter
        def number(self):
            # 删除属性
            del self.__number
    p1 = People('张三', 22)
    # 正常的对象属性赋值
    # 对象.属性名 = 属性值
    p1.name = '李四'
    # 获取对象的属性值
    name = p1.name
    # 删除对象的属性
    del p1.name
    # 私有属性升级版
    # 会去执行@property装饰number函数,函数执行完成后返回一个结果
    num = p1.number
    print(num)
    # 会去执行@number.setter装饰的number函数,在函数中设置__number属性的值
    p1.number = 666
    # 会去执行@property装饰number函数,函数执行完成后返回一个结果
    print(p1.number)
    # 会去执行@number.deleter装饰的number函数,在函数中会将__number属性删除
    del p1.number
    # 会去执行@property装饰number函数,函数执行完成后返回一个结果
    print(p1.number)
    

      birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。

    class Student(object):
    
        @property
        def birth(self):
            return self._birth
    
        @birth.setter
        def birth(self, value):
            self._birth = value
    
        @property
        def age(self):
            return 2015 - self._birth
    
    s = Student()
    s.birth = 5
    print(s.birth)

    8.多重继承

      在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。 

    class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
        pass

    9.检查对象的特性

      hasattr() 函数用于判断对象是否包含对应的属性。语法:hasattr(object, name)

      getattr() 函数用于返回一个对象属性值。语法:getattr(object, name[, default])  default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。

    c = ff()
    print(hasattr(c, 'age')) #检查实例属性是否拥有
    print(hasattr(c, 'study')) #检查实例方法是否拥有
    print(callable(getattr(c, 'study',None))) #检查实例方法study能否被调用
    是否拥有
  • 相关阅读:
    C++学习笔记-C++对C语言的扩充和增强
    C++学习笔记-C++与C语言的一些区别
    C++学习笔记-C++与C语言的一些区别
    C学习笔记-字符串处理函数
    C学习笔记-字符串处理函数
    C学习笔记-gdb
    深入理解C语言-函数指针
    深入理解C语言-函数指针
    深入理解C语言-结构体做函数参数
    async 珠峰培训node正式课笔记 【async】任务流程控制,异步流程控制
  • 原文地址:https://www.cnblogs.com/yunlong-study/p/12613627.html
Copyright © 2011-2022 走看看