Python 装饰器(进阶)

Python装饰器(进阶)

到目前为止,您已经了解了如何创建简单的装饰器。您已经很好地理解了什么是装饰器以及它们是如何工作的。从这篇文章中休息一下,把你学到的东西都练习一下。
在本教程的第二部分中,我们将探索更高级的特性,包括如何使用以下特性:

  • 修饰符类
  • Several decorators on one function
  • Decorators with arguments
  • Decorators that can optionally take arguments
  • Stateful decorators
  • Classes as decorators

修饰类

在类上使用装饰器有两种不同的方法。第一个非常接近于您已经完成的函数:您可以修饰类的方法。这是当初引入装饰器的动机之一。

一些常用的装饰器甚至是Python中内置的,它们是@classmethod、@staticmethod和@property。@classmethod和@staticmethod修饰符用于定义类名称空间中的方法,这些方法不连接到该类的特定实例。@property装饰器用于自定义类属性的getter和setter。展开下面的框,查看使用这些装饰器的示例。

内置修饰器例子:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        """Get value of radius"""
        return self._radius

    @radius.setter
    def radius(self, value):
        """Set radius, raise error if negative"""
        if value >= 0:
            self._radius = value
        else:
            raise ValueError("Radius must be positive")

    @property
    def area(self):
        """Calculate area inside circle"""
        return self.pi() * self.radius**2

    def cylinder_volume(self, height):
        """Calculate volume of cylinder with circle as base"""
        return self.area * height

    @classmethod
    def unit_circle(cls):
        """Factory method creating a circle with radius 1"""
        return cls(1)

    @staticmethod
    def pi():
        """Value of π, could use math.pi instead though"""
        return 3.1415926535

在例子中:

  • . columnder_volume()是一种常规方法。
  • radius是一个可变的属性:它可以被设置为一个不同的值。然而,通过定义setter方法,我们可以进行一些错误测试,以确保它没有设置为无意义的负数。属性作为属性访问,不使用括号。
  • area是一个不可变的属性:没有.setter()方法的属性是无法更改的。即使将其定义为方法,也可以将其检索为没有括号的属性。
  • .unit_circle()是一个类方法。它不局限于一个特定的圆实例。类方法通常用作可以创建类的特定实例的工厂方法。
  • .pi()是一个静态方法。它实际上并不依赖于Circle类,只是它是其名称空间的一部分。可以对实例或类调用静态方法。

运行例子,

>>> c = Circle(5)
>>> c.radius
5

>>> c.area
78.5398163375

>>> c.radius = 2
>>> c.area
12.566370614

>>> c.area = 100
AttributeError: can't set attribute

>>> c.cylinder_volume(height=4)
50.265482456

>>> c.radius = -1
ValueError: Radius must be positive

>>> c = Circle.unit_circle()
>>> c.radius
1

>>> c.pi()
3.1415926535

>>> Circle.pi()
3.1415926535

自定义例子:

使用之前的@debug 和 @timer ,在Python装饰器入门中。

from decorators import debug, timer

class TimeWaster:
    @debug
    def __init__(self, max_num):
        self.max_num = max_num

    @timer
    def waste_time(self, num_times):
        for _ in range(num_times):
            sum([i**2 for i in range(self.max_num)])

使用这个类你就能看到修饰的效果:

>>> tw = TimeWaster(1000)
Calling __init__(<time_waster.TimeWaster object at 0x7efccce03908>, 1000)
'__init__' returned None

>>> tw.waste_time(999)
Finished 'waste_time' in 0.3376 secs

类修饰的另一种方法

在类上使用装饰器的另一种方法是装饰整个类。例如,这是在Python 3.7的新数据类模块中完成的:

from dataclasses import dataclass

@dataclass
class PlayingCard:
    rank: str
    suit: str

语法的含义类似于函数修饰符。在上面的例子中,您可以通过编写PlayingCard = dataclass(PlayingCard)来完成装饰。

就是把一个class扔给修饰器,然后扔出来一个新的class。

类修饰符的一个常见用途是作为元类的一些用例的简单替代。在这两种情况下,您都在动态地更改类的定义。

猜你喜欢

转载自blog.csdn.net/xiabenshu/article/details/88971114