zoukankan      html  css  js  c++  java
  • Python基础学习(26)classmethod/staticmethod 装饰器 部分内置魔术方法

    Python基础学习(26)classmethod/staticmethod 装饰器 部分内置魔术方法

    一、今日内容大纲

    • classmethod staticmethod 装饰器
    • 部分内置魔术方法

    二、classmethod staticmethod 装饰器

    1. classmethod 装饰器:对装饰的绑定方法会变成类方法

      为了了解 classmethod 装饰器到底有什么作用,我们继续使用之前举过的售卖苹果的例子:

      class Goods:
          __discount = 0.8
          def __init__(self):
              self.__price = 5
              self.price = self.__price * self.__discount
      
      apple = Goods()
      print(apple.price)  # 4.0
      

      这时我们如果想修改折扣为 6 折,可以进行下列修改:

      # 修改折扣 0.6
      class Goods:
          __discount = 0.8
          def __init__(self):
              self.__price = 5
              self.price = self.__price * self.__discount
          def change_discount(self, new_discount):  # self参数没有利用
              Goods.__discount = new_discount
      # 虽然成功修改了,但是好像有点儿不和逻辑
      apple = Goods()
      apple.change_discount(0.6)
      apple2 = Goods()
      print(apple2.price)  # 3.0
      

      可以看到,虽然我们能够成功实现修改购物商场的全场折扣,但是内置方法中的 self 参数是完全没有利用的,且修改全场折扣要利用到个别对象的绑定方法,也就是说我们如果想要修改整个全场折扣,还要首先实例化一个对象,再依靠对象来修改折扣。这样显然是不符合正常逻辑的,所以我们使用 classmethod 装饰器来将此方法定义为一个类方法:只可以被类调用(实际使用其实也可以被对象调用,但是一般不可以这么使用):

      # 定义了一个方法,默认传self,但这个self没被使用,
      # 这时我们使用classmethod装饰器
      class Goods:
          __discount = 0.8
          def __init__(self):
              self.__price = 5
              self.price = self.__price * self.__discount
          @classmethod
          def change_discount(cls, new_discount):  # 将self换成类名传入
              cls.__discount = new_discount
      
      Goods.change_discount(0.6)  # 可以直接使用方法名修改,无需先实例化
      apple2 = Goods()
      print(apple2.price)  # 3.0
      

      所以一般什么情况下,才使用 classmethod 装饰器呢?

      • 定义了一个方法,默认传 self,但是这个 self 没有被使用;
      • 这个方法里用到了当前的类名,或者你准备使用这个类的内存空间中的名字的时候;

      我们来举一个实际应用中的例子:定义一个类Date,内部有年、月、日等实例变量,Date.today()可以返回一个存储当天年月日的对象。

      import time
      class Date:
          def __init__(self, year, month, day):
              self.year = year
              self.month = month
              self.day = day
          @classmethod
          def today(cls):
              obj = cls(time.localtime().tm_year, time.localtime().tm_mon, time.localtime().tm_mday)
              return obj
      
      time_obj = Date.today()
      print(time_obj.__dict__)
      
    2. staticmethod 装饰器:被装饰的绑定方法会变成一个静态方法

      class User:
          pass
          @staticmethod  # 本身是一个普通的函数,被挪到类的内部执行,那么直接给这个函数添加了@staticmethod装饰器就可以了
          def login():
              print('login')
              # 在函数的内部不会用到self变量,也不会用到cls类
      
      User.login()  # 除了前面要加上类名,其他使用方式与普通函数一致
      
    3. 小结

      能定义到类的内容主要有:

      • 静态方法
      • 绑定方法
      • 类方法:利用 classmethod 装饰器装饰绑定方法实现
      • 静态方法:利用 staticmethod 装饰器装饰绑定方法实现
      • 属性/实例变量:可直接在__init__中定义或者利用 property 装饰器装饰绑定方法实现
      • 静态变量

    三、部分内置魔术方法

    1. 总览

      魔术方法主要是指 Python 内置的__func__形式的方法,主要包括:

      • __new__
      • __call__
      • __len__
      • __eq__
      • __str__
      • __repr__
      • __del__
      • __enter__
      • __exit__
    2. __call__方法:object_name()调用此对象所属类的__call__方法。

      class A:
          def __call__(self, *args, **kwargs):
              print('----------')
      
      obj = A()
      print(callable(obj))  # True
      obj()  # 调用__call__方法 ----------
      
    3. __len__方法:len(object_name)调用此对象所属类的__call__方法。

      class Cls:
          def __init__(self, name):
              self.name = name
              self.students = []
          def __len__(self):
              return len(self.students)
      py22 = Cls('py22')
      py22.students.append('duxiangxi')
      py22.students.append('taibai')
      py22.students.append('dazhuang')
      print(len(py22.students))  # 3
      # 这两者是等价的
      print(len(py22))  # 3
      print(py22.__len__())  # 3
      
    4. __new__方法:__new__方法就是在实例化之前所完成的操作,实例化的过程会先执行__new__方法,再执行__init__方法,实例化过程返回的对象也就是__new__返回的对象。

      # __new__
      class A:
          def __new__(cls, *args, **kwargs):
              o = super().__new__(cls)
              # o = object.__new__(cls)  # 因为父类是object也可以这么写
              print('new', o)
              return o
      
          def __init__(self):
              print('init', self)
      
      
      A()
      
      
      # new <__main__.A object at 0x0000016947968B38>
      # init <__main__.A object at 0x0000016947968B38>
      
      # 实例化的时候
      # 先创建一块对象空间,有一个指针能指向类 -> 由__new__完成
      # 调用__init__
      
      # __new__是一个构造方法
      
      
      # 为什么要自己实现一个__new__呢?
      
      
      # 设计模式 --> 单例模式
      # 一个类 从头到尾 只会创建一次self的空间
      class Baby:
          __instance = None
      
          def __new__(cls, *args, **kwargs):
              if cls.__instance is None:
                  cls.__instance = super().__new__(cls)
              return cls.__instance
      
          def __init__(self, cloth, pants):
              self.cloth = cloth
              self.pants = pants
      
      
      b1 = Baby('红毛衣', '绿皮裤')
      b2 = Baby('白衬衫', '黑豹纹')
      print(b1)  # <__main__.Baby object at 0x0000022322CFDB00>
      print(b2)  # <__main__.Baby object at 0x0000022322CFDB00>
      print(b1.cloth)  # 白衬衫
      print(b2.cloth)  # 白衬衫
      
      
      # 利用模块的方式实现单例模式是最便捷的方法
      
    5. __str____repr__方法:在打印一个对象或者len(object_name)的时候,调用对象内部的__str__方法,如果对象内部不存在__str__方法则会调用备用的__repr__方法。

      # 2.__str__  __repr__
      class Course:
          def __init__(self, name, price, period):
              self.name = name
              self.price = price
              self.period = period
      
          def __str__(self):  # 它只能返回str数据类型
              return ','.join([self.name, str(self.price), self.period])
      
      
      python = Course('python', 21800, '6 months')
      linux = Course('linux', 19800, '3 months')
      mysql = Course('mysql', 12800, '4 months')
      go = Course('python', 21800, '4 months')
      print(go)  # python,21800,4 months
      lst = [python, linux, mysql, go]
      for course in lst:
          print(course)
      # for index, c in enumerate(lst, 1):
      #     print(index, c.name, c.price, c.period)
      # num = int(input('>>>'))
      # course = lst[num-1]
      # print(f'you choose {course.name} {course.price}.')
      # 在打印一个对象的时候,调用__str__方法
      # 在str一个对象的时候,调用__str__方法
      
      # 当我们打印一个对象的时候, 用%s进行字符串批结,或者str(对象) 总是调用这个对象的__str__方法
      # 如果找不到__str__就调用__repr__方法
      
      # __repr__不仅仅是__str__的替代品,还有自己的功能
      # 用%r进行字符串拼接 或者用repr(对象)的时候总是调用这个对象的__repr__方法
      
  • 相关阅读:
    读取Java文件到byte数组的三种方式
    https://blog.csdn.net/eguid_1/article/category/6270094
    JavaCV 学习(一):JavaCV 初体验
    WebService服务发布与使用(JDK自带WebService)
    SourceTree 免登录跳过初始设置
    Owin password
    IIS并发
    压力测试
    nginx
    消息队列MSMQ
  • 原文地址:https://www.cnblogs.com/raygor/p/13378562.html
Copyright © 2011-2022 走看看