Python从入门到精通8天(装饰器的基本使用)

这篇具有很好参考价值的文章主要介绍了Python从入门到精通8天(装饰器的基本使用)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

装饰器概述

装饰器是一个著名的设计模式,经常被用于有切面(aspect)需求的场景,如插入日志、性能测试、事务处理等。装饰器可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。

用函数实现装饰器

装饰器本质上是一个函数,它接收一个函数作为参数,然后返回新的函数。在装饰器的使用中,我们将原始函数作为参数传递给装饰器,然后将返回的新函数替换原始函数的引用。当我们调用原始函数时,实际上会调用装饰器返回新函数,从而实现对原始函数的修改或扩展。

实现原理如下:

# 装饰器的具体实现

# 定义一个装饰器
# 这里的参数f为一个函数
def name(f):

    # 这里因为name2中有参数,所以这里也得有参数
    def name1(a):
        print("我已经从name1变成了name2")

        # 这里是实现对name2函数的调用
        f(a)
        print("我已经调用了name2函数,所以装饰器使用成功,我可以退出了")

    # 如果我们使用了装饰器,也就意味着我们将name1函数赋值给了我们装饰器要修饰的函数
    return name1

# 直接继承父类Object,这里就不用进行初始化了
class Student(object):
    @name
    def name2(self):
        print("我是在装饰器的内部被调用")

# 实例化类
student = Student()

student.name2()

用类实现装饰器

上面我们将装饰器用函数进行的表示,那么能不能用类进行实现呢?

在这之前我们需要对__call__这个特殊方法进行了解。如果一个类定义了__call__()方法,那么它的实例可以像函数一样被调用。当你调用一个对象时,实际上是调用了该对象的__call__()方法。这个法可以接收任意数量的参数,并且可以返回任意类型的值。

具体代码如下:

class Decorator:
    # 这里的func参数用于接受函数
    def __init__(self,func):
        self.func = func

    # 使用特殊方法__call__

    def __call__(self, *args, **kwargs):
        print("被装饰器装饰的函数在这里被调用了")
        self.func(*args,**kwargs)
        return print("我已经被调用完毕")

# 这里相当于对类进行实例化
# 自动调用__init__方法
# 将装饰器修饰的函数传给__init__方法中的参数
@Decorator
def add(a,b):
    return print(a+b)

add(3,4)

带参数的函数装饰器

函数可以带参数,类也可以带参数,那么我们的装饰器可以带参数吗?当然可以。

具体代码如下:

# 这里是接受装饰器的参数
def a(j,k):
	# 这里是将装饰器修饰的函数进行传参
    def b(f):
        def e():
            print(f"我是{j}{k}")
            f()

        return e
    return b

# 这里相当于给装饰器传参
@a(1,2)
def c():
    print("你好")

c()

带参数的类装饰器

当使用类实现装饰器时,我们的__call__方法将接收函数作为参数,__init__将接收装饰器的参数。

具体代码如下:

class A():
    # 此时初始化__init__特殊方法不在接收函数为参数
    # 接受的装饰器的参数
    def __init__(self,a1,b1):
        self.a = a1
        self.b = b1

    # 用__call__方法接受函数为参数,并实现调用
    def __call__(self, f):
        def b():
            print(f"我接受完了函数{self.a}{self.b}")
            f()
            print("我已经调用完毕")
        return b

@A(1,2)
def c():
    print("我是被装饰器修饰的函数")

c()

内置装饰器的使用

通过上面的几个例子,大家对装饰器的运行应该没有多大问题了。我们现在就来学习Python的内置装饰器,分别是staticmethod、classmethod和property,分别把类中的实例方法变成静态方法、类方法和类属性。由于模块里可以定义函数,所以静态方法和类方法用处不是特别的多。

  • @property装饰器
    它的作用是将一个方法转化为一个只读属性,当访问该属性时,会自动调用该方法。

  • @classmethod装饰器
    它的作用是将被修饰的函数转换成类方法,指的是传入类作为第一个参数的方法。类方法可以在不实例化对象的情况下调用,但他可以访问和修改类的变量和方法。

  • @staticmethod装饰器
    它的作用是将函数变为静态方法,在类中不需要实例化对象就可以调用的方法。静态方法与类有关联,但不依赖于类的实例或类变量。

具体代码如下:

class A(object):

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

    k = 2

    @property
    def a(self):
        print(f"被property装饰器修饰,所以我是类属性{self.j}")
        return self.j

    @staticmethod
    def b(j):
        print(f"被staticmethod修饰,所以我是静态方法{j}")


    @classmethod
    def c(cls):
        print("被classmethod修饰所以我是类方法{0},我可以修改变量".format(cls.k+1))


# staticmethod装饰器,不需要实例化对象便能使用
A.b(1)

# classmethod装饰器,不需要实例化对象便能使用

A.c()

# property装饰器,将一个方法转换成一个只读属性
a1 = A(1)
# a1.a = 2   #can't set attribute 'a'
print(a1.a)

__slots__魔法

Python是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定。但是如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用。

具体代码如下:

class Person(object):

    # 限定Person对象只能绑定_name, _age和_gender属性
    __slots__ = ('_name', '_age', '_gender')

    def __init__(self, name, age):
        self._name = name
        self._age = age
        
        # 不可以使用其他的属性
        # self.b = 3   # AttributeError: 'Person' object has no attribute 'b'
        
	# 名字只能读取,不能被改变
    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        if self._age <= 16:
            print('%s正在玩飞行棋.' % self._name)
        else:
            print('%s正在玩斗地主.' % self._name)


def main():
    person = Person('王大锤', 22)
    # 直接更改年龄
    person.age = 10
    person.play()
    # _gender表示受保护的属性,尽管可以访问
    # 但是不建议这么做,避免出现错误
    person._gender = '男'


main()

练习(工资结算系统)

要求:某公司有三种类型的员工 分别是部门经理、程序员和销售员
需要设计一个工资结算系统 根据提供的员工信息来计算月薪
部门经理的月薪是每月固定15000元
程序员的月薪按本月工作时间计算 每小时150元
销售员的月薪是1200元的底薪加上销售额5%的提成

代码如下:文章来源地址https://www.toymoban.com/news/detail-422711.html

from abc import ABCMeta, abstractmethod


class Employee(object, metaclass=ABCMeta):
    """员工"""

    def __init__(self, name):
        """
        初始化方法

        :param name: 姓名
        """
        self._name = name
	
	# 保护name属性
    @property
    def name(self):
        return self._name
	
	# 规范子类的行为,必须要有get_salary方法,如果没有,则不能实例化类
	# 通过 @abstractmethod 装饰器,我们告诉 Python 这是一个抽象方法,子类必须实现它。
    @abstractmethod
    def get_salary(self):
        """
        获得月薪

        :return: 月薪
        """
        pass


class Manager(Employee):
    """部门经理"""

    def get_salary(self):
        return 15000.0


class Programmer(Employee):
    """程序员"""

    def __init__(self, name, working_hour=0):
        super().__init__(name)
        self._working_hour = working_hour

    @property
    def working_hour(self):
        return self._working_hour
        
	# 将可读工作时间改为可修改
    @working_hour.setter
    def working_hour(self, working_hour):
        self._working_hour = working_hour if working_hour > 0 else 0

    def get_salary(self):
        return 150.0 * self._working_hour


class Salesman(Employee):
    """销售员"""

    def __init__(self, name, sales=0):
        super().__init__(name)
        self._sales = sales

    @property
    def sales(self):
        return self._sales

    @sales.setter
    def sales(self, sales):
        self._sales = sales if sales > 0 else 0

    def get_salary(self):
        return 1200.0 + self._sales * 0.05


def main():
    emps = [
        Manager('刘备'), Programmer('诸葛亮'),
        Manager('曹操'), Salesman('荀彧'),
        Salesman('吕布'), Programmer('张辽'),
        Programmer('赵云')
    ]
    for emp in emps:
		
		# isinstance()可以判断一个变量的类型
        if isinstance(emp, Programmer):
            emp.working_hour = int(input('请输入%s本月工作时间: ' % emp.name))
        elif isinstance(emp, Salesman):
            emp.sales = float(input('请输入%s本月销售额: ' % emp.name))
            
        # 同样是接收get_salary这个消息但是不同的员工表现出了不同的行为(多态)
        print('%s本月工资为: ¥%s元' %(emp.name, emp.get_salary()))


if __name__ == '__main__':
    main()

到了这里,关于Python从入门到精通8天(装饰器的基本使用)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python 函数(lambda 匿名函数、自定义函数、装饰器)基本使用指南

    函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段 对于单行函数,使用 lambda 表达式可以省去定义函数的过程,让代码更加简洁; 对于不需要多次复用的函数,使用 lambda 表达式可以在用完之后立即释放,提高程序执行的性能。 格式: 一般形式 含 if

    2024年02月08日
    浏览(43)
  • javacv从入门到精通——第三章:基本使用

    JavaCV的基本结构如下: JavaCV核心类 :JavaCV核心类是JavaCV库的核心,它包括了JavaCV的所有功能和特性,可以用来进行计算机视觉和人工智能任务的开发和实现。JavaCV核心类的主要功能包括:视频捕获、视频编解码、图像处理、人脸检测、特征提取等。 基本数据类型: JavaCV库支

    2023年04月16日
    浏览(31)
  • 爬虫入门到精通_基础篇1(爬虫基本原理讲解, Urllib库基本使用)

    发起请求:通过HTTP库向目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,等待服务器响应。 获取响应内容:如果服务器能正常响应,会得到一个Response,Response的内容便是所要获取的页面内容,类型可能有HTML,Json字符串,二进制数据(如图片视频)等类型。

    2024年01月23日
    浏览(29)
  • Next.js使用装饰器decorator 解决[作为表达式调用时,无法解析类修饰器的签名。]

    Next.js 会自动检测 jsconfig.json 或 tsconfig.json 中的 experimentalDecorators 。 tsconfig.json 然后重启服务 否则装饰器无法识别 不声明的话vscode 执行 ts检测 也会报错 作为表达式调用时,无法解析类修饰器的签名。 支持的四种装饰器 类装饰器 也可以这样写 下方写法可以将属性写在当前

    2024年02月14日
    浏览(33)
  • 【Linux从入门到精通】vim的基本使用各种操作详解

       文章目录 一、vim编辑器简单介绍 二、vim编辑器的四种模式 2、1 正常/普通/命令模式(Normal mode) 2、2 插入模式(Insert mode) 2、3 末行模式(last line mode) 三、命令模式的相关操作实例 3、1 光标的相关操作 3、2 文本操作 四、插入模式下的相关操作 五、末行模式下的相关操作 🙋

    2024年02月04日
    浏览(30)
  • 【Linux从入门到精通|开发工具】---gcc/g++的基本使用

    个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【Linux专栏】🎈 本专栏旨在分享学习Linux的一点学习心得,欢迎大家在评论区讨论💌 接下来我们来学习 Linux编辑器---gcc/g++ 的使用。 在学习 gcc/g++ 之前,我们先来简单

    2024年02月12日
    浏览(35)
  • C语言从入门到精通第16天(指针的定义与基本使用)

    在使用指针之前我们需要对指针进行初步的了解,首先我们要知道什么是指针? 通过前面的学习我们已经知道了内存的存储方式,他是通过一个字节一个字节的连续存储单位进行内存的存储,每一个字节我们称为一个内存单元。为了能够正确的访问这些内存单元,就必须为每

    2024年02月02日
    浏览(25)
  • Superset 使用手册 -- 从入门到精通 (基本使用+权限管理+可视化实时刷新) 爆肝七天力作

    第一部分Superset 基本使用 1.1 对接数据源(目前支持mysql、hive、es) 登录superset后,点Databases 点这里 选择数据源 按要求填写(把=后面的东西黏贴到url里) Elasticsearch= elasticsearch+http://{user}:{password}@{host}:9200/ Hive = hive://hive@{hostname}:{port}/{database} Mysql = mysql://:@/ 出现这个表示连接成

    2023年04月24日
    浏览(27)
  • CBV添加装饰器的三种方式

    2024年02月08日
    浏览(25)
  • C#从入门到精通之第一篇: C#概述与入门

    1.1 C#概述 C#语言及特点 C#是微软公司发布的一种面向对象的、运行于.NET Framework和 .Net Core(完全开源,跨平台能够在Windows/Linux上运行)之上的高级程序设计语言。 C#是一种安全的、稳定的、简单的、优雅的,由C和C++衍生出来的面向对象的编程语言。它在继承C和C++强大功能的

    2024年02月04日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包