美文网首页
20 类相关

20 类相关

作者: 代码小小白 | 来源:发表于2021-03-02 11:56 被阅读0次

    1.类指针:子类找父类,实例找类都是通过自身携带的类指针去寻找。


    类指针.png

    2.Python3中所有的类都继承于Object类,可以省略不写,Python2不写继承Object类的话就是经典类。新式类和经典类的区别就是继承顺序。

    在下图例子中 类的继承.png

    ① 经典类中是深度优先 :A->B->C->D->E->F
    ② 新式类中是广度优先(继承顺序按照C3算法,了解有这个算法即可):A-B-C-E-F-D
    ③ 在Python中可以利用mro()函数查看类的继承顺序

    3.Python中是有多继承的,Java中只有单继承

    4.多态:
    ① 在python中所有类都是多态的
    ② 在Java中,如果一个函数或者类,需要传入不同的类型B和C,那么B和C必须继承同一个类A,那么我们可以说传入的类型都为A,B和C是类型A表现出来的不同类型。

    5.super方法:
    ① 在单继承中,super就是调用父类的方法

    class User:
        def __init__(self,name):
            self.name = name
    class VIPUser(User):
        def __init__(self,name,level,strat_date,end_date):
            # User.__init__(self,name)
            super().__init__(name)              # 推荐用法
            # super(VIPUser,self).__init__(name)
            self.level = level
            self.strat_date = strat_date
            self.end_date = end_date
    

    ② 在多继承中就是,按照mro的顺序寻找下个类中的同名方法

    class A(object):
        def func(self):
            print('A')
    class B(A):
        def func(self):
            super().func()
            print('B')
    class C(A):
        def func(self):
            super().func()
            print('C')
    class D(B,C):
        def func(self):
            super().func()
            super(D,self).func()
            print('D')
    
    # 分析:D().func(),先搞清mro的顺序D->B->C->A->obj
    # A-C-B-A-C-B-D
    

    6.封装:
    ① 在类的静态变量,实例变量,实例方法加上两个下划线,就会变成私有的

    class User:
         __Country = 'China'   # 私有的静态变量
         __Role = '法师'   # 私有的静态变量
         def func(self):
             print(self.__Country)  # 在类的内部使用的时候,自动的把当前这句话所在的类的名字拼在私有变量前完成变形
    print(User._User__Country)
    print(User._User__Role)
    # __Country -->'_User__Country': 'China'
    # __Role    -->'_User__Role': '法师'
    # User.__aaa = 'bbb'  # 在类的外部根本不能定义私有的概念
    

    ② 私有的变量不能被子类使用

    7.property,setter,deleter装饰器
    ① property装饰器,把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值。什么时候用@property装饰器呢?举个例子,在一个圆形类中,有属性半径r,有函数area,这个函数返回的是面积。其实这个面积和半径一样,可以看做这个圆形类中的一个属性,那么这个时候就可以用@property装饰器。

    from math import pi
    class Circle:
        def __init__(self,r):
            self.r = r
    #     @property   # 把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值
        def area(self):
            return pi * self.r**2
    c1 = Circle(5)
    print(c1.r)
    print(c1.area)
    

    ② setter deleter装饰器

    class Goods:
        discount = 0.8
        def __init__(self,name,origin_price):
            self.name = name
            self.__price = origin_price
        @property
        def price(self):
            return self.__price * self.discount
    
    # @后面的名字必须和函数名字相同
        @price.setter
        def price(self,new_value):
            if isinstance(new_value,int):
                self.__price = new_value
    
        @price.deleter
        def price(self):
            del self.__price
    apple = Goods('apple',5)
    print(apple.price)
    apple.price = 'ashkaksk' # 调用了@price.setter装饰的方法
    del apple.price   # 并不能真的删除什么,只是调用对应的被@price.deleter装饰的方法而已
    print(apple.price)
    

    8.反射
    概念:用字符串数据类型的名字 来操作这个名字对应的函数\实例变量\绑定方法\各种方法
    常见的反射:
    ① 反射对象的 实例变量/绑定方法
    ② 反射类的 静态变量/其他方法
    ③ 模块中的 所有变量(被导入模块和本模块)

    # 反射
    import sys
    # getattr, hasattr
    
    class Person:
        Role = "法师"
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        @staticmethod
        def sing():
            return "我唱歌"
    
    
    xm = Person(name="xiaoming", age=18)
    
    # 访问对象xm的实例方法
    name1 = xm.name
    name2 = getattr(xm, "name") # 通过字符串的方法去访问
    role = getattr(Person, "Role") # 通过字符串访问类的静态属性
    s = getattr(Person, "sing") # 通过字符串访问类的静态方法
    print(name1, name2, role, s())
    
    def pig():
        print('小p')
    # 反射本模块的中的函数,如果是反射其他模块的,只需把第一个参数换成模块名
    getattr(sys.modules['__main__'], "pig")()
    

    9.两个装饰器 @classmethod 和 @staticmethod
    ① @classmethod :把一个对象绑定的方法 修改成一个 类方法

    # 可以通过类名.方法名的方式调用,也可以实例.方法名的方式调用
    # 什么时候用:我的理解是在在方法内部需要用到类名的时候
    
    # 下面例子通过已知分数查看学生的level属性,在handle_score函数中直接返回了Students的对象,用到了类名,所以这时候用@classmethod
    class Students:
        def __init__(self, name, age, level):
            self.name = name
            self.age = age
            self.level = level
    
        @classmethod
        def handle_score(cls, name, age, score):
            if score >= 60:
                return cls(name, age, "及格")
            else:
                return cls(name, age, "不及格")
    
    stu = Students.handle_score("小明", 18, 60)
    print(stu.level)
    

    ② @staticmethod:被装饰的方法会成为一个静态方法,这种常常是因为为了代码结构的完整性,将用不到self和cls的函数写在类中。

    10.Python中的一些魔法方法

    # __call__
    # 一个对象如果是callable的,那么这个对象一定有__call__属性
    class A:
        def __call__(self, *args, **kwargs):
            print('!!!-------')
    A()()  #  调用A的实例中的 __call__ 方法,输出:!!!-------
    
    # __len__
    # 如果想通过len(obj)的方式去获取一个实例中参数的个数,那么这个类中一定要实现__len__方法
    class Cls:
        def __init__(self,name):
            self.name = name
            self.students = []
        def len(self):
            return len(self.students)
        def __len__(self):
            return len(self.students)
    py22 = Cls('py22')
    py22.students.append('杜相玺')
    py22.students.append('庄博')
    py22.students.append('大壮')
    print(py22.len()) # 执行类中__len__方法
    print(len(py22)) #执行类中__len__方法
    
    #__new__
    #负责创建类的实例,并且先于__init__方法执行(通常情况下是使用 super(类名, cls).new(cls,参数1,参数2 …) 这样的方式)
    # __new__创建的实例,就是init中self的空间地址,也是类的实例对应的空间地址。
    #__new__的作用主要有两个,一个是补充init无法实现的功能,另外一个是实现函数的单例模式
    
    #单例模式
    class Baby:
        __instance = None
        def __new__(cls, *args, **kwargs):
            if cls.__instance is None:
                cls.__instance = super().__new__(cls)
            return cls.__instance
        def __init__(self,cloth,pants):
            self.cloth = cloth
            self.pants = pants
    b1 = Baby('红毛衣','绿皮裤')
    print(b1.cloth)
    b2 = Baby('白衬衫','黑豹纹')
    print(b1.cloth)
    print(b2.cloth)
    
    #__str__和__repr__ 方法
    # 在打印一个对象的时候 调用__str__方法
    # 在%s拼接一个对象的时候 调用__str__方法
    # 在str(一个对象)的时候 调用__str__方法
    # 如果找不到__str__,就调用__repr__方法
    # __repr__不仅是__str__的替代品,还有自己的功能
    # 用%r进行字符串拼接 或者用repr(对象)的时候总是调用这个对象的__repr__方法
    
    class clas:
        def __init__(self):
            self.student = []
        def append(self,name):
            self.student.append(name)
        def __repr__(self):
            return str(self.student)
        def __str__(self):
            return 'aaa'
    
    py22 = clas()
    py22.append('大壮')
    print(py22) # aaa
    print(str(py22)) # aaa
    print('我们py22班 %s'%py22) # 我们py22班 aaa
    print('我们py22班 %r'%py22) # 我们py22班 [大壮]
    print(repr(py22))  # 我们py22班 [大壮]
    

    相关文章

      网友评论

          本文标题:20 类相关

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