title: Special methods and decorators for python author: Sekyoro date: 2023-05-07 11:31:24 tags: - python categories: archives: password: abstract: message:
Here will introduce the so-called magic method and decorator of python
magic method
Generally, methods surrounded by double underscores in a class are magic methods, or special methods.
In simple terms, Python's magic method is to take advantage of Python's standard methods and avoid having to remember the names of standard operations to achieve a more uniform interface.
![image-20230507133421451](https://s2.loli.net/2023/05/07/2QCAj8iUIsNtrzO.png)
For example the following code
import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, item):
return self._cards[item]
if __name__ == '__main__':
print(len(deck))
print(deck[0])
__len__
This particular method makes calling len(beer_card) actually call__len__
The getitem method offloads the [] operation to the self._cards list, so our deck class automatically supports slicing.
The output is as follows
52
Card(rank='2', suit='spades')
In addition, only by implementing the getitem method, the object becomes iterable
for i in deck:
print(i)
![image-20230507134341143](https://s2.loli.net/2023/05/07/nBPSwYrg68y47Ff.png)
At the same time __contains__
it is possible to implement in
the method
In addition to implementing iteration, len(), slicing and other methods through special methods above, effects similar to overloaded operators can also be achieved.
from math import hypot
class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __repr__(self):
return 'Vector(%r, %r)' % (self.x, self.y)
def __abs__(self):
return hypot(self.x, self.y)
def __bool__(self):
return bool(abs(self))
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Vector(x, y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
v1 = Vector(3,4)
v2 = Vector(4,5)
v3 = v1+v2
print(v3)
Output Vector(7, 9)
and __repr__
___str__
The difference between repr and str is that the latter is called when the str() function is used, or when an object is printed with the print function, and the string it returns is more friendly to the end user.
如果你只想实现这两个特殊方法中的一个,__repr__ 是更好的选择,因为如果一个对象没有 str 函数,而 Python 又需要调用它的时候,解释器会用 repr 作为替代。
{!r}
就是使用format语法时候的%r
。因此,我们只需要关注%r
就好。%r
表示的用repr()
处理;类似于的%s
表示用str()
处理一样
其他特别方法
![image-20230507134927018](https://s2.loli.net/2023/05/07/GpmoahVdxD1TNwL.png)
装饰器
装饰器的作用就是为已经存在的函数或对象添加额外的功能。 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
def debug(func):
def wrapper():
print("[DEBUG]: enter {}()".format(func.__name__))
return func()
return wrapper
@debug
def hello():
print("hello")
hello()
装饰器涉及到闭包的概念,什么是闭包,一句话说就是,在函数中再嵌套一个函数,并且引用外部函数的变量,这就是一个闭包了
上述无参装饰器可以用于输出日志。
如果要在wrapper中访问参数,如下
def debug(func):
def wrapper(*args, **kwargs):
print("[DEBUG]: enter {}()".format(func.__name__))
print("params", args, kwargs)
return func(*args, **kwargs)
return wrapper
@debug
def test(a,b):
print("this is a test function")
如果要在装饰器中使用参数,还要在外面包围一层。
def logging(level):
def outwrapper(func):
def wrapper(*args, **kwargs):
print("[{0}]: enter {1}()".format(level, func.__name__))
return func(*args, **kwargs)
return wrapper
return outwrapper
@logging(level="INFO")
def hello(a, b, c):
print(a, b, c)
除了使用函数装饰器也可以是使用类装饰器
class logging(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[DEBUG]: enter {}()".format(self.func.__name__))
return self.func(*args, **kwargs)
@logging
def hello(a, b, c):
print(a, b, c)
装饰器中使用参数
class logging(object):
def __init__(self, level):
self.level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print("[{0}]: enter {1}()".format(self.level, func.__name__))
return func(*args, **kwargs)
return wrapper
@logging(level="TEST")
def hello(a, b, c):
print(a, b, c)
属性
当我们创建一个类,以定义对象时,我们可能会希望一些属性对于外界是只读的,或者希望创建属性只能按特定的方式访问或修改。这时就可以使用 Python 中的属性(Property)。
In Python, properties are pieces of code wrapped in functions that intercept access to and modification of properties of an object. Python has a built-in @property decorator that can be used to decorate a method to make it a property call. At the same time, Python also provides the setter method of the corresponding method of the @property decorator, which is used to set the property.
In simple terms, properties optimize the way that previously used public methods to access private properties while having a finer granularity.
class myObj:
def __init__(self, name):
self.__name = name
print("init")
@property
def name(self):
return self.__name
if __name__ == '__main__':
obj = myObj("hello")
print(obj.name)
output
init
hello
An error will be reported if obj.name = "world"
the property is changed.
Add to
@name.setter
def name(self, newname):
self.__name = newname
Can be changed through the name attributeself.__name
In addition there is deleter
@name.deleter
def name(self):
self.__name = None
Use del to delete attributes
del obj.name
print(obj.name)
output isNone
References
This article is published by mdnice multi-platform