zoukankan      html  css  js  c++  java
  • Python基础学习13--面向对象

    面向对象

    面向对象概述:

    类和对象的概念:

    •   类 : 抽象名词,用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

    •   对象 : 具体的事物,通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

    •   类跟对象的关系:

        -> 一个是抽象,代表一大类事物------比如:人类,动物,花,等等。。

        ->一个是具象,代表了一类事物中具体的的某一个个体------比如:人类中的张三、李四、王五等。。

    类的内容:

    •   表明事物的特征,称为属性(变量)

    •   表明事物功能或动作,称为成员方法(函数)

    类的定义:

    •   必须使用class关键字------函数使用的是def

    •   class后面跟 类的名称

    •   类是由属性和方法构成

    •   成员的属性定义可以直接使用变量赋值,如果没有值,可使用None

    类的命名:

    •   遵守变量命名规范:https://www.cnblogs.com/wilson-5133/p/9842843.html

    •   大驼峰:由一个或多个单词构成,每个单词的首字母大写,单词跟单词之间直接相连

    •   可以通过默认内置变量检查类和对象的所有成员

        1. 对象所有成员检查

          # dict前后各有两个下划线

          obj.__dict__

        2. 类所有成员检查

          class_name.__dict__

    代码实例如下:

    # 定以一个学生类,用来形容学生
    # 定义一个空的类
    class Student():
        # 一个空类,pass代表直接跳过
        # 此处pass必须有
        pass
    
    # 实例化类
    # 变量 = 类名()
    Tom = Student()
    
    # 在定义一个类,用来描述学习Python的学生
    class PythonStudent():
    
        # 用None给不确定的值赋值
        name = None
        age = 18
        course = "Python"
    
        # 需要注意
        # 1. def doHomework的缩进层级
        # 2. 系统默认有一个self参数
        def doHomework(self):
            print("我在做作业")
            # 推荐在函数末尾使用return语句
            return None
    
    # 实例化一个叫wilson的学生,是一个具体的人
    wilson = PythonStudent()
    
    # 访问对象成员
    print('wilson.name:',wilson.name)
    print('wilson.age :',wilson.age)
    
    # 注意成员函数的调用没有传递进入参数
    wilson.doHomework()
    
    print('wilson.__dict__:',wilson.__dict__)
    print('PythonStudent.__dict__:',PythonStudent.__dict__)
    
    wilson.name = 'Null'
    wilson.age = 16
    
    print('wilson.__dict__:',wilson.__dict__)
    print('PythonStudent.__dict__:',PythonStudent.__dict__)

    输出结果如下:

    wilson.name: None
    wilson.age : 18
    我在做作业
    
    wilson.__dict__: {}
    PythonStudent.__dict__: {'__module__': '__main__', 'name': None, 'age': 18, 'course': 'Python', 'doHomework': <function PythonStudent.doHomework at 0x02B114F8>, '__dict__': <attribute '__dict__' of 'PythonStudent' objects>, '__weakref__': <attribute '__weakref__' of 'PythonStudent' objects>, '__doc__': None}
    
    wilson.__dict__: {'name': 'Null', 'age': 16}
    PythonStudent.__dict__: {'__module__': '__main__', 'name': None, 'age': 18, 'course': 'Python', 'doHomework': <function PythonStudent.doHomework at 0x02B114F8>, '__dict__': <attribute '__dict__' of 'PythonStudent' objects>, '__weakref__': <attribute '__weakref__' of 'PythonStudent' objects>, '__doc__': None}

    关于self

    •   self在对象的方法中表示当前对象本身,如果通过对象调用一个方法,那么该对象会自动传入到当前方法 的第一个参数中

    •   self并不是关键字,只是一个用于接收对象的普通参数,理论上可以用任何一个普通变量名代替

    •    方法中有self形参的方法称为非绑定类的方法,可以通过对象访问, 没有self的是绑定类的方法, 只能通过类访问

    •    使用类访问绑定类的方法时, 如果类方法中需要访问当前类的成员,可以通过 __class__成员名来访问

    代码实例如下: 

    class Teacher():
        name = "Jack"
        age = 33
    
        def Math(self):
            self.name = "Tony"
            self.age = 31
            print("My name is {0}".format(self.name))
    
            # 调用类的成员变量需要用 __class__
            print("My age is {0}".format(__class__.age))
    
        def English():
            print(__class__.name)
            print(__class__.age)
            print("Are u ok?")
    
    t = Teacher()
    t.Math()
    
    # 调用绑定类函数使用类名
    Teacher.English()

    输出结果如下: 

    My name is Tony
    My age is 33
    
    Jack
    33
    Are u ok?

     面向对象的三大特性

    •   封装
    •   集成
    •   多态

    封装

      封装就是对对象的成员进行访问限制

      封装的的3个级别:

      1. 公开、公共:Public
        • 公共的封装实际对成员没有任何操作,任何地方都可以访问
      2. 受保护的:Protected
        • 受保护的封装是将对象成员进行一定级别的封装,在类实例或者子类实例都可以进行访问,但是外部不可以访问
        • 封装方法:在成员前加1个下划线即可
      3. 私有的:Private
        • 私有成员是最高级别的封装,只能在当前类或对象中访问,在类的外部无法直接进行访问,包括子类
        • 在成员前面添加2个下划线即可

    代码实例如下:

    class Person():
        # name是共有的成员
        name = "Chinese"
        # sex是受保护的
        _sex = 'male'
        # __age就是私有变量
        __age = 18
    
        def Old(self):
            print('{} years old'.format(self.__age))
    
    p = Person()
    # name是公有变量
    print('p.name:',p.name)
    
    # sex是受保护的,可以在实例中调用
    print('p._sex:',p._sex)
    
    # 当前类或对象中可访问
    p.Old()
    
    # __age是私有变量,只能在当前的类或对象中访问,实例不能访问私有变量
    print(p.__age)

    输出结果如下:

    p.name: Chinese
    
    p._sex: male
    
    18 years old    # 只能通过当前类或对象访问
    
    AttributeError: 'Person' object has no attribute '__language'    # 不能直接访问私有变量

    继承

      继承就是一个类可以获得另外一个类中的成员属性和成员方法

      作用:减少代码,增加代码的复用功能,同时可以设置类与类直接的关系

       继承与被继承的关系

      • 被继承的类称为父类,也叫基类、超类
      • 用于继承的类,称为子类,也叫派上类
      • 继承与被继承一定存在一个 is-a 的关系 

      继承的特征:

      • 所有的类都继承自object类,即所有的类都是object类的子类
      • 子类一旦继承父类,则可以使用父类中除私有成员外所有的内容
      • 子类继承父类后并没有将父类成员完全赋值到子类中,而是通过引用关系访问调用
      • 子类可以定义独有的成员属性和方法
      • 子类中定义的成员如果和父类的成员相同,则优先使用子类成员
      • 子类如果想扩充父类的方法,可以在定义新方法的同时访问父类成员来进行代码重用,可以使用 [父类名.父类成员] 的格式来调用父类成员,也可以使用 super().父类成员 的格式调用

    代码实例如下:

    # 子类和父类定义同一个变量名称,则优先使用子类本身
    # 人有工作的函数, 老师也有工作的函数,但老师的工作需要讲课
    class Person():
        name = "NoName"
        age = 18
        __score = 0  # 考试成绩是秘密,只要自己知道
        _petname = "sec"  # 小名,是保护的,子类可以用,但不能公用
    
        def sleep(self):
            print("Sleeping ... ...")
    
        def work(self):
            print("show me the money")
    
    # 父类写在括号内
    class Teacher(Person):
        teacher_id = "9527"
        name = "Tony"
    
        def teach(self):
            print("Lecture to students")
    
        def work(self):
            # 扩充父类的功能只需要调用父类相应的函数
            # Person.work(self)
            # 扩充父类的另一种方法
            # super代表得到父类
            super().work()
            self.teach()
    
    t = Teacher()
    # 子类和父类定义同一个变量名称,则优先使用子类本身
    print('t.name:',t.name)
    # 扩充后,会调用父类和子类的方法
    t.work()

    输出结果如下:

    t.name: Tony
    
    # t.work()
    show me the money     # 继承自父类Person的work()
    Lecture to students    # 子类Teacher扩充的work()

      

      继承变量函数的查找顺序问题:

      • 优先查找自身的变量
      • 如果没有,则查找父类
      • 构造函数如果子类中没有定义,则自动调用父类的构造函数
      • 如果子类有定义,则不向上查找

       构造函数

      • 是一类特殊的函数,在类进行实例化之前进行调用
      • 如果定义了构造函数,则实例化的时候使用自身的构造函数,不会查找父类的构造函数
      • 如果没有定义,会自动查找父类的构造函数
      • 如果子类没有定义,父类的构造函数带参数,则构造对象时的参数应该按照父类参数传参

    代码实例如下:

    # 例1:实例会直接调用构造函数
    class Animal:
        pass
    
    class Reptiles(Animal):     # Reptiles:爬行动物
        # __init__就是构造函数/构造方法
        # 每次实例化的时候,第一个被自动调用
        def __init__(self):
            print('这是Reptiles-Animal的子类')
    # 实例化的时候,自动调用Reptiles的构造函数
    R1 = Reptiles()
    
    # 例2:如果子类中存在构造函数,则不会再向上查找
    class Tortoise(Reptiles):   # Tortoise:乌龟
        def __init__(self,name):
            print('这是Tortoise-Reptiles的子类:{}'.format(name))
    # 实例化的时候,自动调用Tortoise的构造函数
    T1 = Tortoise('turtle')
    
    class Snake(Reptiles):
        pass
    # 实例化的时候,如果子类没有构造函数,所以会向上查找,即其父类-Reptiles
    S1 = Snake()
    
    class Terrapin(Tortoise):   # Terrapin:水龟
        pass
    
    # 此时,由于Terrapin没有构造函数,则向上查找
    # 因为Tortoise的构造函数需要2个参数,实例化的时候给了1个,报错
    T2 = Terrapin()

    输出结果如下:

    # 实例化的时候,自动调用Reptiles的构造函数
    # R1 = Reptiles()
    这是Reptiles-Animal的子类
    
    # 实例化的时候,自动调用Tortoise的构造函数
    # T1 = Tortoise('turtle')
    这是Tortoise-Reptiles的子类:turtle
    
    # 实例化的时候,如果子类没有构造函数,所以会向上查找,即其父类-Reptiles
    # S1 = Snake()
    这是Reptiles-Animal的子类
    
    # 子类没有构造函数,父类的构造函数需要2个参数,如果只传1个,会报错!
    TypeError: __init__() missing 1 required positional argument: 'name'

      单继承和多继承

      • 单继承:每个类只能继承一个类
      • 多继承:每个类允许继承多个类

      单继承和多继承的优缺点

      • 单继承:
        • 优点:传承有序,逻辑清晰,语法简单,隐患少
        • 缺点:功能不饿能无限扩展,只能在当前唯一的继承链中扩展
      • 多继承:
        • 优点:类的功能扩展方便
        • 缺点:继承关系混乱

    代码实例如下:

    # 子类可以直接拥有父类的属性和方法,私有属性和方法除外
    class Fish():
        def __init__(self, name):
            self.name = name
    
        def swim(self):
            print("我会游泳...")
    
    class Bird():
        def __init__(self, name):
            self.name = name
    
        def fly(self):
            print("我会飞...")
    
    class Person():
        def __init__(self, name):
            self.name = name
    
        def work(self):
            print("Show me the money...")
    
    # 单继承的例子
    class Student(Person):
        def __init__(self, name):
            self.name = name
    
    stu = Student("stu")
    print(stu.name)
    stu.work()
    
    # 多继承的例子
    class SuperMan(Person, Bird, Fish):     # 继承3个父类:Person, Bird, Fish
        def __init__(self, name):
            self.name = name
    
    class SwimMan(Person, Fish):            # 继承2个父类:Person, Fish
        def __init__(self, name):
            self.name = name
    
    Kent = SuperMan("Clark")
    
    print(Kent.name)
    Kent.fly()
    Kent.swim()
    Kent.work()

    输出结果如下:

    # stu继承自Person
    stu
    Show me the money...
    
    # Clark继承自Person, Bird, Fish
    Clark
    我会飞...
    我会游泳...
    Show me the money...

    多态

    • 多态就是同一个对象在不同情况下有不同的状态出现

    • 多态不是语法,而是一种设计思想

    • 多态性:一种调用方式,不同的执行效果

    • 多态:同一事物的多种形态,如:动物分为人类,鸟类,爬行类,鱼类......

    • 多态和多态性

    • Mixin设计模式:Mix-in  混入的意思

      • 主要采用多继承方式对类的功能进行扩展
      • Mixin的概念
      • Mixin模式
      • 从某种程度上来说,继承强调 I am,Mixin 强调 I can
    • 使用Mixin实现多继承的时候非常小心

      • 首先它必须表示某一单一功能,而不是某个物品
      • 指责必须单一,如果由多个功能,则写多个Mixin
      • Mixin不能依赖于子类的实现
      • 子类即使没有继承这个Mixin类,也能照样工作,只是缺少了某个功能
    • 优点

      • 使用Mixin可以在不对类进行任何修改的情况下,扩充功能
      • 可以方便地组织和维护不同功能组件的划分
      • 可以根据需要任意调整功能类的组合
      • 可以避免创建很多新的类,导致类的继承混乱

    代码实例如下:

    class Vehicle(object):      # Vehicle:交通工具
        pass
    
    class PlaneMixin(object): 
        def fly(self):
            print('I am flying')
    
    # 多继承,父类为:Vehicle, PlaneMixin
    class Airplane(Vehicle, PlaneMixin):
        pass
    
    # 第二个父类为 PlaneMixin 而非 Plane
    # 不影响功能,但会告诉读代码的人,Airplane 只是 Vehicle,不是 Plane
    # 换言之,Airplane 属于 Vehicle类,但是他又具备 Plane 的 fly 功能
    # Mixin,表示混入(mix-in),它告诉别人,这个类(PlaneMixin)是作为功能添加到子类中,而不是作为父类

    类的相关函数

    1、issubclass(A, B)

        判断 A 类是否是 B 类的子类

    class A():
        pass
    
    class B(A):
        pass
    
    class C():
        pass
    
    print(issubclass(B, A))         # 判断 B 是否为 A 的子类
    print(issubclass(C, A))         # 判断 C 是否为 A 的子类
    print(issubclass(B, object))    # 判断 B 是否为 object 的子类
    # B 是 A 的子类,所以为 True
    True
    
    # C 不是 A 的子类,所以为 False
    False
    
    # 所有类都是 object 的子类,所以为True
    True

    2、isinstance(obj, A)

        判断 obj 对象是否是 A 类的实例对象

    class A():
        pass
    
    a = A()
    
    print(isinstance(a, A))     # 判断 a 是否是 A 的实例对象
    print(isinstance(A, A))     # 判断 A 是否是 A 的实例对象
    # a 是 A 的实例对象,所以为True
    True
    
    # A 不是 A 的实例对象,所以为False
    False

    3、hasattr(obj, name)

        判断 obj 对象是否存在成员 name

    class A():
        name = "NoName"
    
    a = A()
    print(hasattr(a, "name"))       # 判断 实例对象 a 中是否包含 name 属性
    print(hasattr(a, "age"))        # 判断 实例对象 a 中是否包含 age 属性
    # 判断 实例对象 a 中包含 name 属性
    True
    
    # 判断 实例对象 a 中不包含 age 属性
    False

    4、getattr(object, name[, default])

        返回一个对象属性值

    class A(object):
        bar = 1
    
    a = A()
    
    print(getattr(a, 'bar'))        # 属性 bar 存在,则获取属性 bar 值
    
    print(getattr(a, 'bar2', 3))    # 属性 bar2 不存在,但设置了默认值 3 ,会返回 3
    
    print(getattr(a, 'bar2'))       # 属性 bar2 不存在,会触发异常报错
    # 属性 bar 存在,则获取属性 bar 值 1
    1
    
    # 属性 bar2 不存在,但设置了默认值 3 ,会返回 3
    3
    
    # 属性 bar2 不存在,又没有设置默认值,会触发异常报错
    AttributeError: 'A' object has no attribute 'bar2'

    5、setattr(object, name, value)

        用于设置属性值,该属性不一定是存在的

    class A(object):
        bar = 1
    
    a = A()
    
    # 属性 bar 存在
    print(getattr(a, 'bar'))        # 获取属性 bar 值
    
    setattr(a, 'bar', 5)            # 设置属性 bar 值为 5
    print(a.bar)                    # 查看设置后 bar 的值
    
    # 属性 obj 不存在
    setattr(a, "name", 'wilson')    # 如果属性不存在,会创建一个新的属性,并对属性赋值
    print(a.name)                   # 查看 name 属性的值
    # 使用 getattr 查看 bar 的属性值
    1
    
    # 使用 setattr 更改 bar 的属性值后,再次查看
    5
    
    # 使用 setattr 创建新的属性并赋值后,查看
    wilson

    6、delattr(object, name)

        用于删除属性

    class A(object):
        bar = 1
    
    a = A()
    
    # 查看属性值
    print(a.bar)
    
    delattr(A, 'bar')       # 通过 delattr 删除 A 类中的 bar 属性
    
    print(a.bar)
    # 执行delattr(A, 'bar')操作前,查看 a.bar 的值
    1
    
    # 执行delattr(A, 'bar')操作后,查看 a.bar 的值
    AttributeError: 'A' object has no attribute 'bar'

    推荐歌曲:生僻字(计算机版)(Cover:陈柯宇)

  • 相关阅读:
    java多线程:并发包中ConcurrentHashMap和jdk的HashMap的对比
    java编程之:Unsafe类
    mave之:java的web项目必须要的三个jar的pom形式
    java多线程:并发包中ReentrantReadWriteLock读写锁的锁降级模板
    java多线程:并发包中ReentrantReadWriteLock读写锁的原理
    java编程之:按位与运算,等运算规则
    java多线程:jdk并发包的总结(转载)
    liunx之:wps for liunx的安装经验
    mysql中enum类型理解
    MySQL类型float double decimal的区别
  • 原文地址:https://www.cnblogs.com/wilson-5133/p/10371261.html
Copyright © 2011-2022 走看看