码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-12-17 12:03:44      阅读:2      评论:0      收藏:0      [点我收藏+]

标签:语言   删除对象   turn   默认   cep   utf8   txt   面向对象   输出   

一、上下文管理器

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: 属性不存在
"""

 

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

标签:语言   删除对象   turn   默认   cep   utf8   txt   面向对象   输出   

原文地址:https://www.cnblogs.com/zhangjx2457/p/14104993.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!