python-reflection/built-in method/descriptor/secondary packaging

table of Contents

 

A reflection

Two built-in functions

 1、isinstance(obj,cls)和issubclass(sub,super)

isinstance(obj,cls) checks whether obj is an object of class cls

2、__setattr__,__delattr__,__getattr__

3、__getattribute__

4、__format__

5、__doc__

6 、 __ of__

Three descriptors (descriptor)

1. The essence of the descriptor

2. The role of descriptors

3. Examples

4. There are two types of descriptors

5. Matters needing attention:

6. Application of Descriptor

Four secondary processing standard type

package

Five __enter__ and __exit__


A reflection

In python, you can manipulate the attributes of objects in the form of strings. This behavior is called reflection in python

It can map strings to instance variables or instance methods and then perform operations such as invocation and modification.
Here are the four basic methods of reflection:

  • getattr Get the object attribute of the specified string name This function returns the value of the attribute or the memory address of the method
  • setattr sets an object for the object setattr(x,y,v) Note that the second parameter is a string, and the third parameter is the value of the attribute to be set or the form of the method
  • hasattr judges whether the object has a corresponding object (string) hasattr(object,name) returns True if it exists, and returns False if it does not exist.
  • delattr delete the specified attribute delattr(x,y) Note that the second parameter is a string, if the deleted does not exist, an error will be reported

 Use range:

  1. Objects and classes
  2. Reflection of current module memberssys.modules[__name__]  #sys.modules查看所有被导入的模块,以字典的形式存储
  3. Reflection of other file modules import incoming modules

Two built-in functions

 1、isinstance(obj,cls)和issubclass(sub,super)

isinstance(obj,cls) checks whether obj is an object of class cls

class Foo:

    pass

obj = Foo()

print(isinstance(obj,Foo)) #输出结果 True

issubclass(sub, super) checks whether the sub class is a derived class of super

class Foo(object):

    pass

class Son(Foo):

    pass

print(issubclass(Son,Foo))  #输出结果True

print(issubclass(Foo,object)) #输出结果True

2、__setattr__,__delattr__,__getattr__

__setattr___Adding/modifying attributes will trigger its execution

__delattr___It will be triggered when the attribute is deleted

__getattr__It will only be triggered when the attribute is called using the point and the attribute does not exist, and it will not be triggered when the existing attribute or method is called

class Foo():
​
    def __init__(self,name):
        self.name = name
​
    def func(self):
        print("func------")
​
​
    def __delattr__(self, item):
        print("执行__delattr__")
        # del self.item #无限递归
        self.__dict__.pop(item)
​
    def __setattr__(self, key, value):
        print("执行__setattr__")
        # self.key=value #进入无限递归
        self.__dict__[key]=value #应该使用它
​
p = Foo("jack")  #实例化的过程中会增加属性,执行__setattr__,执行self.__dict__[key]=value语句,为name属性赋值
print(p.name)  #
p.age = 18   #执行__setattr__方法,对象新增加属性
print(p.__dict__)  #输出结果{'name': 'jack', 'age': 18}
del p.age  #调用__delattr__方法,删除对象的age属性
print(p.__dict__) #输出结果{'name': 'jack'},此时已经不包含age属性


输出:
执行__setattr__
jack
执行__setattr__
{'name': 'jack', 'age': 18}
执行__delattr__
{'name': 'jack'}
class Foo():
     def __init__(self,name):
         self.name = name
 ​
     def func(self):
         print("func------")
 ​
     def __getattr__(self, item):
         print("执行__getattr__",item)
 ​
 p = Foo("jack")  #实例化的过程中会增加属性,
 print(p.__dict__)
 print(p.name)
 print(p.age)  #调用不存在的属性会执行__getattr__

输出:
{'name': 'jack'}
jack
执行__getattr__ age
None

3、__getattribute__

object.__getattribute__(self, name)    Access properties through the instance, unconditionally called

Every time you access a property through an instance , you go through a __getattribute__function.

When the attribute does not exist, it still needs to be accessed __getattribute__, but then it needs to be accessed __getattr__. This is like an exception handling function. It should be noted that when using a class to access a variable that does not exist, it will not go through the __getattr__function.

When the attribute exists, the __getattribute__function returns the value of the attribute.

class Foo:
​
    def __init__(self,x):
        self.x = x
​
    def __getattr__(self, item):
        print("执行__getattr__")
​
    def __getattribute__(self, item):
        print("执行__getattribute__")
        # raise AttributeError("不存在的异常")
​
f = Foo("nick")
print(f.x)
print(f.xxxx)#

输出:
执行__getattribute__
None
执行__getattribute__
None

Note: After calling f.xxxx, AttributeError should be generated in __getattribute__, and then __getattr__ should be called, but #here __getattribute__ is overwritten and no AttributeError is generated, so __getattr__ is not called

In other words, the call of __getattr__ generates AttributeError exception through __getattribute__

4、__format__

Custom format string

format_dic = {
    "ymd":"{0.year}{0.month}{0.day}",
    "dmy":"{0.day}:{0.month}:{0.year}",
    "mdy":"{0.month}-{0.day}-{0.year}"
}
​
class Foo:
​
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
​
    def __format__(self, format_spec):
        if not format_spec or format_spec not in format_dic:
            format_spec = "ymd"
        fmt = format_dic[format_spec]
        return fmt.format(self)
​
f = Foo(2018,8,20)
print(format(f))
print(format(f,"dmy"))
print(format(f,"mdy"))
print("{:mdy}".format(f))

输出:
2018820
20:8:2018
8-20-2018
8-20-2018

5、__doc__

class Foo:
    """
    我是文档注释
    """
    pass
​
f = Foo()
print(f.__doc__) #输出结果 :    我是文档注释

6、__del__

The destruction method automatically triggers execution when the object is released in memory. That is, the method of clearing and releasing the memory.

This is the method that triggers execution when the instantiated object is recycled. Deleting the properties of the object will not trigger the __del__method.

Usage scenario: 1, del obj 2 When the program ends, the python interpreter automatically reclaims the memory and executes the __del__method

Typical application scenarios:

Create a database class, use this class to instantiate the database link object, the object itself is stored in the user space memory, and the link is managed by the operating system and stored in the kernel space memory

When the program ends, python will only reclaim its own memory space, that is, user-mode memory, but the resources of the operating system are not reclaimed. This requires us to customize __del__and initiate a system call to the operating system to close the database link before the object is deleted. , Recycling resources.

class Foo:
​
    def __del__(self):
        print("我执行了")
​
f = Foo()
f.file  = open("test.txt")   #打开文件,在操作系统中打开了一个文件,
# 拿到了文件操作符存在了内存中
del f.file   #删除了内存中的文件操作符,但是并未关闭操作系统中的文件,
# 这时需要在__del__中加入定制f.file.close(),关闭操作系统的文件
print("-----1")
#最后程序结束python解释器自动执行内存回收,执行了__del__方法

Three descriptors ( descriptor )

(__get__,__set__,__delete__)

Descriptors in python can be used to define the code that triggers automatic execution, which is like a proxy class for object attribute operations (access, assignment, deletion) . The property described earlier is a kind of descriptor.

The general process is like this:

  1. Definition of a descriptor class D, which comprises one or more internal __get__(), __set__(), __delete__()method
  2. Assign the instance object d of the descriptor class D to an attribute attr in another class to be proxied, namelyattr = D()
  3. After the visit, the assignment, remove attr attribute, will automatically trigger descriptor class__get__() , __set__(), __delete__()method

In short, it is to create a descriptor class, and its instance object as an attribute of another class .

It is very simple to define a descriptor class. As long as a certain class contains one or more of the following methods, even if it satisfies the descriptor protocol, it is a descriptor class and can be used as a proxy for attribute operations.

Note also that not to __delete__and __del__confused , the former is a method to realize the protocol descriptor, which is a function of the destruction of the object (often referred destructor).

Regardless of the parameters in these methods, let's look at an example first:

class Descriptor():
    def __get__(self, instance, owner):
        print("self: %s\ninstance: %s\nowner: %s" % (self, instance, owner))

class S:
    # 描述符的示例对象作为S的属性
    attr = Descriptor()

s1 = S()
s1.attr  # 访问对象属性

print("-" * 30)
S.attr   # 访问类属性

result:

self: <__main__.Descriptor object at 0x030C02D0>
instance: <__main__.S object at 0x030C0AB0>
owner: <class '__main__.S'>
------------------------------
self: <__main__.Descriptor object at 0x030C02D0>
instance: None
owner: <class '__main__.S'>

Here __get__(self, instance, owner)are three parameters explained below :

  • self: the descriptor object itself, which is the attribute attr in the proxy class S
  • instance: The instance object of the proxy class. So when accessing the class attribute (class.attr) is None
  • owner: The class to which the descriptor object is attached, which is actually the class to which the instance belongs, that is, type(instance)

Explain the relevant roles here:

  • Descriptor: It is a descriptor class and also an agent
  • S: Is another class, managed class, customer class, that is, the owner in the parameter
  • attr = Descriptor(): Is the instance object of the descriptor, attr is the attribute of the managed class, that is, the self in the parameter
  • s1: Is the instance object of the managed class, that is, the instance in the parameter

1. The essence of the descriptor

Is a new class, in this new class implements at least __get__(), __set__(), __delete__()one of which is also called descriptors protocol.

__get__(): Triggered when an attribute is called

__set__(): Trigger when assigning a value to an attribute

__delete__(): Triggered when the attribute is deleted by del

2. The role of descriptors

It is used to proxy the attributes of another class ( the descriptor must be defined as the class attribute of this class, and cannot be defined in the constructor )

The descriptor is defined in the class attribute of another class , and the descriptor is in the class attribute __dict__dictionary of a class

If the class defines it, then this class can be called a descriptor. Owner is the owner's class, and instance is the instance that accesses the descriptor. If the access is not through the instance, but through the class, the instance is None. ( The instance of descriptor accessing itself will not trigger __get__, but will trigger __call__. Only descriptor as an attribute of other classes is meaningful .)

Descriptor of course, we also need to know if a class only implements __get__()the method, then the class is called the non-data descriptor; if implemented in a class __get__(), and also be implemented in  __set__()and __del__()one of the class data is called Descriptor

3. Examples

After defining a class, you can access, assign values, and delete its attributes. These operations are also applicable to its instance objects.

from weakref import WeakKeyDictionary

class Score():
    """ score should in [0,100] """

    def __init__(self):
        self.score = WeakKeyDictionary()
        #self.score = {}

    def __get__(self, instance, owner):
        return self.score[instance]

    def __set__(self, instance, value):
        if 0 <= value <= 100:
            self.score[instance] = value
        else:
            raise ValueError("score not in [0,100]")


class Student():
    # 托管属性定义在类级别上
    score1 = Score()
    score2 = Score()
    score3 = Score()

    def __init__(self, stuid, name, score1, score2, score3):
        self.stuid = stuid
        self.name = name
        self.score1 = score1
        self.score2 = score2
        self.score3 = score3

    def returnMe(self):
        print(self)
        return "%s, %s, %i, %i, %i" % (
            self.stuid,
            self.name,
            self.score1,
            self.score2,
            self.score3)
if __name__=='__main__':
    stu = Student("20101120", "malong", 67, 77, 88)
    print(stu.returnMe())
    # stu.score1 = -23
    print(stu)
    print(type(stu))


输出:
<__main__.Student object at 0x00000285B03FB390>
20101120, malong, 67, 77, 88
<__main__.Student object at 0x00000285B03FB390>
<class '__main__.Student'>

note: definition of the stu later, Student in class examples of self is so, whether self or stu stu will trigger descriptor class__get__() , __set__(), __delete__()method

class Foo:
​
    def __get__(self, instance, owner):
        print("执行了__get__")
​
    def __set__(self, instance, value):
        print("执行了__set__")
​
    def __delete__(self, instance):
        print("执行了__delete__")
​​
class Bar:
    x = Foo()
​
    def __init__(self,name):
        self.name = name
​
​
b = Bar("nick")
b.x     #调用执行描述符里的__get__方法
print(b.x)  #
b.x = 1  # 调用执行描述符里的__set__方法
print(b.__dict__)
del b.x  #调用执行描述符里的__delete__方法
print(b.__dict__)

输出:
执行了__get__
执行了__get__
None
执行了__set__
{'name': 'nick'}
执行了__delete__
{'name': 'nick'}
#描述符Str
class Str:
    def __get__(self, instance, owner):
        print('Str调用')
    def __set__(self, instance, value):
        print('Str设置...')
    def __delete__(self, instance):
        print('Str删除...')
​
#描述符Int
class Int:
    def __get__(self, instance, owner):
        print('Int调用')
    def __set__(self, instance, value):
        print('Int设置...')
    def __delete__(self, instance):
        print('Int删除...')
​
class People:
    name=Str()
    age=Int()
    def __init__(self,name,age): #name被Str类代理,age被Int类代理,
        self.name=name
        self.age=age
​
#何地?:定义成另外一个类的类属性
​
#何时?:且看下列演示
​
p1=People('alex',18)
​
#描述符Str的使用
p1.name
p1.name='egon'
del p1.name
​
#描述符Int的使用
p1.age
p1.age=18
del p1.age
​
#我们来瞅瞅到底发生了什么
print("__p1.__dict__",p1.__dict__)
print(People.__dict__)
​
#补充
print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
print(type(p1).__dict__ == People.__dict__)

输出:
Str设置...
Int设置...
Str调用
Str设置...
Str删除...
Int调用
Int设置...
Int删除...
__p1.__dict__ {}
{'__module__': '__main__', 'name': <__main__.Str object at 0x021C6850>, 'age': <__main__.Int object at 0x021C6870>, '__init__': <function People.__init__ at 0x021C5DB0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
True
True

note: When the descriptor and the constructor have the same name, call the descriptor

4. There are two types of descriptors

(1) Data descriptor: at least achieve __get__()and__set__() 

(2) Non-data descriptor: not implemented__set__() 

 Note: Non-data descriptors generally only have __get__, and if you keep __delete__, an error will be reported.

5. Matters needing attention:

(1) The descriptor itself should be defined as a new-style class, and the class being proxied should also be a new-style class (all new-style classes in python3)

(2) The descriptor must be defined as a class attribute of another class, and cannot be defined in the constructor,

(3) The priority must be strictly followed, and the priorities from high to bottom are

a. Class attribute b. Data descriptor c. Instance attribute d. Non-data descriptor e. Cannot find attribute trigger__getattr__()

   class Foo:
​
    def __get__(self, instance, owner):
        print("执行了__get__")
​
    def __set__(self, instance, value):
        print("执行了__set__")
​
    def __delete__(self, instance):
        print("执行了__delete__")
​
class People1:
​
    name = Foo()
​
    def __init__(self,name):
        self.name = name

p = People1("nick")        #执行__init__后执行__set__
print(People1.__dict__)    #{'__module__': '__main__', 'name': <__main__.Foo2 object at 0x00000157D73AD208>, '__init__': <function People1.__init__ at 0x00000157D72ED378>, '__dict__': <attribute '__dict__' of 'People1' objects>, '__weakref__': <attribute '__weakref__' of 'People1' objects>, '__doc__': None}
print(People1.name)    # 执行了__get__     None
print(p.__dict__)        #{}
People1.name = "NICK"  # 调用执行了描述符的__set__方法,这一步类属性由之前的描述符被定义成另外一个字符串,
 # 所以下面再次调用就无法再次使用描述符了
print(People1.name)    #NICK
print(p.__dict__)      #{}
print(People1.__dict__)  #{'__module__': '__main__', 'name': 'NICK', '__init__': <function People1.__init__ at 0x00000157D72ED378>, '__dict__': <attribute '__dict__' of 'People1' objects>, '__weakref__': <attribute '__weakref__' of 'People1' objects>, '__doc__': None}

NOTE: It can be concluded that the priority of the class attribute is greater than the data descriptor

class Foo:
​
    def __get__(self, instance, owner):
        print("执行了__get__")
​
    def __set__(self, instance, value):
        print("执行了__set__")
​
    def __delete__(self, instance):
        print("执行了__delete__")
​
class People:
​
    name = Foo()
​
    def __init__(self,name):
        self.name = name
​
​
p = People("nick")  #实例化对象,调用数据描述符的__set__,
# 但是由于描述符的__set__只是执行了打印操作,什么都没做,所以p对象的__dict__什么都没有
p.name = "nicholas"
print(p.__dict__) #输出的结果为空

NOTE: Therefore, it can be concluded that the priority of the data descriptor is greater than the instance attribute (dictionary operation)

class Foo(object):
    def __init__(self):
        pass
​
    def __get__(self, instance, owner):
        print("执行了__get__")
​
class People(object):
​
    name = Foo("x")
​
    def __init__(self,name,age):
        self.name = name
        self.age = age
​
​
​
p = People("nick",18)  #实例化对象,这里由于是非数据描述符,优先级低于实例属性,
# 所以这里直接设置了实例属性,而不再调用描述符
print(p.name)  #打印直接输出实例属性
print(p.__dict__)
#输出的结果:{'name': 'nick', 'age': 18}

NOTE: It can therefore be concluded that the priority of instance attributes is greater than that of non-data descriptors

class Foo(object):
    def __init__(self,name2):
        self.name2 = name2
​
    def __get__(self, instance, owner):
        print("执行了__get__")
​
​
class People(object):
​
    name = Foo("x")
​
    def __init__(self,name,age):
        self.name = name
        self.age = age
​
    def __getattr__(self, item):
        print("__getattr__")
​
​
p = People("nick",18)  #实例化对象,这里由于是非数据描述符,优先级低于实例属性,
# 所以这里直接设置了实例属性,而不再调用描述符
print(p.name)
print(p.sex)  #调用不存在的属性执行了__getattr__
print(p.__dict__)
#输出的结果:{'name': 'nick', 'age': 18}

6. Application of Descriptor

class Type:
​
    def __init__(self,key,expect_type):
        self.key = key
        self.expect_type = expect_type
​
    def __get__(self, instance, owner):
        print("执行__get__方法")
        print(self)                #这里的self就是type类的对象
        print(instance)            #这里的instance就是传入的People类的对象
        print("执行__get__方法")
        return  instance.__dict__[self.key]   #通过instance的字典获取对象的属性值
​
    def __set__(self, instance, value):
        print("执行__set__方法")
        instance.__dict__[self.key] = value   #instance是另一个类的对象,这里要设置对象的属性字典
​
    def __delete__(self, instance):
        print("执行__delete__方法")
        instance.__dict__.pop(self.key)  #删除对象的属性
​
class People:
    name = Type("name",str)
    age = Type("age",int)
​
    def __init__(self,name,age):
        self.name = name
        self.age = age
​
p1 = People("nick",18)  #调用2次描述符,对对象的字典进行设置
print(p1.name)  #通过数据描述符获取对象的属性值
print(p1.__dict__)
p1.age = 20  #调用描述符对对象进行设置
print(p1.__dict__)

输出:
执行__set__方法
执行__set__方法
执行__get__方法
<__main__.Type object at 0x004CB4F0>
<__main__.People object at 0x02106DF0>
执行__get__方法
nick
{'name': 'nick', 'age': 18}
执行__set__方法
{'name': 'nick', 'age': 20}
class Type:
​
    def __init__(self,key,expect_type):
        self.key = key
        self.expect_type = expect_type
​
    def __get__(self, instance, owner):
        print("执行__get__方法")
        print(self)                #这里的self就是type类的对象
        print(instance)            #这里的instance就是传入的People类的对象
        print("执行__get__方法")
        return  instance.__dict__[self.key]   #通过instance的字典获取对象的属性值
​
    def __set__(self, instance, value):
        print("执行__set__方法")
        if not isinstance(value,self.expect_type):
            print("您输入的%s不是%s"%(self.key,self.expect_type))
            raise TypeError
        instance.__dict__[self.key] = value   #instance是另一个类的对象,这里要设置对象的属性字典
​
    def __delete__(self, instance):
        print("执行__delete__方法")
        instance.__dict__.pop(self.key)  #删除对象的属性
​
class People:
    name = Type("name",str)
    age = Type("age",int)
​
    def __init__(self,name,age):
        self.name = name
        self.age = age
​
p1 = People("nick",18)  #调用2次描述符,对对象的字典进行设置
print(p1.name)  #通过数据描述符获取对象的属性值
print(p1.__dict__)
p1.age = 20  #调用描述符对对象进行设置
print(p1.__dict__)
# p1.name = 11  #通过描述符的if not isinstance(value,self.expect_type)判断属性的类型
​
# p2 = People(88,18)  #通过描述符的if not isinstance(value,self.expect_type)判断属性的类型

Four secondary processing standard type

package

Python provides you with standard data types and a wealth of built-in methods. In fact, in many scenarios, we need to customize our own data types based on standard data types and add/rewrite methods. This uses the inheritance we just learned / Derived knowledge (other standard types can be processed in the following way), in simple terms, it is to rewrite the various built-in methods of the previous class, inherit the original functions, and then add functions

class LIST(list):  #继承list所有的属性
 ​
     def append(self, object):
         if type(object) is not str:  #这里对append方法进行二次处理,增加了新的功能
             print("%s 必须是字符串"%object)
         super().append(object)
         #list.append(self,object) 与上面一句作用相同,都是调用父类list的append方法
 ​
     @property   #使用property使得mid方法更像对象的数据属性,可以直接获得返回值
     def mid(self): #获得列表中间的元素的值
         index = len(self)
         mid_index = index//2  #这里是取除以2的整数商部分,向下取整
         return self[mid_index]
 ​
 ​
 la = LIST("hellonick") #调用list的方法将字符串转为列表
 print(la,type(la)) #输出结果 ['h', 'e', 'l', 'l', 'o', 'n', 'i', 'c', 'k'] <class '__main__.LIST'>
 # 这里的la是类LIST的一个对象
 print(la.mid)  #输出结果 o
 ​
 lb = list("hellonick")
 print(lb,type(lb))  #输出结果['h', 'e', 'l', 'l', 'o', 'n', 'i', 'c', 'k'] <class 'list'>,
 # 这里直接显示lb是列表类型,也是list的一个对象
class LIST(list):  #继承list所有的属性
​
    def __init__(self,item,tag=False):
        super().__init__(item)
        self.tag = tag
​
    def append(self, object):
        if type(object) is not str:  #这里对append方法进行二次处理,增加了新的功能
            print("%s 必须是字符串"%object)
        super().append(object)
        #list.append(self,object) 与上面一句作用相同,都是调用父类list的append方法
​
    def clear(self):
        if not self.tag: #改写原列表方法clear,增加权限限制
            raise PermissionError
        super().clear()
​
la = LIST("hellonick") #调用list的方法将字符串转为列表,输出结果 ['h', 'e', 'l', 'l', 'o', 'n', 'i', 'c', 'k']
print(la)               #['h', 'e', 'l', 'l', 'o', 'n', 'i', 'c', 'k']
print(la.tag)           #False
# la.clear() #会报错
​
​
lb = LIST([2,3,4,5,6,7])
print(lb)                #[2, 3, 4, 5, 6, 7]
# lb.clear() #会报错
print(lb.tag)            #False
​
lc = LIST([5,3,4,5,7],)
lc.tag = True
lc.clear()               
print(lc) #输出结果为 []

Authorization: Authorization is a feature of packaging. Packaging a type is usually some customization of an existing type. This approach can create, modify, or delete the functions of the original product. The others remain the same. The authorization process means that all updated functions are handled by a certain part of the new class, but the existing functions are authorized to the default properties of the object.

Simply put, the updated function uses the method of its own class definition, and the non-updated function uses the method of the parent class. If you define a method with the same name as the parent class, then use the method defined by yourself, and continue to use the method of the parent class for other methods. Authorization is also a kind of packaging, but the realization of authorization is not through inheritance, but __getattr__method of use .

The key point to achieve authorization is to override the __getattr__method

class FileHandle:
​
    def __init__(self,file,mode,encoding):
        self.file = open(file,mode,encoding=encoding)
​
    def __getattr__(self, item):
        return getattr(self.file,item)
    #这里调用属性的时候自动执行__getattr__方法,执行之后用getattr方法返回原属于open的方法
​
    def read(self):
        print("读取文件中。。。")
    #如果有同名的方法那么就用自己定义的方法,不用__getattr__获得的方法,
    # 因为__getattr__只有在使用点调用属性且属性不存在的时候才会触发
     
​
f = FileHandle("test.txt","w+","utf-8")
f.write("aaaaa")
f.seek(0)
data = f.read()  #这里是执行了FileHandle的自己定义的read()方法,所以输出结果是None
print(data)

 Note: When calling the __getattr__ function, first judge whether there is this function in the class, if so, call the function in the class, if not, call __getattr__

 

import time
​
class FileHandle:
​
    def __init__(self,file,mode,encoding):
        self.file = open(file,mode,encoding=encoding)
​
    def __getattr__(self, item):
        return getattr(self.file,item)
    #这里调用属性的时候自动执行__getattr__方法,执行之后用getattr方法返回原属于open的方法
​
    def write(self,msg):
        self.file.write("%s %s"%(time.strftime("%Y-%m-%d %X"),msg))  #调用self.file中open的方法
        #为每次写入增加时间
​
f = FileHandle("test.txt","w+","utf-8")
f.write("aaaaa")
f.seek(0)
data = f.read()
print(data)
 

Five  __enter__and__exit__

Open file operation uses with open() as f operation, which is called context management protocol, namely with statement. In order to make an object compatible with with statement, you must declare __enter__and __exit__method in the object's class .

__enter__(self): Trigger the operation of this method when with starts to run

__exit__(self, exc_type, exc_val, exc_tb): Trigger the operation of this method when the with operation ends

If exc_type throws an exception, get the type of the exception here

If exc_val throws an exception, the exception content is displayed here

If exc_tb throws an exception, the location is displayed here

 

Uses or benefits:

1. The purpose of using the with statement is to put the code block into the with for execution. After the with ends, the cleanup work is automatically completed without manual intervention.

2. In a programming environment where you need to manage some resources such as files, network connections and locks, you can __exit__customize the mechanism for automatically releasing resources. You don't need to worry about this problem anymore, which will be very useful

class OPEN:
 
    def __init__(self,name):
        self.name = name
 
    def __enter__(self):
        print("执行__enter__")
        return self
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("执行__exit__")
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        print("执行__exit__2222")
 
with OPEN("a.txt") as f:
    print(f)  #执行打印__enter__内置方法,同时打印内置方法返回的结果
 
#with 语句结束时执行__exit__方法,没有错误则打印None,有错误则打印错误的信息
print("上下文管理协议")

 

Guess you like

Origin blog.csdn.net/zangba9624/article/details/109748758