day026学习笔记

类的约束

  • 作用

    在一些重要的逻辑,与用户数据相关等核心部分,要建立一种约束,避免发生错误(保护程序内部的核心代码完整)

  • 约束的方法

    • 在父类建立一种约束(通过抛出异常) -归一化思想

      通过继承实现,父类提前定义好方法,子类中无该方法时调用父类方法时抛出异常

      class Fpay:
          def pay(self):
              raise Exception("子类必须重新pay方法")
      
      class QQpay(Fpay):
      
          def pay(self):
              print(f"QQpay")
      
      class Alipay(Fpay):
          def pay(self):
              print("Alipay")
      
      class WXpay(Fpay):
          def pay1(self):
              print("微信支付")
      
      def pay(pay_func):  # 归一化设计
          pay_func.pay()
      
      q = QQpay()
      a = Alipay()
      w = WXpay()
      pay(q) #QQpay
      pay(w) #Exception: 子类必须重新pay方法
      
    • 引入抽象类的概念

      通过抽象类(规范)建立一种约束

      抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

      from abc import ABCMeta,abstractmethod #导入元类,抽象方法
      class Payment(metaclass=ABCMeta):#修改了元类,该元类可以创建抽象类
          @abstractmethod #声明抽象方法,只定义,不实现具体功能(但要求子类必须实现同名方法)
          def pay(self):
              #子类必须实现该功能
              pass
      
      • Python本身不提供抽象类和接口机制,要想实现抽象类,可以借助abc模块。ABC是 Abstract Base Class(抽象父类)的缩写
      • abc.ABCMeta是用来生成抽象基础类的元类。由它生成的类可以被直接继承,但是 抽象类不能直接创建对象(只能被继承)
      • @abstractmethod表明抽象方法,如果子类不具备@abstractmethod的方法,那么就会抛出异常
      class QQpay(Payment):
          def pay(self):
              print(f"QQpay")
      
      class Alipay(Payment):
          def pay(self):
              print("Alipay")
      
      class WXpay(Payment):
          def pay1(self):  #创建对象时就报错
              print("微信支付")
      
      def pay(pay_func):  # 归一化设计
          pay_func.pay()
      
      q = QQpay()
      a = Alipay()
      w = WXpay() #TypeError: Can't instantiate abstract class WXpay with abstract methods pay
      pay(q)
      

类方法

  • 概念

    • 指一个类中通过@classmethod修饰的方法
    • 第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法)
    • 调用:实例对象和类对象都可以调用
    • 类方法是将类本身作为对象进行操作的方法
  • 使用场景

    • 通过继承在定义一个子类对象时修改父类的类属性
    #举例
    class Class:
        __student_num = 0
        def __new__(cls, *args, **kwargs):
            if cls != Class:
                Class.add_student()
            return super().__new__(cls)
    
        def get_num(self):
            print(self.__student_num)
        @classmethod #声明定义一个类方法,可通过类名调用
        def add_student(cls):
            cls.__student_num += 1
    
    class Student(Class):
        def __init__(self, name):
            self.name = name
    #通过对象调用
    class1 = Class()
    class1.add_student()
    class1.add_student()
    class1.get_num() #2
    
    #间接通过类调用
    student1 = Student("张三")
    student2 = Student("李四")
    student3 = Student("王五")
    Class().get_num() #5
    

静态方法

  • 概念

    • 使用@staticmethod修饰的方法
    • 参数随意,没有“self”和“cls”参数,方法体中不能使用类或实例的任何属性和方法
    • 实例对象和类对象都可以调用(也只能通过类和对象去调用)
    • 静态方法是一个孤立的函数方法,仅仅是被放在类中
    import time
    class TimeTest:
        def __init__(self, hour, minute, second):
            self.hour = hour
            self.minute = minute
            self.second = second
    
        def show_time(self):
            return self.showTime()
    	
        @classmethod
        def show_time2(cls):
            return cls.showTime()
    
        @staticmethod #声明创建普通函数
        def showTime():
            return time.strftime("%H:%M:%S",time.localtime())
    
    
    print(TimeTest.showTime()) #通过类直接调用
    print(TimeTest.show_time2()) #通过类间接调用
    t = TimeTest(1,2,3)
    print(t.showTime()) #通过对象直接调用
    print(t.show_time()) #通过对象间接调用
    
  • 作用

    • 托管函数
    • 便于维护
    • 使逻辑更有调理

property

  • 概念

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

  • 作用

    • 将方法伪装成属性用于调用(将对象的方法封装为属性)
    • 在外部看来是自动生成的属性
    • 遵循了统一访问的原则
    • 可进一步对数据进行约束
  • 访问方式

    • 获取@property
    • 修改@property下方法名.setter
    • 删除(不常用)@property下方法名.deleter
    #实现一:只有在属性定义property后才能定义setter,deleter
    class Person:
        def __init__(self, age):
            self.__age = age
    
        @property #将age方法封装,功能是获取私有属性__age
        def age(self):
            return self.__age
    
        @age.setter #定义同名设置方法用于修改私有属性
        def age(self,num):
            if 0 < num <150:
                self.__age = num
        @age.deleter #定义同名设置方法用于删除私有属性
        def age(self):
            del self.__age
    
    xiaoM = Person(18)
    print(xiaoM.age) #18
    xiaoM.age = 20 #可修改
    print(xiaoM.age) #20
    
    del xiaoM.age #可删除
    print(xiaoM.age) #AttributeError: 'Person' object has no attribute '_Person__age'
    
    #实现二:可针对性给封装后的属性功能
    class Person:
        def __init__(self, age):
            self.__age = age
    
        def get_age(self):
            return self.__age
    
        def set_age(self,num):
            if 0 < num <150:
                self.__age = num
            else:
                raise Exception("年龄设置错误")
    
        def del_age(self):
            del self.__age
    
        age = property(fget=get_age,fset=set_age,fdel=del_age)#将三种功能赋予age(可设置None)
    
    xiaoM = Person(18)
    print(xiaoM.age)
    xiaoM.age = 220
    print(xiaoM.age) #超限会抛出异常
    
    del xiaoM.age
    print(xiaoM.age)
    

反射

  • 概念

    • 指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
    • python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
  • 实现反射的方法

    • hasattr 检测是否含有某属性

      • 对象:包含类和对象所有的属性
      • 类:只检测类的属性
      class Foo:
          f = '类变量'
          def __init__(self, name, age):
              self.name = name
              self.age = age
          def say_hi(self):
              print('hi,%s' % self.name)
      
      obj = Foo('小明', 73)
      
      print(hasattr(Foo,'name')) #False
      print(hasattr(obj,'name')) #True
      print(hasattr(obj,'age1')) #False
      print(hasattr(obj,'f')) #True
      print(hasattr(obj,'say_hi')) #True
      print(obj.__dict__)
      print(Foo.__dict__)
      
    • getattr 获取属性的值(必须有)

      print(getattr(obj,"name")) #小明
      b = getattr(obj,"say_hi") #可获取方法内存地址
      b() #hi,小明
      
    • setattr 设置属性,该属性不一定是存在的

      • 设置类属性,类和对象都可使用,但定义函数时需要加self

        setattr(Foo,"sex","男")
        print(obj.sex) #男
        def eat1(self):
            print("吃")
        setattr(Foo,"eat",eat1)
        obj.eat() #吃
        print(hasattr(obj,'eat')) #True
        
      • 设置对象属性,只能通过对象去访问,且不用加self

      • 综合用法(判断属性不存在时设置该属性)

        getattr(obj, "age", setattr(obj, "age", "18")) 
        
    • delattr 删除属性

      delattr(obj,'name')
      print(obj.name) #被删除后报错
      
  • 反射应用举例(判断方法是否在类中从而调用方法)

    class User:
        def login(self):
            print('欢迎来到登录页面')
        def register(self):
            print('欢迎来到注册页面')
        def save(self):
            print('欢迎来到存储页面')
    
    user = User()
    while True:
        choose = input('>>>').strip()
        if hasattr(user,choose):
            func = getattr(user,choose)
            func()
        else:
            print('输入错误。。。。')
    
posted @ 2019-10-13 20:04  寂静四月  阅读(103)  评论(0)    收藏  举报