返回顶部
首页 > 资讯 > 后端开发 > Python >Python学习之装饰器与类的装饰器详解
  • 501
分享到

Python学习之装饰器与类的装饰器详解

2024-04-02 19:04:59 501人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录装饰器装饰器的定义装饰器的用法类中的装饰器类的装饰器 - claSSMethod类的装饰器 - staticmethod类的装饰器 - property通过学习装饰器可以让我们更

通过学习装饰器可以让我们更好更灵活的使用函数,通过学会使用装饰器还可以让我们的代码更加优雅。

在我们的实际工作中,很多场景都会用到装饰器,比如记录一些日志、或者屏蔽一些不太合法的程序执行从而使我们的代码更加安全

装饰器

什么是装饰器?虽然对这个次感到陌生,但是完全不需要担心。

首先,装饰器也是一种函数;只不过装饰器可以接收 函数 作为参数来传递。

并且可以通过 return 可以返回一个函数,装饰器通过接收一个函数,对它在装饰器内部进行处理、调用,并返回一个新的函数,同时还可以动态增强传入函数的功能。

装饰器整个流程是这样的:

  • A函数是装饰器,B函数是A函数传入的参数。
  • 将B函数在A函数中执行,在A函数中可以选择执行或不执行,也可以对B函数的结果进行二次加工处理。

接下来我们看看 装饰器长什么样子

def a():
    
    def b():
        print(helloworld)
        
    b()
    
    
a()
b()

a() 函数中书写了一个 b() 函数,并在 a() 函数中调用 b() 函数。是不是非常类似在类中定义一个局部函数并调用的例子?其实装饰器就是有些类似这样的操作,只不过被装饰器调用的函数是通过 参数 的形式传进去,并在 b() 函数中执行。

我们在定义完 a() 函数之后进行调用,可以正常处理。但是 b() 函数 是 a() 函数的局部函数 如果在外部调用会报错。(如上文中的第十行,就会报错)

装饰器的定义

示例如下:

def out(func_args):            # 装饰器的第一层函数被称为 外围函数 , 'func_args' 为要处理的函数
    
    def inter(*args, **kwargs):        # 外围函数 的函数体内定义的函数被称为 内嵌函数 ;传入的参数为要处理的 func_args 函数的参数
                                    # 这里我们并不知道 func_args 函数需要传入进来的参数是什么,所以目前写传入可变参数是比较合理的
        return func_args(*args, **kwargs)        # 在 内嵌函数 的函数体内调用 func_args 函数,并将可变参数传入
                                                # 其实这里我们可以处理更多的逻辑;
                                                # 我们可以选择执行或者不执行,甚至可以func_args 函数的执行结果进行二次处理
    
    
    return inter             # 书写完 内嵌函数的业务之后,我们在 外围函数体内返回 内嵌函数
                            # 需要注意的是,这里是不执行的(因为没有加括号),这是装饰器的定义规则,是必不可少的
                            # 只有外围函数返回内嵌函数,才可以被之后的代码执行;(因为所有的业务都在内嵌函数中,不返回就无法执行调用)

装饰器的用法

在我们日常工作中,装饰器的使用方法有两种。

第一种:将被调用的函数直接作用为参数传入装饰器的外围函数括弧内;示例如下:

def a(func):
    
    def b(*args, **kwargs):
        return func(*args, **kwargs)
    
    return b


def c(name):
    print(name)
    

a(c)('Neo')

# >>> 执行结果如下:
# >>> Neo

第二种:将装饰器与被调用函数绑定在一起, @ 符号 + 装饰器函数放在被调用函数的上一行,被调用的函数正常定义,只需要直接调用被执行函数即可。示例如下:

def a(func):
    
    def b(*args, **kwargs):
        return func(*args, **kwargs)
    
    return b


@a
def c(name):
    print(name)
    
    
c('Neo')

# >>> 执行结果如下:
# >>> Neo

最常用的装饰器用法为第二种。

现在我们构建一个 检查字符串类型的装饰器,加深一下对装饰器的理解。

def check_ok(func):

    def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        if result == 'OK':
            return '传入的参数数据为:\'%s\'' % result
        else:
            return '传入的参数数据不为:\'OK\''

    return inner


@check_ok
def test_str(data):
    return data


result = test_str('OK')
print(result)

# >>> 执行结果如下:
# >>> 传入的参数数据为:'OK'

result = test_str('NO')
print(result)

# >>> 执行结果如下:
# >>> 传入的参数数据不为:'OK'

以上就是一个装饰器的简单用法,后续的学习内容会接触到更多的高级用法。

类中的装饰器

类的装饰器 - classmethod

classmethod 的功能:可以将类函数不经过实例化即可直接被调用

classmethod 的用法:示例如下

@classmethod
def func(cls, ...):
    todo
    
# >>> cls 替代普通类函数中的 self ;
# >>> 变更为 cls ,表示当前的类
# >>> self 代表的是 实例化对象,所以只有通过实例化后,才可以调用
# >>> cls 代表的是 类 ,所以即使不通过实例化,也可以调用 


# *****************************************************


class Test(object):

    @classmethod
    def add(cls, a, b):
        return a + b


print(Test.add(1, 3))

# >>> 执行结果如下:
# >>> 4

演示案例:

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜欢吃鱼')

    @classmethod
    def work(cls):
        print('会抓老鼠')


draGonLi = Cat('狸花猫')
print(dragonLi.eat(), dragonLi.work())

# >>> 执行结果如下:
# >>> 狸花猫 喜欢吃鱼
# >>> 会抓老鼠

接下来我们不使用 类的实例化 ,直接使用 类 调用 eat() 函数 与 work() 函数

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜欢吃鱼')

    @classmethod
    def work(cls):
        print('会抓老鼠')


dragonLi = Cat('狸花猫')

Cat.eat()

# >>> 执行结果如下:
# >>> TypeError: Cat.eat() missing 1 required positional argument: 'self'
# >>> 报错缺少重要参数 'self'  (没有进行实例化的类,类无法直接调用类函数)

Cat.work()
# >>> 执行结果如下:
# >>> 会抓老鼠
# >>> 绑定了 classmethod 装饰器 的 work() 函数,即使没有实例化,也可以直接被 类 调用

再尝试一下看看 没有装饰器的 eat() 函数 与 使用了 classmethod 装饰器 work() 之间可不可以互相调用

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜欢吃鱼')

    @classmethod
    def work(cls):
        print('会抓老鼠')
        cls.eat()			# 在 classmethod 装饰器的 work() 函数内 调用 eat() 函数


dragonLi = Cat('狸花猫')
dragonLi.work()

# >>> 执行结果如下:
# >>> TypeError: Cat.eat() missing 1 required positional argument: 'self'
# >>> 同样报错缺少重要参数 'self' 
class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜欢吃鱼')
        self.work()

    @classmethod
    def work(cls):
        print('会抓老鼠')


dragonLi01 = Cat('狸花猫')
dragonLi01.eat()

# >>> 执行结果如下:
# >>> 执行结果如下:
# >>> 狸花猫 喜欢吃鱼
# >>> 会抓老鼠

综合以上两个场景,我们得出以下结论:

  • 在带有 classmethod 装饰器 的 函数 内,是无法调用普通的 带有 self 的函数的
  • 但是在普通的带有 self 的类函数内,是可以调用带有 classmethod 装饰器 的 函数的

类的装饰器 - staticmethod

staticmethod 的功能:可以将 类函数 不经过实例化而直接被调用,被该装饰器调用的函数不需要传入 self 、cls 参数,并且无法在该函数内调用其他 类函数 或 类变量

staticmethod 的用法:参考如下

@staticmethod
def func(...):
    todo
    
# >>> 函数内无需传入 cls 或 self 参数


# *****************************************************


class Test(object):
    
    @staticmethod
    def add(a, b):
        return a + b


print(Test.add(1, 3))

# >>> 执行结果如下:
# >>> 4

接下来我们在上文的 Cat() 类基础演示一下 staticmethod 装饰器 (新建一个 color() 函数,使用 staticmethod 装饰器 )

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜欢吃鱼')
        self.work()

    @classmethod
    def work(cls):
        print('会抓老鼠')

    @staticmethod
    def color():
        print('黄棕色')


dragonLi = Cat('狸花猫')
print(dragonLi.eat(), dragonLi.color())

# >>> 执行结果如下:
# >>> 狸花猫 喜欢吃鱼
# >>> 会抓老鼠
# >>> 黄棕色
# >>> 从执行结果来看, staticmethod 装饰器的 color() 函数可以被实例化后的对象 dragonLi 调用。
# >>> 那么可以被 Cat() 类 直接调用么?我们往下看


print(Cat.color())

# >>> 执行结果如下:
# >>> 黄棕色
# >>> 可以看到,staticmethod 装饰器构造的 color() 函数,即使没有被实例化,依然可以直接被 类 调用

同样的,也尝试一下 staticmethod 装饰器构造的 color() 函数 是否能够在类函数中互相调用。

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜欢吃鱼')
        self.work()
        self.color()

    @classmethod
    def work(cls):
        print('会抓老鼠')

    @staticmethod
    def color():
        print('黄棕色')


dragonLi = Cat('狸花猫')
dragonLi.eat()

# >>> 执行结果如下:
# >>> 狸花猫 喜欢吃鱼
# >>> 会抓老鼠
# >>> 黄棕色				
# >>> 结合执行结果得出结论:staticmethod 装饰器构造的 color() 函数 可以在 eat() 类函数中被调用

与带有 classmethod 装饰器 的 函数 一样,staticmethod 装饰器构造的 函数也是无法调用普通的 带有 self 的函数的,这里就不再书写演示代码进行演示了。(staticmethod 装饰器构造的 函数也是无法调用普通的 带有 self 的函数会报错 : NameError: name 'self' is not defined )

类的装饰器 - property

property 的功能:可以将类函数的执行免去小括号,类似于直接调用类的变量(属性)

staticmethod 的用法:参考如下

@property
def func(self):
    todo
    
# >>> 不能传入参数,无重要函数说明


# *************************示例如下*************************


class Test(object):

    def __init__(self, name):
        self.name = name

    @property
    def call_name(self):
        return 'Hello {}'.fORMat(self.name)


test = Test('Neo')
result = test.call_name			# 不需要添加 小括号 即可调用 call_name 函数;
								# 关于 staticmethod 不可传入参数,其实并不是不可以传入参数,而是传入的方法比较另类,我们继续往下看
print(result)

# >>> 执行结果如下:
# >>> Hello Neo

重新创建一个 Dog 类 ,然后我们继续演示。

class Dog(object):

    def __init__(self, name):
        self.__name = name

    @property
    def type(self):
        if self.__name in ['哈士奇', '萨摩耶', '阿拉斯基']:
            return self.__name, '是雪橇犬,\'雪橇三傻\'之一'
        elif self.__name in ['吉娃娃', '博美犬', '约克夏']:
            return self.__name, '是小型犬'
        else:
            return self.__name, '我暂时不知道这是什么犬种,也许它是\'泰日天\'的亲戚'


dog = Dog(name='哈士奇')
print(dog.type)			# 这里我们并不需要 dog.type + () 小括号,即可调用 type() 函数

# >>> 执行结果如下:
# >>> ('哈士奇', "是雪橇犬,'雪橇三傻'之一")
# >>> 这里我们看到 当 Dog 类 实例化 dog 变量之后,我们传入的 '哈士奇' 参数是不可更改的,如果我们尝试利用赋值的方式修改传入的参数呢?

dog = Dog(name='哈士奇')
dog.type = '约克夏'
print(dog.type)

# >>> 执行结果如下:
# >>> AttributeError: can't set attribute
# >>> 报错:属性错误,不可以设置这个属性
# >>> 其实,property 装饰器绑定的函数的参数并不是不可以更改,只是更改的方式比较特殊,并不是不能通过赋值的形式传入参数,我们继续往下看。

首先,我们已经使用了 @property 绑定了我们的 type 函数,这是一个返回值的方法。 所以我们要如何给 type() 函数赋值呢?其实很简单,我们可以通过 @type 对应上 type() 函数,在它的函数内部有一个函数 setter ;然后再定义一个 type 函数,在这个新定义的 type() 函数内定义一个值 value (可以是任意的名字,但这里需要注意,只能定义一个值)。然后再通过设置一个 self.__name = value ,如此就可以达到修改传入参数的目的。废话不多说了,看下方的示例:

class Dog(object):

    def __init__(self, name):
        self.__name = name

    @property
    def type(self):
        if self.__name in ['哈士奇', '萨摩耶', '阿拉斯基']:
            return self.__name, '是雪橇犬,\'雪橇三傻\'之一'
        elif self.__name in ['吉娃娃', '博美犬', '约克夏']:
            return self.__name, '是小型犬'
        else:
            return self.__name, '我暂时不知道这是什么犬种,也许它是\'泰日天\'的亲戚'

    @type.setter
    def type(self, value):
        self.__name = value


dog = Dog(name='哈士奇')
dog.type = '约克夏'
print(dog.type)

# >>> 执行结果如下:
# >>> ('约克夏', '是小型犬')

附:使用最广泛的装饰器为 classmethod

以上就是python学习之装饰器与类的装饰器详解的详细内容,更多关于Python装饰器的资料请关注编程网其它相关文章!

--结束END--

本文标题: Python学习之装饰器与类的装饰器详解

本文链接: https://lsjlt.com/news/142103.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python学习之装饰器与类的装饰器详解
    目录装饰器装饰器的定义装饰器的用法类中的装饰器类的装饰器 - classmethod类的装饰器 - staticmethod类的装饰器 - property通过学习装饰器可以让我们更...
    99+
    2024-04-02
  • python3学习之装饰器
    #定义装饰器,outer参数是函数,返回也是函数 #作用:在函数执行前和执行后分别附加额外功能 def  outer(func):     def  inner(*args, **kwargs):         print("log") ...
    99+
    2023-01-31
  • python学习系列之python装饰器
    一、常规的装饰器,比如 @auth,执行2步操作:1、执行auth函数,并传参func进来2、获取返回值,并赋值给被装饰器的函数的函数名(如让fetch_server_list等于返回值)二、而带参数的装饰器,比如 @auth(before...
    99+
    2023-01-31
    系列之 python
  • python装饰器2:类装饰器
    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 本文是装饰器相关内容的第二篇,关于类装饰器。 "类装饰器"有两种解读方式:用来装饰类的装饰器;类作为装饰器装饰其它东西。你如何认为取决于你,两种说法都有出现在其它的文章中。我的...
    99+
    2023-01-30
    python
  • Python装饰器与类的装饰器怎么实现
    这篇“Python装饰器与类的装饰器怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python装饰器与类的装饰器怎么...
    99+
    2023-06-29
  • 详解Python装饰器之@property
    一、property() 函数讲解 了解 @property 装饰器之前,我们首先要了解内置函数的 property()。 class property(fget=None, fset=None, fdel=No...
    99+
    2022-06-02
    Python @property python装饰器
  • Python 3 之 装饰器详解
    ------------ 装饰器 -----------------------------------------------------什么是装饰器装饰器是为函数和类指定管理代码的一种方式。装饰器本身的形式是处理其他的可调用对象的可调用...
    99+
    2023-01-31
    详解 Python
  • python装饰器1:函数装饰器详解
    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 先混个眼熟 谁可以作为装饰器(可以将谁编写成装饰器): 函数 方法 实现了__call__的可调用类 装饰器可以去装饰谁(谁可以被装饰): 函数 方法 类 基础...
    99+
    2023-01-30
    详解 函数 python
  • python之yield与装饰器
    防伪码:忘情公子著python中的yield:  在之前发布的《python之列表解析与生成器》中我们有提到过,生成器所实现的是跟列表解析近似的效果,但是我们不能对生成器做一些属于列表解析的操作。  因为生成器本身就不是一个列表,它只是模拟...
    99+
    2023-01-31
    python yield
  • python 进阶学习之python装饰器小结
    装饰器总结 什么是装饰器?处理函数的函数,加一个功能,但是不影响原来函数的内部结构生活中的例子:给手机加一个外壳,外壳保护了手机 装饰器有什么用?增强函数的功能 装饰器使用场景增加被...
    99+
    2024-04-02
  • python装饰器详解
            python中的装饰器(decorator)一般采用语法糖的形式,是一种语法格式。比如:@classmethod,@staticmethod,@property,@xxx.setter,@wraps(),@func_na...
    99+
    2023-09-01
    python
  • python基础之装饰器详解
    目录一、前言二、高阶函数三、函数嵌套四、装饰器4.1 被装饰方法带返回值4.2 被装饰方法带参数4.3 验证功能装饰器4.4 验证功能装饰器——带参数一、前言 装...
    99+
    2024-04-02
  • python三大器之装饰器详解
    目录装饰器总结装饰器 讲装饰器之前要先了解两个概念: 对象引用 :对象名仅仅只是个绑定内存地址的变量 def func(): # 函数名仅仅只是个绑定内存地址的...
    99+
    2024-04-02
  • python基础学习12----装饰器
    装饰器可以在不修改目标函数代码的前提下, 在目标函数执行前后增加一些额外功能 例如有一个简单的函数 import time def func1(): print("这是一个简单的函数") time.sleep(2) 想给这...
    99+
    2023-01-30
    基础 python
  • Python之装饰器
    在Python中一切皆对象,函数是一等对象。这意味着可以通过名字引用函数。>>> a=123 >>> a 123 >>> name='zeng' >>> name 'z...
    99+
    2023-01-31
    Python
  • Python装饰器-闭包与函数装饰器
    一、闭包在学习装饰器前,需要先了解闭包的概念。形成闭包的要点:函数嵌套将内部函数作为外部函数的返回值内部函数必须要使用到外部函数的变量下面以一个计算列表平均值的案例来讲解闭包:def make_average(): # 创建一个列表,用来保...
    99+
    2023-05-14
    Python 函数 装饰器
  • Python语法详解之decorator装饰器
    python 是一门优雅的语言,有些使用方法就像魔法一样。装饰器(decorator)就是一种化腐朽性为神奇的技巧。最近一直都在使用 Tornado 框架,一直还是念念不忘 Flas...
    99+
    2024-04-02
  • Python的装饰器用法学习笔记
    在python中常看到在定义函数是使用@func. 这就是装饰器, 装饰器是把一个函数作为参数的函数,常常用于扩展已有函数,即不改变当前函数状态下增加功能. def run(): print "I'...
    99+
    2022-06-04
    法学 笔记 Python
  • day20-python之装饰器
    1.装饰器 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import time 4 def cal(l): 5 start_time=time.time() ...
    99+
    2023-01-31
    python
  • 类装饰器
      在理解类装饰器之前,先回忆一下有关装饰器的知识。装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(函数的引用)。   __call__方法  一个对象是否可调用,看...
    99+
    2023-01-30
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作