• python, 面向对象编程Object Oriented Programming(OOP)


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

    面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。

    一:封装(类内的事)

    对于类的方法而言,对外只知道功能隐藏细节

    假设我们要处理学生的成绩表,为了表示一个学生的成绩,面向过程的程序可以用一个dict表示:
    #面向程序
    std1 = { 'name': 'Michael', 'score': 98 }
    std2 = { 'name': 'Bob', 'score': 81 }
    
    def print_score(std):
        print('%s: %s' % (std['name'], std['score']))
    
    #面向对象
    class Student(object): # 继承类object,所有类最终都会继承的类
      #属性
      def __init__(self, name, score):
         self.name = name self.score = score 
      #数据封装,类的方法,为了和类关联起来
      def print_score(self): 
        print('%s: %s' % (self.name, self.score)) 
    
    #封装的另一个好处是可以给Student类增加新的方法
        def get_grade(self):
            if self.score >= 90:
                return 'A'
            elif self.score >= 60:
                return 'B'
            else:
                return 'C'
    #给对象发消息就是调用对象对应的关联函数,称为对象的方法,实例
     bart = Student('Bart Simpson', 59)
     bart.print_score()
    #类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响;

    访问限制

    #属性的名称前加上两个下划线__,私有变量(private),只有内部可以访问
    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))
    
    #如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法
        def get_name(self):
            return self.__name
    
        def get_score(self):
            return self.__score
    
    #如果又要允许外部代码修改score
        def set_score(self, score):
            self.__score = score
    
    #bart.score = 59也可以修改,因为在方法中,可以对参数做检查,避免传入无效的参数
        def set_score(self, score):
            if 0 <= score <= 100:
                self.__score = score
            else:
                raise ValueError('bad score')
    
    #变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的
    
    #一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的但是约定为私有变量
    
    #不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,强烈建议你不要这么干,因为不同版本的Python解释器可能会把__name改成不同的变量名
    >>> bart._Student__name
    'Bart Simpson'

    二:继承(类之间的事)

    子类从属父类的属性和方法,也可自己定义,覆盖父类或添加。

    当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)

     1 class Animal(object):
     2     def run(self):
     3         print('Animal is running...')
     4 
     5 #继承
     6 #对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类
     7 class Dog(Animal):
     8     pass
     9 
    10 class Cat(Animal):
    11     pass
    12 
    13 #子类获得了父类的全部功能
    14 dog = Dog()
    15 dog.run()
    16 #结果
    17 Animal is running...
    18 
    19 #可以对子类增加一些方法
    20 class Dog(Animal):
    21 
    22     def run(self):
    23         print('Dog is running...')
    24 
    25     def eat(self):
    26         print('Eating meat...')
    27 
    28 #子类和父类都存在相同的run()方法时,子类的run()覆盖了父类的run()
    29 dog = Dog()
    30 dog.run()
    31 #结果,多态
    32 Dog is running...

    三:多态

    定义一个class的时候,实际上就定义了一种数据类型,和Python自带的数据类型,比如str、list、dict没什么两样

     1 a = list() # a是list类型
     2 b = Animal() # b是Animal类型
     3 c = Dog() # c是Dog类型
     4 
     5 #判断一个变量是否是某个类型可以用isinstance()
     6 >>> isinstance(a, list)
     7 True
     8 >>> isinstance(b, Animal)
     9 True
    10 >>> isinstance(c, Dog)
    11 True
    12 #个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类
    13 >>> isinstance(c, Animal)
    14 True
    15 #反过来就不行
    16 >>> isinstance(b, Dog)
    17 False

    传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法

    def run_twice(animal):
        animal.run()
        animal.run()
    
    >>> run_twice(Animal())
    Animal is running...
    Animal is running...
    
    >>> run_twice(Dog())
    Dog is running...
    Dog is running...

    著名的“开闭”原则:

    对扩展开放:允许新增Animal子类;

    对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。

    静态语言和动态语言

    对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

    对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了

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

  • 相关阅读:
    Redis配置文件的使用
    WEB请求处理一:浏览器请求发起处理
    Nginx配置文件(nginx.conf)配置详解
    【node】------mongoose的基本使用
    Promise.resolve()与new Promise(r => r(v))
    promise是什么?
    apiDoc
    apiDoc 使用指南
    微信小程序-性能与体验优化
    微信小程序-调取上一页的方法
  • 原文地址:https://www.cnblogs.com/xiexiaoxiao/p/7047142.html
Copyright © 2020-2023  润新知