This is the 14th day of my participation in Gwen Challenge
Wechat public number search [program yuan xiaozhuang], pay attention to the halfway program yuan how to rely on Python development to support the family ~
preface
This article introduces common magic methods in Python and the very important singleton pattern in object orientation.
Magic methods
Everything in Python is an object because Python is an object-oriented programming language. Python provides a number of built-in methods, also known as magic methods, for classes and objects. These magic methods are always automatically triggered under certain conditions, just like magic.
__init__
methods
This method is used to receive an empty object returned by the __new__ method when defining a class and initialize it without returning a value.
class Test() :
def __init__(self, name) :
self.name = name
def test(self) :
print(self.name)
t = Test('xu')
t1 = Test('python')
Copy the code
__new__
methods
This method is the first method that is fired when a class is called to instantiate an object, to instantiate an empty object and return.
class Test() :
def __new__(* * kwargs CLS, * args) :
return object.__new__(cls, *args, **kwargs)
def __init__(self, name) :
self.name = name
Copy the code
__call__
methods
If you want an object to become a callable (callable in parentheses), you define a __call__ method in the object’s class. The return value of the call to the callable is the return value of the __call__ method.
class Test() :
def __init__(self) :
self.name = 'python'
def __call__(self, *args, **kwargs) : # self is an object of class Test
print(self) # <__main__.Test object at 0x000001C78CE78FD0>
print(self.name)
t = Test()
t() # python
Copy the code
__str___
methods
To trigger execution when an object is accessed to print, the method must have a return value of type string.
class Test() :
def __init__(self, name) :
self.name = name
def __str__(self) :
return self.name
t = Test('xu')
print(t1) # xu
Copy the code
__del___
methods
The __del__ method is triggered automatically when an object is deleted. Since Python’s garbage collection mechanism automatically cleans up unused resources in the program, there is no need to define a __del__ method if an object is only using application resources, but if it is designed to use system resources, such as open file objects, When Python’s garbage collection mechanism is not useful because of the operating system resources involved, you need to create a __del__ method for an object that automatically triggers the recycling of operating system resources when the object is deleted.
class Test:
def __init__(self) :
self.x = open('a.txt',mode='w')
# self.x = occupies operating system resources
def __del__(self) :
print('run')
Make a system call that tells the operating system to reclaim related system resources
self.x.close()
obj = T()
del obj # obj.__del__()
Copy the code
__enter__ & __exit__
methods
With context management, the __enter__ method in the object is triggered and the return value of the __enter__ method is assigned to the variable declared by AS.
When the with statement normally terminates, the __exit__ method is fired, which takes three arguments representing the exception type, the exception value, and the tracing information. If the with block is abnormal, the code after the with statement is not executed. If the method returns True, the exception is cleared. The code after the with block will be executed normally. The code is as follows:
class Open:
def __init__(self) :
self.name = 'open'
def __enter__(self) :
print('The method executed first when the with statement is executed, and the return value is assigned to the variable declared by as')
return self.name
def __exit__(self, exc_type, exc_val, exc_tb) :
print('Exit when the code block in with completes execution')
print(exc_type, 'If an exception occurs indicate the type of exception')
print(exc_val, 'Represents the value of the exception')
print(exc_tb, 'Represents trace information for exception')
return 123 # non-zero non-null non-none is true
with Open() as test:
print(test)
raise TypeError('Look at the error message')
print('Am I going to be executed?') The __exit__ method is executed when it returns true, otherwise it is not
Copy the code
item
Series method
The item family of methods includes __setitem__, __getitem__, and delitem__ methods. These three methods are triggered when brackets are assigned/modified, brackets are evaluated, and brackets are deleted, respectively. For example, you can define a dictionary class and define the methods for brackets to assign, evaluate, and delete values:
class MyDict(dict) :
def __setitem__(self, key, value) :
print('execution setitem', key, value) Execute setitem, x, 1
self.__dict__[key] = value
def __getitem__(self, item) :
print('perform the getitem', item) Getitem x
print(self.__dict__[item]) # 1
def __delitem__(self, key) :
print('execution delitem', key) Execute delitem x
self.__dict__.pop(key)
d = MyDict()
d['x'] = 1
print(d['x'])
del d['x']
Copy the code
attr
Series method
The attr family of methods includes __setattr__,__getattr__,__delattr__, __setattr__ when adding/modifying attributes, ___delattr__ when deleting attributes, and __getattr__ when in use. Fired when a property is called and does not exist. See the code below
class Test:
def __init__(self) :
self.name = 'python'
def __setattr__(self, key, value) :
print('Add/Modify attribute setattr')
self.__dict__[key] = value
# self.key = value # wireless recursion occurs because of the object. Attribute calls the __setattr__ method
def __delattr__(self, item) :
print('Delete attribute delattr')
self.__dict__.pop(item)
def __getattr__(self, item) :
print('Call getattr when property does not exist')
t = Test()
t.x = 'x'
print(t.y)
del t.x
Copy the code
The singleton pattern
The singleton pattern is a software design pattern that ensures that no matter how many times a class is called, the resulting object points to the same memory address, that is, there is only one object.
There are many ways to implement the singleton pattern, the general principle is to ensure that a class only instantiates one object, so the key is how to determine whether the class has instantiated an object.
Here are several implementation methods for your reference:
How modules are imported
The principle is that modules are imported and run only once, and classes in the module are retrieved directly from memory when they are used again.
# cls_singleton.py
class Foo(object) :
pass
instance = Foo()
# test.py
import cls_singleton
obj1 = cls_singleton.instance
obj2 = cls_singleton.instance
print(obj1 is obj2) # True
Copy the code
through__new__
methods
The principle is to determine if a class has power, return it if it does, and save it in _instance if it does not
class Test:
_instance = None
def __init__(self, name, age) :
self.name = name
self.age = age
def __new__(cls, *args, **kwargs) :
# if cls._instance:
CLS._instance # return CLS
# else:
# cls._instance = super().__new__(CLS) #
CLS._instance # return CLS._instance # return CLS
if not cls._instance: # This is a simplified way of writing, the above comment is easier to draw a judgment of the idea
cls._instance = super().__new__(cls)
return cls._instance
t1 = Test('python'.18)
t2 = Test('python1'.18)
print(t1 is t2) # True
Copy the code
How to customize metaclasses
The principle of this approach is the process of class invocation. The __init__ of the metaclass is called when the class is defined, and the __call__ method of the metaclass is triggered when the class is called (instantiating the object).
class Mymeta(type) :
def __init__(cls, name, bases, dic) :
super().__init__(name, bases, dic)
cls._instance = None Data attributes for instance objects of record classes are automatically defined in metaclasses
def __call__(cls, *args, **kwargs) : This call is triggered when the class is called (i.e. instantiated)
if cls._instance: Check whether the class instantiates an object
return cls._instance
else: The control class nulls the object and initializes it when no object is instantiated
obj = cls.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
cls._instance = obj The next time you instantiate the object, you can return it directly without recreating it
return obj
class Test(metaclass=Mymeta) :
def __init__(self, name, age) :
self.name = name
self.age = age
t1 = Test('python'.18)
t2 = Test('python1'.18)
print(t1 is t2) # True
Copy the code
conclusion
The article was first published on the wechat public account Program Yuan Xiaozhuang, and synchronized with nuggets and Zhihu.
The code word is not easy, reprint please explain the source, pass by the little friends of the lovely little finger point like and then go (╹▽╹)