面向对象的装饰器

【 1 】什么是property

  • property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

【 2 】使用方法和具体实例

面向对象的装饰器是一种在面向对象编程中用于修改类或方法行为的技术。装饰器提供了一种灵活的方式。可以在不修改原始类或方法的情况下, 动态的添加额外的功能或修改其行为。
在Python中, 装饰器通常以函数的形式存在。当应用于类或方法时, 装饰器将被调用,并且可以对目标或方法进行修改或扩展。
面向对象的装饰器可以用于以下几个方面:
  1. 类装饰器: 类装饰器用于修改或扩展整个类的行为。它接收一个类作为参数,并返回修改后的类。类装饰器可以用于添加类级别的属性、修改方法的行为、扩展类的功能等
  2. 方法装饰器: 方法装饰器用于修改单个方法的行为。它接收一个方法作为参数,并返回修改后的方法。方法装饰器可以用于添加额外的逻辑、实现缓存、实现权限控制登。
  3. 属性装饰器: 属性装饰器用于修改类的属性的行为。它接收一个属性名作为参数,并返回修改后的属性描述。属性装饰器可以用于验证属性值、实现延迟加载等。、
    • @property装饰器将name方法转换为一个只读属性。当我们通过person.name的方式获取属性值时,实际上是调用了name方法,并返回其结果。

    • @name.setter装饰器将name方法转换为一个可写属性。当我们通过person.name = value的方式设置属性值时,实际上是调用了name方法,并将value作为参数传递给它。

    • @name.deleter装饰器将name方法转换为一个可删除属性。当我们使用del person.name的方式删除属性时,实际上是调用了name方法。

通过使用面向对象的装饰器,我们可以在不修改原始类或方法代码的情况下,动态地扩展其功能或修改其行为。

需要注意的是,在使用装饰器时,应该遵循装饰器的规范,并确保装饰器函数的签名和返回值与被装饰的类或方法一致,以确保正确的行为修改。

类装饰器:

class MyClass:
    @classmethod
    def class_method(cls):
        print("This is a class method.")
        print("Class name:", cls.__name__)

# 调用类方法,无需创建类的实例
MyClass.class_method()
# This is a class method.
#  Class name: MyClass

# 类装饰器的应用
#
user = {
    'username': 'mao',
    'password': 123
}
​
​
def add_method(cls):
    def new_method(self):
        username = input('请输入你的账号:')
        password = input('请输入你的密码:')
        if username in user['username'] and int(password) == user["password"]:
            print('登陆成功!')
        else:
            print('用户名或密码错误!')
​
    cls.new_method = new_method  # 添加新方法到类中
    return cls
​
​
@add_method
class MyClass:
    def existing_method(self):
        print("Existing method in the class")
​
​
if __name__ == '__main__':
    obj = MyClass()
    obj.existing_method()  # 输出:Existing method in the class
    obj.new_method()   

方法装饰器:

import random
​
​
user = {'username': 'mao',
        'password': 123}
​
​
def get_code():
    result = ""
    for _ in range(4):
        random_int = str(random.randint(0, 9))
        temp = random.choice([random_int])
        result += temp
    return result
res = get_code()
​
​
def outter(func):
    def inner(*args, **kwargs):
​
        print('登陆之前先输入验证码!')
        res = func(*args, **kwargs)
        username = input('请输入你的账号!')
        password = input('请输入你的密码:')
​
        if user['username'] == username and user['password'] == int(password):
            print('登陆成功!')
        else:
            print('用户密码错!')
        return res
    return inner
​
class MyClass:
    @outter
    def my_method(self):
        # 生产验证码并提示输入
        code = get_code()
        print(f'请输入下面的验证码进行注册:{code}')
        input_code = input('请输入你的验证码!')
​
        if input_code != code:
            print('验证码错误! ')
            return
​
​
obj = MyClass()
obj.my_method()
# 添加课程
import random
​
user = {'username': 'mao', 'password': 123}
​
​
def get_code():
    result = ""
    for _ in range(4):
        random_int = str(random.randint(0, 9))
        temp = random.choice([random_int])
        result += temp
    return result
​
​
def verify_code(func):
    def wrapper(*args, **kwargs):
        code = get_code()
        print(f'请输入下面的验证码进行操作:{code}')
        input_code = input('请输入你的验证码!')
​
        if input_code != code:
            print('验证码错误!')
            return
​
        result = func(*args, **kwargs)
        return result
​
    return wrapper
​
​
def outter(func):
    def inner(*args, **kwargs):
        print('登陆之前先输入验证码!')
​
        username = input('请输入你的账号!')
        password = input('请输入你的密码:')
​
        if user['username'] == username and user['password'] == int(password):
            print('登陆成功!')
            res = func(*args, **kwargs)
            return res
        else:
            print('用户密码错!')
            exit()
​
    return inner
​
​
class Login:
    @verify_code
    def add_course(self):
        course_name = input('请输入课程名称:')
        print(f'成功添加课程:{course_name}')
​
    @outter
    def login(self):
        ...
​
​
obj = Login()
obj.login()  # 调用登陆方法
​
obj.add_course()  # 调用添加课程方法

属性装饰器:

# 属性装饰器
class MyClass:
    def __init__(self):
        self._name = None
        # 我们在这里name设置为受保护属性
​
    @property
    # 这里的property是将我们的_name重新设定为可读属性
    def name(self):
        return self._name
​
    @name.setter
    # 将name方法转换为一个可写属性。
    def name(self, value):
        self._name = value.capitalize()
​
obj = MyClass()
​
# 使用属性装饰器设置属性值
obj.name = 'john doe'
​
# 使用属性装饰器获取属性值
print(obj.name)  # John doe

小试牛刀:

class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password
​
    @property
    def username(self):
        return self._username
​
    @username.setter
    def username(self, value):
        if not isinstance(value, str):
            raise ValueError('用户名必须是字符串!')
        self._username = value
​
    @property
    def password(self):
        return self._password
​
    @password.setter
    def password(self, value):
        if not isinstance(value, str):
            raise ValueError('密码必须是字符串!')
        self._password = value
​
    def login(self, username, password):
        if username == self.username and password == self.password:
            print('登陆成功!')
        else:
            print('登陆失败!')
​
​
user = User('admin', '12186')
username = input('请输入你的账号: >>>>>>')
password = input('请输入你的密码: >>>>>>')
​
user.login(username, password)

【3】为什么要用property

  • 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

  • 面向对象的封装有三种方式:

    • 【public】

      • 这种其实就是不封装,是对外公开的

    • 【protected】

      • 这种封装方式对外不公开

      • 但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开

    • 【private】

      • 这种封装对谁都不公开

使用property的主要目的是为了实现对类的属性访问和修改的控制,以提供更加灵活和可靠的代码。

class Rctena:
    def __init__(self, width, height):
        self._width = width # 初始化宽度
        self._height = height # 初始化高度
​
    @property
    def width(self):
        return self._width
​
    @width.setter
    def width(self, value):
        if value > 0:
            self._width = value
        else:
            raise ValueError('宽度必须大于0')
​
    @property
    def height(self):
        return self._height
​
    @height.setter
    def height(self, value):
        if value > 0:
            self._height = value
        else:
            raise ValueError('高度必须大于0')
​
x = Rctena(10,6)
print(x.width,x.height)
​
​
x.height = 15
print(x.height)  # 输出:15
​
x.height = -5  #ValueError: 高度必须大于0

代码更加自然和简洁,同时提高了代码的可读性和可维护性。

总之,使用property装饰器可以提供更好的封装性、访问控制、可兼容性、代码一致性和易用性,以及对属性修改过程的控制能力。它是一种有效的编程技术,有助于编写高质量、可维护的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/312865.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

58.leetcode 最后一个单词的长度

一、题目 二、解答 1. 思路 分2种情况 第一种情况只有一个单词,不包含空格:这种情况直接返回单词本身的长度。第二种情况包含空格:先去掉首尾的空格,根据空格切割字符串生成一个字符串列表,返回倒数第一个索引位置字…

k8s集群配置NodeLocal DNSCache

一、简介 当集群规模较大时,运行的服务非常多,服务之间的频繁进行大量域名解析,CoreDNS将会承受更大的压力,可能会导致如下影响: 延迟增加:有限的coredns服务在解析大量的域名时,会导致解析结果…

大模型学习与实践笔记(五)

一、环境配置 1. huggingface 镜像下载 sentence-transformers 开源词向量模型 import os# 设置环境变量 os.environ[HF_ENDPOINT] https://hf-mirror.com# 下载模型 os.system(huggingface-cli download --resume-download sentence-transformers/paraphrase-multilingual-…

网站ICP备案和公安备案教程

由于最近华为云那边的服务器到期了,而续费的价格比较贵一点,刚好阿里云这边有活动就入手了一台,但是将网站迁移过来后发现又要进行ICP备案,那就备案呗。但是备案完成之后发现还有一个公安备案,真让人头大啊... 很多人也…

怎么挑选一体化污水处理设备

选择一体化污水处理设备是一个关键决策,它直接影响到污水处理系统的效能和运行成本。随着环保意识的日益提高,各种污水处理设备也不断地涌现出来。那么,在众多选项中,如何挑选一体化污水处理设备?本文将为您提供一些建…

17- Echarts 配置系列之:单轴 singleAxis

singleAxis: 用于展示只有一个数据维度的数据。它通常用于展示时间序列数据或者数值序列数据。 对于单轴的应用和绘制,其实就相当于我们平时的直角坐标系少一个 X 或者 Y ,然后进行图形绘制。 注意: 1.在使用单轴时&#xff0…

2024年最好用的简历编辑工具,助你腾飞职业生涯!

随着科技的不断发展,求职竞争也愈发激烈。在2024年,如何在众多求职者中脱颖而出成为关键问题。为了帮助大家在职业生涯中取得更好的机会,特别推荐一款在2024年最为出色的简历编辑工具——芊芊简历。 1. 创新的编辑功能 芊芊简历拥有直观易用…

使用JMeter发送FTP请求

使用jmeter发送FTP请求: FTP(File Transfer Protocol 文件传输协议)用于Internet上文件的双向传输。作为一个应用程序不同的操作系统也有不同的实现,为了保证可以跨平台,FTP程序都要遵循相同协议,FTP有上传…

05- OpenCV:图像操作和图像混合

目录 一、图像操作 1、读写图像 2、读写像素 3、修改像素值 4、Vec3b与Vec3F 5、相关的代码演示 二、图像混合 1、理论-线性混合操作 2、相关API(addWeighted) 3、代码演示(完整的例子) 一、图像操作 1、读写图像 (1)…

JVM基础(7)——ParNew垃圾回收器

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖&…

信息系统中的需求分析

软件需求是指用户对新系统在功能、行为、性能、设计约束等方面的期望。根据IEEE的软件工程标准词汇表,软件需求是指用户解决问题或达到目标所需的条件或能力,是系统或系统部件要满足合同、标准、规范或其他正式规定文档所需具有的条件或能力,…

监督学习 - 支持向量机(Support Vector Machines,SVM)

什么是机器学习 支持向量机(Support Vector Machines,SVM)是一种强大的机器学习算法,可用于解决分类和回归问题。SVM的目标是找到一个最优的超平面,以在特征空间中有效地划分不同类别的样本。 基本原理 超平面 在二…

亚马逊卖家福音:鲲鹏系统全自动化操作,让你的账号更安全、生意更畅通

我想向大家分享一款让我的生意更轻松、更高效的神奇工具——亚马逊鲲鹏系统。这是一款功能齐全的全自动化操作软件,简直就是我的电商利器。下面我将为大家详细介绍一下我在使用这个系统时的真实体验。 首先,亚马逊鲲鹏系统的全自动批量注册买家号功能真是…

maya , motionbuilder 骨骼动画相关操作与脚本

文章目录 maya 解除/增加父子关系maya 修改骨骼局部坐标系mb同时打开两个动画文件显示骨骼局部坐标系删除不需要的骨骼重命名骨骼 maya 解除/增加父子关系 解触: 右键->操作->解除父子关系 增加:鼠标中键拖拽 maya 修改骨骼局部坐标系 注意一般就是改旋转&…

练习-sizeof()和strlen()

目录 前言解题技巧一、sizeof()练习题1.1 整型数组1.1.1 一维整型数组1.1.2 二维整型数组 1.2 字符数组1.3 字符指针 二、strlen()练习题2.1 字符数组初始化时不包含\02.2 字符数组初始化包含\02.3 字符指针指向字符串常量 总结 前言 最近有点疲倦,啊啊啊&#xff…

CentOS7 搭建Hadoop集群

1.环境准备 准备三台Linux(CentOS7)服务器 IP服务器名称192.168.11.136Master192.168.11.137Slave01192.168.11.138Slave02 1.2修改配置文件 1.2.1修改hosts文件 # Master服务器 vi /etc/hosts192.168.11.137 Slave01 192.168.11.138 Slave02 192.1…

微短剧市场暴涨267.65%,用微短剧场景AUI Kit精巧入局

微短剧,不仅上头,更要上心。 微短剧,深度“拿捏”了这个碎片化时代,也是刚过去的2023年绕不开的热词。 与传统影视剧制作精益求精、耗时长相反,门槛与耗时“双低”恰恰成为了微短剧的独特优势,使其走上以量…

普通卷积、转置卷积(transposed convolution)的原理及运算步骤解释

1.首先声明一点,转置卷积不是卷积的逆运算,转置卷积也是一种卷积方式,作用是进行上采样!主要出现在分割和对抗神经网络模型中比较多。 2.其次,transposed convolution、fractionally-strided convolution 和 deconvol…

Hadoop分布式文件系统(三)

目录 一、Hadoop 1、MapReduce 1.1、理解MapReduce思想 1.2、分布式计算概念 1.3、MapReduce介绍 1.4、MapReduce特点 1.5、MapReduce局限性 1.6、MapReduce实例进程 1.7、MapReduce阶段组成 1.8、MapReduce数据类型 1.9、MapReduce官方示例 2、YARN 一、Hadoop 1…

leetcode 每日一题 2024年01月11日 统计出现过一次的公共字符串

题目 2085. 统计出现过一次的公共字符串 给你两个字符串数组 words1 和 words2 ,请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。 示例 1: 输入:words1 ["leetcode","is","amazing","a…