美文网首页
(3) python 面向对象编程

(3) python 面向对象编程

作者: 小黄不头秃 | 来源:发表于2022-10-18 00:16 被阅读0次

    (一)面向对象编程

    在面向对象中最重要的三个部分分别是:封装、继承、多态

    可参考我前面的笔记:https://www.jianshu.com/p/92790574f3d2

    在学习这些之前,我们先明白两个概念:类、对象

    • 类(class):描述具有相同属性和方法的对象的集合。例如:人类。
    • 对象(object):通过对类进行实例化,分配内存空间,能能够被用户使用。例如:张三。
    # 类
    class Person():
        name="人类有个名字"
        age="人类有年龄"
        sex="人类有性别"
    
    # 对象
    p1 = Person()
    p1.name = "我叫张三"
    p1.age = 18
    p1.sex = "man"
    print(type(p1)) # <class '__main__.Person'>
    
    (1)封装(encapsulation)

    将一个类的所有属性和方法放到一起,或者说将数据和功能汇聚到一起。
    封装能够保证类内部数据结构的完整性,只允许用户使用公开的数据,不允许使用私有数据,避免了外部对内部数据的影响,从而提高了程序的可维护性。

    首先我们来看看,对象生命周期和函数执行的顺序:

    self:代表当前对象,可以在类的内部直接访问任何类的变量和方法,类里面的所有函数都以self作为第一个参数。(self不是关键字,只是形参的名字)

    class Person():
        """人类"""
        # 这个方法一般不使用
        def __new__(cls,*args, **kwargs):
            print("new")
            return super().__new__(cls)
    
        # 一个人诞生了,需要给它起个名字,初始化年龄等
        def __init__(self,name,age) -> None:
            print("初始化函数") # 实例化对象的时候会自动调用
            self.name = name
            self.age = age
            self.print_name()
    
        def print_name(self):
            print("我是:",self.name)
        
        def __del__(self):
            print("析构函数")# 释放对象的时候会自动调用
    
    p1 = Person("张三", 18)
    # new
    # 初始化函数
    # 我是: 张三
    # 析构函数
    

    类变量和实例变量

    • 类变量:类变量是每一个类都有的变量,新创建的每一个实例的类变量都是一样的,地址也都一样。类变量可以是可变变量和不可变变量。我们可以以通过实例和类访问到类变量,如果类变量是可变变量,只要在一个实例中改变类变量,其他实例访问的时候也会改变。不推荐使用实例访问类变量。
    • 实例变量:是每一个实例私有的,每个实例的变量的地址都不同,每个实例之间不会相互影响。并且无法通过类名访问。

    私有变量:私有成员变量,外部不能访问。以__开头
    私有方法:私有成员方法,外部不能访问。以__开头

    理论上私有变量是不允许外部访问的,但是python给我们开了个后门,我们可以使用实例名._类名__变量名来访问

    class Person():
        # 类变量
        sex = "man"
        list1 = [1,2,3]
        __a = 1 # 私有成员变量
    
        # 初始化函数
        def __init__(self, name) -> None:
            self.name = name 
    
        # 私有成员方法
        def __get_a(self):
            __a = 3 # 内部可以访问,外部不能访问
    
    # 两个都叫张三的人
    p1 = Person("张三")
    p2 = Person("张三")
    
    # 类变量, 不可变变量
    print(Person.sex == p1.sex == p2.sex, id(Person.sex), id(p1.sex), id(p2.sex)) # True 1371018000456 1371018000456 1371018000456
    p1.sex = "woman"
    print(Person.sex == p1.sex == p2.sex, id(Person.sex), id(p1.sex), id(p2.sex)) # False 1371018000456 1371047207352 1371018000456
    
    # 类变量, 可变变量
    print(Person.list1 == p1.list1 == p2.list1, id(Person.list1), id(p1.list1), id(p2.list1)) # True 1371046436744 1371046436744 1371046436744
    Person.list1.append(4)
    print(Person.list1 == p1.list1 == p2.list1, id(Person.list1), id(p1.list1), id(p2.list1)) # True 1371046436744 1371046436744 1371046436744
    
    # 实例变量
    print(id(p1.name), id(p2.name)) # 1371047341288 1371047984448
    print(Person.name) # AttributeError: type object 'Person' has no attribute 'name'
    
    # 私有成员变量&方法
    print(p1.__a) # AttributeError: 'Person' object has no attribute '__a'
    print(p1.__get_a()) # AttributeError: 'Person' object has no attribute '__get_a'
    print(p1._Person__a) # 1
    

    类方法属于类但不属于实例的方法,需要在方法前面使用@classmethod标记。
    静态方法寄居在类中,独立存在,不能调用对象方法和类方法(类名.方法名除外),需要在方法前面使用@staticmethod标记。
    property 装饰器让一个方法被当成属性来调用,不能传入参数,,需要在方法前面使用@property标记

    python还有很多的魔术方法:

    class A():
        def __init__(self) -> None:
            pass
    
        @classmethod
        def a(self):
            print("类方法")
    
        @staticmethod
        def b(): # 无需传入self
            print("静态方法")
        
        @property
        def c(self):
            print("c")
    
        def __str__(self) -> str:
            return "hello, this is the object of A"
    
        def d(self):
            print("d")
    
    a1 = A()
    A.a() # 类方法
    A.b() # 静态方法
    A.c # c
    A.d(self=1)# 可以使用类名调用实例方法但是需要手动传入self参数
    a1.a() # 类方法
    a1.b() # 静态方法
    a1.c # c
    a1.c() # c TypeError: 'NoneType' object is not callable
    print(a1) # hello, this is the object of A
    
    (2)继承

    子类通过继承父类从而获取父类的属性和方法。

    如果父类和子类有相同名称的方法或者属性,会被后者覆盖。可以通过super调用父类的重名函数。

    一个类也可以继承于多个父类。

    class Person(): # 父类
        title="人类"
        __a = "a"
    
        def print_title(self):
            print(Person.title)
    
    class Teacher(Person): # 子类
        name = "老师"
    
    class Student(Person): # 子类
        name = "学生"
        def print_title(self):
            print(Student.name)
    
        def private_a(self):
            print(Person._Person__a) # 不推荐使用
    
    t1 = Teacher()
    s1 = Student()
    t1.print_title() # 人类 继承父类方法
    s1.print_title() # 学生 覆盖父类方法
    super(Student, s1).print_title() # 人类
    # 访问父类私有属性
    s1.private_a()
    s1._Person__a # 'a' 不推荐使用
    
    (3)多态

    多态就是子类重写父类的方法,上面已经说过了。也就是子类和父类方法重名,子类方法覆盖父类方法。

    class A():
        def test(self):
            print("a")
    
    class B(A):
        def test(self):
            print("b")
    
    b = B()
    b.test() # b
    

    相关文章

      网友评论

          本文标题:(3) python 面向对象编程

          本文链接:https://www.haomeiwen.com/subject/qnveartx.html