面向对象的装饰器

发布时间:2024年01月11日

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

文章来源:https://blog.csdn.net/m0_58310590/article/details/135532294
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。