复习

上节课复习: 1、什么是元类 元类是我们自定义类的类,即我们用class定义的类本质 就是在实例化元类 class Foo: #Foo=元类('类名',(obejct),class_dic) pass obj=Foo() 2、为何用用元类+如何用? 2.1 控制class定义类的过程 class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #控制逻辑 super().__init__(class_name,class_bases,class_dic) class Foo(object,metaclass=Mymeta): #Foo=Mymeta('Foo',(object,),{'x':1,....}) x=1 2.2 控制对象(指的就是Foo的对象)的产生过程 class Mymeta(type): def __call__(self,*args,**kwargs): obj=self.__new__(self) #self=Foo self.__init__(obj,*args,**kwargs) return obj class Foo(object,metaclass=Mymeta): #Foo=Mymeta(...) def __init__(self,x,y): self.x=x self.y=y obj=Foo(x=1,y=2) 今日内容: 1、单例模式的三种实现方式 2、异常处理
元类补充

class Mymeta(type): n=444 def __call__(self, *args, **kwargs): obj = self.__new__(self) # self=Foo # obj = object.__new__(self) # self=Foo self.__init__(obj, *args, **kwargs) return obj class A(object): n=333 # pass class B(A): n=222 # pass class Foo(B,metaclass=Mymeta): # Foo=Mymeta(...) n=111 def __init__(self, x, y): self.x = x self.y = y print(Foo.n) #查找顺序: #1、先对象层:Foo->B->A->object #2、然后元类层:Mymeta->type # print(type(object)) # obj=Foo(1,2) # print(obj.__dict__)
练习

class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #控制类Foo的创建 # if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0: # raise TypeError('类中必须有文档注释,并且文档注释不能为空') # if not class_name.istitle(): # raise TypeError('类名首字母必须大写') super(Mymeta,self).__init__(class_name,class_bases,class_dic) def __call__(self, *args, **kwargs): #控制Foo的调用过程,即Foo对象的产生过程 obj = self.__new__(self) self.__init__(obj, *args, **kwargs) obj.__dict__={'_%s__%s' %(self.__name__,k):v for k,v in obj.__dict__.items()} #对象的属性变成隐藏属性 return obj class Foo(object,metaclass=Mymeta): # Foo=Mymeta(...) def __init__(self, name, age,sex): self.name=name self.age=age self.sex=sex obj=Foo('egon',18,'male') obj.name='alex' print(obj.__dict__)
单利模式

''' 1、什么是单例模式 单例模式:基于某种方法实例化多次得到实例是同一个 2、为何用单例模式 当实例化多次得到的对象中存放的属性都一样的情况,应该将多个对象指向同一个内存,即同一个实例 3、如何用 ''' # 单例模式实现方式一: # import settings # # class Mysql: # __instacne=None # # def __init__(self,ip,port): # self.ip=ip # self.port=port # # @classmethod # def from_conf(cls): # if cls.__instacne is None: # cls.__instacne=cls(settings.IP,settings.PORT) # return cls.__instacne # # obj=Mysql('1.1.1.10',3306) # # obj1=Mysql.from_conf() # obj2=Mysql.from_conf() # obj3=Mysql.from_conf() # # print(obj1) # print(obj2) # print(obj3) # # obj4=Mysql('10.10.10.11',3307) # 单例模式实现方式二: # import settings # def singleton(cls): # cls.__instance=cls(settings.IP,settings.PORT) # def wrapper(*args,**kwargs): # if len(args) == 0 and len(kwargs) == 0: # return cls.__instance # return cls(*args,**kwargs) # return wrapper # # @singleton #Mysql=singleton(Mysql) #Mysql=wrapper # class Mysql: # def __init__(self,ip,port): # self.ip=ip # self.port=port # # # obj1=Mysql() #wrapper() # obj2=Mysql() #wrapper() # obj3=Mysql() #wrapper() # print(obj1 is obj2 is obj3) # print(obj1) # print(obj2) # print(obj3) # obj4=Mysql('1.1.1.4',3308) # print(obj4) # 单例模式实现方式三: import settings class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #self=Mysql super(Mymeta,self).__init__(class_name,class_bases,class_dic ) self.__instance=self.__new__(self) #造出一个Mysql的对象 self.__init__(self.__instance,settings.IP,settings.PORT) #从配置文件中加载配置完成Mysql对象的初始化 # print(self.__instance) # print(self.__instance.__dict__) def __call__(self, *args, **kwargs): #self=Mysql if len(args) == 0 and len(kwargs) == 0: return self.__instance obj=self.__new__(self) self.__init__(obj,*args,**kwargs) return obj class Mysql(object,metaclass=Mymeta): #Mysql=Mymeta(...) def __init__(self,ip,port): self.ip=ip self.port=port obj1=Mysql() obj2=Mysql() obj3=Mysql() obj4=Mysql('10.10.10.11',3308) print(obj1) print(obj2) print(obj3) print(obj4)
面向对象相关知识

一 什么是面向对象的程序设计及为什么要有它,与面向过程的程序设计优劣对比以及应用场景 二 类和对象 3.1 什么是对象,什么是类 3.2 类的属性引用和实例化 3.3 对象的属性引用 3.4 对象之间的交互 3.5 类名称空间与对象/实例名称空间 三 继承与派生 4.1 什么是继承 4.2 继承与抽象(先抽象再继承) 4.3 继承与重用性 4.4 组合与重用性 四 4.6 抽象类 五 4.7 继承实现的原理(继承顺序:深度优先,广度优先) 4.8 子类中调用父类方法 六 多态与多态性 5.1 多态 5.2 多态性 七 封装 6.1 要封装什么 6.2 为什么要封装 6.3 封装分为两个层面 八 property,绑定到对象的方法,绑定到类的方法,解除绑定的方法 九 反射 十 isinstance,issubclass,__str__,__slots__ 十一 __del__ 十二 __call__,元类

# # 一 什么是面向对象的程序设计及为什么要有它,与面向过程的程序设计优劣对比以及应用场景 # 核心是对象,对象是特征与技能的结合体,基于面向对象设计程序好比在创造一个世界,你就是这个世界的上帝,存在的皆为对象 # 不存在的也可以创造出来,与面向过程机械式的思维方式形成鲜明的对比,面向对象更加注重对显示世界的模拟,是一种上帝式的思维方式 # # 优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。 # # 缺点: # 1. 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。一些扩展性要求低的场景使用面 # 向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。 # # 2无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题 # ,即便是上帝也无法准确地预测最终结果。于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能 # ,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。 # # 应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方 # 二 类和对象 # 3.1 什么是对象,什么是类 # 类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体 # 3.2 类的属性引用和实例化 # .:专门用来访问属性,本质操作的就是__dict__ # s1=OldboyStudent() #调用类,或称为实例化,得到对象 # 3.3 对象的属性引用 # s2.name # 在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常 # 3.4 对象之间的交互 # 3.5 类名称空间与对象/实例名称空间 # 类中可以有任意python代码,这些代码在类定义阶段便会执行 # 因而会产生新的名称空间,用来存放类的变量名与函数名 # 先调用类产生空对象,然后调用 类.__init__(s1,'李坦克','男',18) 放入名称空间 # # 三 继承与派生 # 4.1 什么是继承 # 继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承), # 父类又可称为基类或超类,新建的类称为派生类或子类。 # 子类会“”遗传”父类的属性,从而解决代码重用问题 # 4.2 继承与抽象(先抽象再继承) # 继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。 # 4.3 继承与重用性 # 通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用 # 4.4 组合与重用性 # 组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合 # 用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系 # # 四 # 4.6 抽象类 #归一化 # import abc #利用abc模块实现抽象类 # class All_file(metaclass=abc.ABCMeta): # @abc.abstractmethod #定义抽象方法,无需实现功能 # 五 # 4.7 继承实现的原理(继承顺序:深度优先,广度优先) # c3 mro # 经典类:深度优先 # 新式类:广度优先 # 4.8 子类中调用父类方法 # Vehicle.__init__(self,name,speed,load,power) # # super(Subway,self)).__init__(name,speed,load,power) # super().__init__(name,speed,load,power) # # 六 多态与多态性 # 5.1 多态 # 5.2 多态性 # 无任何关系,但是方法名一样 松耦合 # import abc # class File(metaclass=abc.ABCMeta): #同一类事物:文件 # @abc.abstractmethod # def click(self): # pass # # # 七 封装 # 6.1 要封装什么 # 在python中用双下划线开头的方式将属性隐藏起来(设置成私有的) # 6.2 为什么要封装 # 限制外部的直接访问。 # 变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形 # 6.3 封装分为两个层面 # 1:封装数据:将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口, # 然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。 # 2:封装方法:目的是隔离复杂度 # # 八 property,绑定到对象的方法,绑定到类的方法,解除绑定的方法 # @property @name.setter @name.deleter 伪装 # @classmethod @staticmethod # # 九 反射 #hasattr getattr setattr delattr # # 十 isinstance,issubclass,__str__,__slots__ # isinstance(obj, Foo) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 # issubclass(Bar, Foo) issubclass(sub, super)检查sub类是否是 super 类的派生类 # 十一 __del__ #如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源 #比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__ # # 十二 __call__,元类 # 对象后面加括号,触发执行。 #
重点代码

class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #控制类Foo的创建 if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0: raise TypeError('类中必须有文档注释,并且文档注释不能为空') if not class_name.istitle(): raise TypeError('类名首字母必须大写') super(Mymeta,self).__init__(class_name,class_bases,class_dic) def __call__(self, *args, **kwargs): #控制Foo的调用过程,即Foo对象的产生过程 obj = self.__new__(self) self.__init__(obj, *args, **kwargs) obj.__dict__={'_%s__%s' %(self.__name__,k):v for k,v in obj.__dict__.items()} #对象的属性变成隐藏属性 return obj class Foo(object,metaclass=Mymeta): # Foo=Mymeta(...) def __init__(self, name, age,sex): self.name=name self.age=age self.sex=sex obj=Foo('egon',18,'male') obj.name='alex' print(obj.__dict__) ######### settings 内容 IP='1.1.1.1' PORT=3306 单利模式1 类方法 import settings class Mysql: __instance=None def __init__(self,ip,port): self.ip=ip self.port=port @classmethod def from_conf(cls): if cls.__instance is None: cls.__instance=cls(settings.IP,settings.PORT) return cls.__instance obj1=Mysql.from_conf() obj2=Mysql.from_conf() obj3=Mysql.from_conf() obj4=Mysql('10.10.10.10',3307) print(obj1) print(obj2) print(obj3) print(obj4) 单例模式2 装饰器 import settings def singleton(cls): _instance = cls(settings.IP,settings.PORT) def wrapper(*args,**kwargs): if len(args) == 0 and len(kwargs) == 0: return _instance return cls(*args,**kwargs) return wrapper @singleton class Mysql: def __init__(self,ip,port): self.ip=ip self.port = port obj1=Mysql() obj2=Mysql() obj3=Mysql() obj4=Mysql('2.2.2.2',3307) print(obj1) print(obj2) print(obj3) print(obj4) 单利模式3 元类方式 import settings class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): super(Mymeta,self).__init__(class_name,class_bases,class_dic) self.__instance=self.__new__(self) self.__init__(self.__instance,settings.IP,settings.PORT) def __call__(self, *args, **kwargs): if len(args) == 0 and len(kwargs) == 0: return self.__instance obj= self.__new__(self) self.__init__(obj,*args,**kwargs) return obj class Mysql(object,metaclass=Mymeta): def __init__(self,ip,port): self.ip=ip self.port=port obj1=Mysql() obj2=Mysql() obj3=Mysql() obj4=Mysql('2.2.2.2',3309) print(obj1) print(obj2) print(obj3) print(obj4)