• 深入类和对象


     
     
    1. 鸭子类型
    鸭子类型:多个类都有一个相同的方法,我们可以分别实例化一个对象,定义另外一个函数统一调用多个类中的相同方法
    class Person:
        def walk(self):
            print("i walk use my foot")
     
    class Bird:
        def walk(self):
            print("i walk use my foot too")
     
    jack = Person()
    chiken = Bird()
     
    def move(arg):
        arg.walk()
     
    move(jack)
    move(chiken)
    输出
    i walk use my foot
    i walk use my foot too
     
     
    2. 抽象基类(abc类),了解就好
    特点:抽象基类不能实例化;继承类必须重写抽象基类中的方法
    python中有一个函数hasattr(),用于判断对象中是否有某个函数,例如
    print(hasattr(b,"__init__")),若返回True,表示b有__init__函数
     
    抽象基类用途1:判断对象的类型
    isinstance()可用于判断一个对象是否为指定的类型,例如抽象基类Sized
    from collections.abc import Sized
    isinstance(b, Sized)
     
    用途2:强制某个子类必须实现某些方法
     
     
     
    3. isinstance 和 type的区别
    class A:
        pass
     
     
    class B(A):
        pass
     
    b = B()
     
    print(isinstance(b, B))
    print(isinstance(b, A))
    print(type(b))
    输出:
    True
    True
    <class '__main__.B'>
     
     
     
    4. is和"=="
    is用于判断2个对象内存地址是否相同,也就是id是否相同;==用于判断2个对象的value值是否相同
    a=[1,2,3]
    b=[1,2,3]
    print(a is b)
    print(a==b)
    输出
    False
    True
     
    注意:
    当对象是比较小的int或者string类型时,为了提高内存利用效率,python采取重用对象内存的办法,此时a is b是True;
    当a和b是tuple,list,dict或set型时,python都会给a,b重新分配内存地址,所以a is b为False
     
     
    5. 类变量和类的实例变量
    class A:
        aa = 1
        def __init__(self, x, y):
            self.x = x
            self.y = y
    a = A(2, 3)
    A.aa = 11
    a.aa = 100
    print(a.x, a.y, a.aa)
    print(A.aa)
    输出
    2 3 100
    11
    说明
    aa:是类变量;
    self是实例,self.x, self.y 中的x, y为实例变量
    A.aa = 11修改了A类的aa属性
    a.aa = 100 相当于给__init__()增加了一个变量self.aa=100,并不影响原先类的属性aa
     
     
     
    6. 复杂的继承关系中,类和实例属性的查找顺序,可用__mro__函数查找
    class D():
        pass
     
    class C(D):
        pass
     
    class B(D):
        pass
     
    class A(B, C):
        pass
     
    print(A.__mro__)
    输出
    (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
    也就是先查找A中的属性,然后是B, C, D, object
     
     
     
    7. 类方法,静态方法,实例方法。静态方法和类方法相当于在__init__之前对数据做一个预处理
    class Date:
        def __init__(self, year, month ,day):
            self.year = year
            self.month = month
            self.day = day
     
        def __str__(self):
            return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)
     
        @staticmethod
        def parse_from_string(date_str):
            year, month, day = tuple(date_str.split("-"))
            return Date(int(year), int(month), int(day))
     
        @classmethod
        def from_string(cls, date_str):
            year, month, day = tuple(date_str.split("-"))
            return cls(int(year), int(month), int(day))
     
        @staticmethod
        def valid_str(date_str):
            year, month, day = map(int, date_str.split("-"))
            if year > 0 and month > 0 and month <= 12 and day > 0 and day <= 31:
                return True
            else:
                return False
     
    if __name__ == "__main__":
        date1 = Date(2018, 7, 2)
        print(date1)
     
        # 静态方法
        date_str = "2018-12-3"
        date2 = Date.parse_from_string(date_str)
        print(date2)
     
        # 类方法
        date3 = Date.from_string(date_str)
        print(date3)
        
        # 不需要返回类时,使用静态方法好些
        date4 = Date.valid_str("2018-13-2")
        print(date4)
    输出
    2018/7/2
    2018/12/3
    2018/12/3
    False
     
    说明:
    1)参数中有self的方法都是实例方法,其中的self表示实例对象
    2) 如果 import 一个模块,那么模块__name__ 的值通常为模块文件名,不带路径或者文件扩展名。如果直接运行模块,__name__ 的值等于特别缺省值"__main__"。
    3) tuple可以解包
    >>> date = "2018-4-5"
    >>> date.split("-")
    ['2018', '4', '5']
    >>> year, month, day = tuple(date.split("-"))
    >>> year
    '2018'
    提取字段也可以用map来实现,更方便,map也就是映射,把一组元素按照一个函数映射成另一组元素
    >>> year1, month1, day1 = map(int, date.split("-"))
    >>> year1
    2018
     
    4)静态方法的缺陷是函数内return语句要调用类的名字,如果类的名字变化,静态方法也要修改,也就是通常说的硬编码。可使用class method解决这个缺陷,可以说类方法是静态方法的升级版,功能很相似
    5)类方法中的参数cls代表类本身,其中cls并不是非要这么写,也可改成其他字符。实例方法中的参数self也是可以修改的
     
     
     
     
    8. 数据封装和私有属性
    在上面类的基础上新加一个类User, 如下.  实现隐藏具体生日信息,只能得到年龄的数据
    class User:
        def __init__(self, birthday):
            self.__birthday = birthday
     
        def get_age(self):
            return 2018 - self.__birthday.year
     
    if __name__ == "__main__":
        user = User(Date(1990, 2, 1))
        print(user.get_age())
        print(user._User__birthday)
    输出
    28
    1990/2/1
     
    说明:
    1)以双下划线开头的变量是私有变量,不能用对象名+变量名直接调用,如果用user.__birthday的话会报错
    2)但是可以通过类中的公有函数来调用
    3)其实在python内部是把私有变量做了一个变形,"__属性名"变成"_类名__属性名".
     
     
     
    9. python对象的自省机制,也就是通过一些方法查询对象的内部结构
    class Person:
        name = "jack"
     
    class Student(Person):
        """
        继承Person类
        """
        def __init__(self, school_name):
            self.school_name = school_name
     
    if __name__ == "__main__":
        user = Student("北大")
     
        # 通过__dict__查询属性
        print(user.__dict__)
        print(Student.__dict__)
     
        # 通过__dict__设置属性
        user.__dict__["school_addr"] = "北京市"
        print(user.school_addr)
     
        # dir()获取对象的方法名和属性名
        print(dir(Person))
        print(dir(user))
    输出
    {'school_name': '北大'}
    {'__module__': '__main__', '__doc__': '     继承Person类     ', '__init__': <function Student.__init__ at 0x000001C82CC05510>}
    北京市
    ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
    ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'school_addr', 'school_name']
     
    说明:
    1)__dict__可查看对象的属性和值,同时也能给对象定义新属性和值
    2)python中字典是用c编写实现的,很多python的内部结构的数据都是用字典来编写存储的
    3)dir()可查看对象的方法和属性名,不能查看其值
    4)如果对象不是类,而是列表,那么是不能用__dict__的,只能用dir. 比如a=[1,2], 使用a.__dict__会报错
     
     
     
    10. super函数,真的就是调用父类么
    class A:
        def __init__(self):
            print("A")
     
    class B(A):
        def __init__(self):
            print("B")
            super().__init__()
     
    class C(A):
        def __init__(self):
            print("C")
            super().__init__()
     
    class D(B, C):
        def __init__(self):
            print("D")
            # 参数中B在C的前面,所以会先调用B
            super().__init__()
     
     
    if __name__ == "__main__":
        print(D.__mro__)
        d = D()
    输出
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    D
    B
    C
    A
    说明:
    如果super函数就是调用父类,那么输出结果的前三个应该是D, B, A,但经验证是D, B, C, A。 也就是和类的__mro__属性顺序一致
     
     
     
     
    11. mixin 模式特点
    1) mixin类功能单一
    2)不和基类关联,可以和任意基类组合,基类可以不和mixin关联就能初始化成功
    3)在mixin中不要使用super这种用法
     
     
     
     
    12. with语句--上下文管理器,用于简化程序
     
    里面包括两个魔法函数__enter__和__exit__
    class Sample:
        def __enter__(self):
            print("enter")
            # 获取资源
            return self
     
        def __exit__(self, exc_type, exc_val, exc_tb):
            # 释放资源
            print("exit")
     
        def do_something(self):
            print("doing sth")
     
    with Sample() as sample:
        sample.do_something()
     返回结果
    enter
    doing sth
    exit
     
     python中内置了一个contextmanager,可以把函数变成上下文管理器,进一步简化代码
    import contextlib
     
    @contextlib.contextmanager
    def file_open(filename):
        print("file open")
        yield {}
        print("file end")
     
    with file_open("1.txt") as sample:
        print("file processing")
    输出结果
    file open
    file processing
    file end
    其中yield上面的print相当于__enter__,下面的print相当于__exit__
  • 相关阅读:
    省选模拟64
    省选模拟63
    杂题
    省选模拟62
    省选模拟61
    省选模拟60
    省选模拟58
    IntelliJ IDEA配置tomcat【全程详解】
    java之 Timer 类的简单使用案例
    Intellij IDEA导入Github中的MAVEN多模块项目【保持项目样式】
  • 原文地址:https://www.cnblogs.com/regit/p/9881131.html
Copyright © 2020-2023  润新知