• 七、上下文管理器/魔术方法


    一、上下文管理器

    python的上下文管理协议:包含__enter__() 、__exit__()方法

    上下文管理器:支持"上下文管理协议"的对象

    with 语句操作上下文管理器对象:

    with object as o:
            pass

    其中:

    • with后的object是上下文管理器的对象;o是__enter__()的返回值

    • 在执行with里的语句之前,先执行__enter__(),再执行with中的语句,最后执行__exit__()

    # 自定义上下文管理器
    class MyClass(object):
    
        def __enter__(self):
            print("enter is running...")
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("exit is running...")
    
    def main():
        # 实例对象
        obj = MyClass()
        with obj as o:
            print("with is running...")
    
    if __name__ == '__main__':
        main()
    
    """
    enter is running...
    with is running...
    exit is running...
    """

    常见的上下文管理器:

    with open("text.txt","w",encoding="utf8") as f:
        f.write("hello world")

    open能够被with操作:

    f = open("上下文管理器.txt") 
    print(dir(f))
    
    """
    ... ,'__enter__', '__eq__', '__exit__', ...
    """
    # open()的返回值f是一个上下文管理器,所以可以被with操作

    注意:不是上下文管理器,不能被with操作

    with 1 as o:
        print"hello""""
        with 1 as o:
    AttributeError: __enter__
    """

    一个对象不是上下文管理器,怎么变成上下文管理器?

    在继承的新的类中,添加__enter__() 、__exit__()方法 

    class Base(object):
        pass
    
    class MyBase(Base):
        def __enter__(self):
            pass
        def __exit__(self, exc_type, exc_val, exc_tb):
            pass
    
    def main():
        obj = MyBase()
        with obj as o:
            print('with is running....')
    
    if __name__=="__main__":
        main()

    二、魔术方法

    在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”(魔术方法)

    参考转载自:https://www.cnblogs.com/nmb-musen/

    参考转载自:https://www.cnblogs.com/pyxiaomangshe/p/7927540.html

    1)__str__ 

    当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印这个方法中return的数据 

    __str__方法需要返回一个字符串 

    不写__str__()方法,默认继承object的str方法,返回的是存储地址

    class MyClass(object):
    
        def __init__(self,name):
            self.name = name
    
    
    def main():
        a = MyClass("zjx")
        print(a)
    
    if __name__ == '__main__':
        main()  # <__main__.MyClass object at 0x000001B57D0BEC88>

    重写__str__()

    class MyClass(object):
    
        def __init__(self,name):
            self.name = name
    
        def __str__(self):
            print("__str__ is running...")
            return self.name
    
    
    def main():
        obj = MyClass("zjx")
        print(obj)
    
    if __name__ == '__main__':
        main()  
    
    """
    __str__ is running...
    zjx
    """

    2.__add__

    自定义的类生成的对象(实例)能够使用运算符操作

    def main():
        a = [1, 2]
        b = [3, 4]
        return a + b
    
    if __name__ == '__main__':
       print(main()) # [1, 2, 3, 4]

    思考:为什么list能够相加?因为list含有__add__属性

    def main():
        a = [1, 2]
        b = [3, 4]
        print(hasattr(a,"__add__"))  # True
        return a + b
    
    if __name__ == '__main__':
       print(main())

    对象没有__add__属性,进行相加会报错

    class MyClass(object):
        pass
    
    def main():
        obj1= MyClass()
        obj2 = MyClass()
        return  obj1 + obj2
    
    if __name__ == '__main__':
        print(main()) 
    
    '''
    TypeError: unsupported operand type(s) for +: 'MyClass' and 'MyClass'
    '''

    对象添加__add__属性;

    class MyClass(object):
        def __init__(self, value):
            self.value = value
    
        def __add__(self, other):
            return self.value + other.value 
    
    
    def main():
        obj1 = MyClass(1)  
        obj2 = MyClass(2)
        return  obj1 + obj2
    
    if __name__ == '__main__':
        print(main())  # 3

    # obj1是self obj2是other

    3.__del__

     python解释器自动删除对象,释放内存

    class MyClass(object):
        def __init__(self):
            print("init is running...")
    
        def __new__(cls, *args, **kwargs):
            print("new is running...")
            instance = super().__new__(cls)
            return instance
    
        def __del__(self):
            print("del is running...")
    
    def main():
        obj1 = MyClass()
        obj2 = MyClass()
    
    if __name__ == '__main__':
        main()
        print("main() is running...")
    
    """
    new is running...
    init is running...
    new is running...
    init is running...
    del is running...
    del is running...
    main() is running...
    """

    del关键字手动删除

    class MyClass(object):
        def __init__(self):
         # 构造 初始化
    print("init is running...") def __new__(cls, *args, **kwargs):
         # 创建对象、分配内存      print("new is running...") instance = super().__new__(cls) return instance
    def __del__(self): 
         # 销毁对象 java里叫‘’析构 print("del is running...") def main(): obj1 = MyClass() obj2 = MyClass() del obj1 del obj2

    4.多态

    面向对象的三大特征:封装、继承、多态

    多态就是在子类中重写父类的方法,作用是同样名称的方法在不同的子类中会有不同的行为。

    class MyClass(object):
    
        def music(self):
            print("myclsss music is running...")
    
    class AClass(MyClass):
        def music(self):
            print("Aclass music is running...")
    
    class BClass(MyClass):
        def music(self):
            print("Bclass music is running...")
    
    def func(obj):
        obj.music()  # 只要这个对象有music方法,就会正常调用
    
    if __name__ == '__main__':
        m = MyClass()
        a = AClass()
        b = BClass()
       #上面三个对象都有music方法,都可以正常调用该方法
        func(a)
        func(b)
        func(m)
    
    """
    Aclass music is running...
    Bclass music is running...
    myclsss music is running...
    """

    5.鸭子类型

    python不支持多态也用不到多态,多态的概念是应用于java和C#这一类强类型语言中,而Python崇尚鸭子类型(Duck Typing)

    一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

    不管什么类型,只要有核心的功能。就可以是鸭子类型

    当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。” 在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型。

    class Animal(object):
        def run(self):
            print("animal is running...")
    
    class Cat(Animal):
        def run(self):
            print("cat is running...")
    
    class Dog(Animal):
        def run(self):
            print("dog is running...")
    
    class Person(object):
        def run(self):
            print("person is running...")
    
    def canrun(obj):   # 只要obj含有run()方法,就是个鸭子类型
        obj.run()
    
    if __name__ == '__main__':
        canrun(Animal())
        canrun(Cat())
        canrun(Person())
    
    """
    animal is running...
    cat is running...
    person is running...
    """

    6.类方法的使用

    类方法是为了创建对象

    # 类方法创建对象
    class Person(object):
    
        def __init__(self, first_name, last_name):
            self.first_name = first_name
            self.last_name = last_name
    
        @classmethod
        def teacher(cls,full_name):
            # 类方法,扩展一个创建对象的方式
            first_name, last_name = map(str, full_name.split(" "))
            obj = cls(first_name, last_name)
            return obj
    
    if __name__ == '__main__':
        # 普通方式创建对象
        zhangsan = Person("san", "zhang")
        print(zhangsan.first_name)
    
        # 类方法创建对象 使用类方法后,多了一种创建对象的方法
        teacher = Person.teacher("si li")
        print(teacher.first_name)
        print(teacher.last_name)

    7.__getitem_

    有__getitem__方法的对象才能用[ ]操作

    在类中定义了这个__getitem__ 方法,那么它的实例对象obj,可以obj[key] 取值,当实例对象做obj[key] 运算时,会调用类中的方法__getitem__

    class MyClass(object):
    
        def __init__(self):
            self.items = [1, 2, 3]
    
        def __getitem__(self, item):
            return self.items[item]
    
    if __name__ == '__main__':
        myclass = MyClass()
        print(myclass[0])  # 1
        print(myclass[1])  # 2
        print(hasattr(myclass, "__getitem__"))  # True
    
    print(hasattr(list, "__getitem__"))  # True
    print(hasattr(tuple, "__getitem__")) # True

    8.__getattr__

    __getattr__方法,对象没有该属性而调用该属性时,会报系统内置的属性错误信息 

    class Myclass(object):
        def __init__(self,name):
            self.name = name
    
    if __name__ == '__main__':
        A = Myclass("zhangsan")
        print(A.value)   # AttributeError: 'Myclass' object has no attribute 'value'

    添加__getattr__方法,执行调用对象的属性,而对象无此属性时,会调用__getattr__方法

    class Myclass(object):
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self, item):
            return 1
    
    if __name__ == '__main__':
        A = Myclass("zhangsan")
        print(A.value)     # 1     对象A并没有value属性,但是输出的是__getattr__的返回值

    重写__getattr__方法,自定义报错信息

    class MyAttributionError(Exception):
        def __init__(self,msg = "属性不存在"):
            super().__init__(self)
            self.msg = msg
    
        def __str__(self):
            return self.msg
    
    class Myclass(object):
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self, item):
            raise MyAttributionError
    
    if __name__ == '__main__':
        A = Myclass("zhangsan")
        print(A.value)
    
    """
        raise MyAttributionError
    __main__.MyAttributionError: 属性不存在
    """
  • 相关阅读:
    尾递归
    gcc/g++ 命令
    GCC输出带C源代码的汇编文件
    linux下Ctrl命令组合
    静态链接库(lib)、动态链接库(dll)与动态链接库的导入库(lib)
    VS2010-MFC(菜单:菜单及CMenu类的使用)
    VS2010-MFC(菜单:VS2010菜单资源详解)
    VS2010-MFC(常用控件:标签控件Tab Control 下)
    VS2010-MFC(常用控件:标签控件Tab Control 上)
    VS2010-MFC(常用控件:树形控件Tree Control 下)
  • 原文地址:https://www.cnblogs.com/zhangjx2457/p/14104993.html
Copyright © 2020-2023  润新知