zoukankan      html  css  js  c++  java
  • python之装饰器初识

    一、@abstractmethod

    1、抽象类的作用:规范编程模式
    多人开发、复杂的需求、后期的扩展
    是一种用来帮助我们完成规范化的手段

    2、如何定义抽象类
    1,from abc import ABCMeta,abstractmethod
    2,在这个类创建的时候指定 metaclass = ABCMeta
    3,在你希望子类要实现的方法的上一行加上一个 @abstractmethod装饰器

    3、使用抽象类
    1,继承这个类
    2,必须实现这个类中被@abstractmethod装饰器装饰的方法

    4、实例

    # 支付功能
    
    from abc import ABCMeta, abstractmethod
    class Payment(metaclass=ABCMeta):  # 模板的功能
        @abstractmethod                               # abstractmethod是一个装饰器,装饰器怎么用?放在函数或者类的上一行
        def pay(self): pass
    
    # 这样就构建了一个抽象类Payment,并声明了子类必须要实现的方法是 pay(),若子类没有定义pay(),则实例化时会报错
    
    
    class Alipay(Payment):  # 继承了抽象类,就必须实现抽象类中被@abstractmethod装饰器装饰的方法 pay()
        def pay(self, money):
            print('使用支付宝支付了%s元' % money)
    
    
    class Wechatpay(Payment):
        def pay(self, money):
            print('使用微信支付了%s元' % money)
    
    
    class My_pay(Payment):  # 这里没有定义pay()方法,那么在实例化的时候机会报错
        def fuqian(self,money):
            print('你支付了%s元' % money)
    
    
    def pay(obj, money):
        obj.pay(money)
    
    
    # p = Payment()  # 报错 抽象类不能被实例化
    
    a = Alipay()
    # a.pay(100)
    pay(a,100)  # 使用支付宝支付了100元
    
    we = Wechatpay()
    # we.pay(200)
    pay(we,200)  # 使用微信支付了200元
    
    my = My_pay()  # 报错:类中没有定义抽象类的pay方法
    pay(my,300)
    View Code

    二、@property  setter deleter

    1、
    装饰器的分类:
    装饰函数
    装饰方法 : property
    装饰类

    装饰器函数都怎么用:
    在函数、方法、类的上面一行直接@装饰器的名字

    2、property是一个装饰器函数(就是用来解决刚才私有属性的问题)
    property:将一个方法伪装成一个属性

    2-1学生信息中,姓名不想给别人修改,就设置为私有属性,在定义一个同名的方法伪装成属性,便于查找

    class Student:
        def __init__(self,name,age):
            self.__name = name
            self.age = age
    
        @property
        def name(self):    # 声明了@property使用此方法的时候就可以不写括号,就伪装成了属性
            return self.__name
    
    xiaoming = Student('小明',18)
    print(xiaoming.name)  # 小明
    
    xiaoming.name = '小狗'  # 改:报错
    print(xiaoming.name)
    View Code

    2-2圆的半径可以修改,但是面积和周长应该是属性的形式比较正确,但是直接设置为属性,圆的半径改了后,
    周长和面积并不会改变

    class Circle:
        def __init__(self,r):
            self.r = r
            self.area = 3.14 * self.r ** 2
            self.perimeter = 2 * 3.14 * self.r
    c = Circle(6)
    print(c.area)  # 113.04
    print(c.perimeter)  # 37.68
    
    c.r = 3  # 改变了半径
    print(c.area)  # 113.04
    print(c.perimeter)  # 37.68
    View Code

    2-3因此上面的圆可以写成这样:

    class Circle:
        def __init__(self,r):
            self.r = r
    
        @property
        def area(self):
            return 3.14 * self.r ** 2
    
        @property
        def perimeter(self):
            return 2 * 3.14 * self.r
    
    c = Circle(6)
    print(c.area)  # 113.04
    print(c.perimeter)  # 37.68
    
    c.r = 3  # 改变了半径
    print(c.area)  # 28.26
    print(c.perimeter)  # 18.84
    View Code

    2-4完整的property

    1、定义
    一个方法被伪装成属性之后,应该可以执行一个属性的增删改查操作,
    增加和修改就对应着被setter装饰的方法,
    删除一个属性对应着被deleter装饰的方法。

    @property:把方法伪装成属性

    @被property装饰的方法名.setter:
    当被property装饰的方法,又实现了一个同名方法,且被setter装饰器装饰了,
    那么在对被装饰的方法赋值的时候,就会触发被setter装饰器装饰的方法,
    这个方法必须要传一个参数接收等号后面的值,
    是用来保护一个变量在修改的时候能够添加一些保护条件。

    @被property装饰的方法名.deleter:
    当被property装饰的方法,又实现了一个同名方法,且被deleter装饰器装饰了,
    那么在对被装饰的方法进行删除的操作时,就会触发被deleter装饰器装饰的方法,
    这个方法并不能在执行的时候真的删除这个属性,而是你在代码中执行什么就有什么效果.

    2、例题

    复制代码
    学生类
    class Student:
        def __init__(self,name):
            self.__name = name
    
        @property
        def name(self):
            return self.__name
    
        @name.setter
        def name(self,new):
            if type(new) is str:   #因为名字是字符串类型的,我们这样设置可以保证只能用字符串修改名字
                self.__name = new
    
        @name.deleter
        def name(self):
            del self.__name
    
    xiaoming = Student('小明')
    print(xiaoming.name)   #小明
    
    xiaoming.name = 123   # 不是字符串修改不了
    print(xiaoming.name)   # 小明
    
    xiaoming.name = '小花猫'
    print(xiaoming.name)   # 小花猫
    
    del xiaoming.name
    print(xiaoming.__dict__) # {} 空字典
    
    
    水果类:
    class Fruits:
        __discount = 0.7
    
        def __init__(self,price):
            self.__price = price
    
        @property
        def price(self):
            return self.__price * Fruits.__discount
    
        @price.setter
        def price(self,new):
            if type(new) is int or float:
                self.__price = new
    
        @price.deleter
        def price(self):
            del self.__price
    
    banana = Fruits(10)
    print(banana.price)  # 折扣价7.0
    
    
    banana.price = 9
    print(banana.price) # 折扣价6.3
    
    del banana.price
    print(banana.__dict__)  # {} 空字典
    复制代码

    3、总结

    被setter和deleter装饰的方法名必须和被property装饰的方法名一致,对象.方法名 不加括号 可以调用被property装饰的方法,
    当对被property装饰的方法赋值时,就会触发被setter装饰的方法,当对被property装饰的方法进行删除del操作时,就会触发
    被deleter装饰的方法。
    注意:(一般来说用的最多的是property,其他两个看情况而使用)

    三、@classmethod

    类方法:
    用@classmethod装饰
    类方法默认形参用cls表示,而不用self
    可以直接通过类去修改类的属性,不需要实例化

    复制代码
    class Fruits:
        __discount = 0.7  # 类的静态属性
    
        def __init__(self,price):
            self.__price = price  # 对象的私有属性
    
        @property
        def price(self):
            return self.__price * Fruits.__discount
    
        @classmethod
        def change_discount(cls,new):  # 类方法默认形参用cls表示,而不用self
            cls.__discount = new
    
    
    Fruits.change_discount(0.6)
    print(Fruits.__dict__)  # '_Fruits__discount': 0.6
    
    
    类方法的特点:
    只使用类中的资源,且这个资源可以直接用类名引用,那这个方法应该被改为一个类方法
    复制代码

    四、@staticmethod

    静态方法
    被@staticmethod装饰的方法,不使用类中的命名空间也不使用对象的命名空间,
    可以传参,也可以不传参,没有默认参数(self,cls),相当于一个类外的普通的方法,
    不同的是调用的时候需要 类名.方法名

    复制代码
    class Student:
        @staticmethod
        def login():
            print('登录成功')
    
    Student.login())
    复制代码
  • 相关阅读:
    hdu 3047 Zjnu Stadium(加权并查集)2009 Multi-University Training Contest 14
    hdu 5407 CRB and Candies(组合数+最小公倍数+素数表+逆元)2015 Multi-University Training Contest 10
    hdu 3635 Dragon Balls(加权并查集)2010 ACM-ICPC Multi-University Training Contest(19)
    hdu 3038 How Many Answers Are Wrong(种类并查集)2009 Multi-University Training Contest 13
    【进阶——种类并查集】hdu 1829 A Bug's Life (基础种类并查集)TUD Programming Contest 2005, Darmstadt, Germany
    hdu 1026 Ignatius and the Princess I(优先队列+bfs+记录路径)
    hdu2368Alfredo's Pizza Restaurant
    C#结课报告
    C#三个平台上的文件选择方法
    C#线程
  • 原文地址:https://www.cnblogs.com/yidashi110/p/10092244.html
Copyright © 2011-2022 走看看