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('输入错误。。。。')
浙公网安备 33010602011771号