一.面向对象编程概述:
1.面向过程编程
面向过程编程:核心是过程二字,指的是解决问题的步骤 ,即先干什么,在干什么,好比一条流水线,是一种机械是的思维方式
一旦完成基本很少改变的场景,linux内核,git ,ApacheHTTPServer 等
缺点:扩展性能低下
2 面向对象编程
面向对象编程:基于面向对象设计程序好比在创造一个世界,你就是一个上帝,周围存在的事物都是对象,
不存在的也可以创造出来,与面向过程机械是的思维烦那个是形成鲜明对比,面向对象更加注重对现实世界的模拟,是一种上帝的思维方式\
优点:解决了程序的扩展性
缺点:编程的复杂度远高于面向过程
3:类与对象:
类即类别,种类,是面向对象设计最重要的概念,
对象是特征与技能的结合体
类是有一系列对象相似的特征与技能的结合体
4 类与对象的__init__方法:
# __init__方法 # 强调: # 1、该方法内可以有任意的python代码 # 2、一定不能有返回值 class People: country='China' x=1 def __init__(obj, name, age, sex): #obj=obj1,x='egon',y=18,z='male' # if type(name) is not str: # raise TypeError('名字必须是字符串类型') obj.name = name obj.age = age obj.sex = sex def run(self): print('----->', self) # obj1=People('egon',18,'male') obj1=People(3537,18,'male') # print(obj1.run) # obj1.run() #People.run(obj1) # print(People.run)
5 类的特殊属性
#python为类内置的特殊属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
""" class OldboyStudent: school = 'oldboy' #相同的特征 def choose_course(self): print('choose course') # print('>>>>') # print(OldboyStudent.__dict__) # print(OldboyStudent.school) # 调用类的过程称之为类的实例化,调用类的返回值称之为类的一个对象/实例 # 会产生一个对象然后返回 stu1=OldboyStudent() stu2=OldboyStudent() stu3=OldboyStudent() print(stu1.__dict__) print(stu2.__dict__) print(stu3.__dict__) stu1.name='lzq' stu1.age=78 stu1.sex='female' print(stu1.__dict__) stu2.name='wxb' stu2.age=8 stu2.sex='female' print(stu2.__dict__) stu3.name='jh' stu3.age=9 stu3.sex='female' print(stu3.__dict__) """ # 为对象定制自己独有的特征,简化方案二 """ class OldboyStudent: school = 'oldboy' #相同的特征 def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def choose_course(self): print('choose couese') a=OldboyStudent('ouyang',18,'male') print(a.__dict__) """ """ xxx=33333 class OldboyStudent: school = 'oldboy' # xxx=2222 yyy=333 def __init__(obj, name, age, sex): # print(OldboyStudent.yyy) print(yyy) obj.name = name #stu1.name='李铁蛋' obj.age = age #stu1.age=18 obj.sex = sex #stu1.sex='male' def choose_course(self): print('choosing course') # 1. 属性查找顺序 stu1=OldboyStudent('李铁蛋',18,'male') # print(stu1.__dict__) # print(OldboyStudent.__dict__) # stu1.xxx=111 # print(stu1.__dict__) # 先从对象自己的名称空间找,没有则去所属的类中找 # print(stu1.xxx) """ xxx=33333 class OldboyStudent: school = 'oldboy' # xxx=2222 yyy=333 count=0 def __init__(obj, name, age, sex): # print(OldboyStudent.yyy) # print(obj.yyy) OldboyStudent.count+=1 obj.name = name #stu1.name='李铁蛋' obj.age = age #stu1.age=18 obj.sex = sex #stu1.sex='male' def choose_course(self): print('choosing course') stu1=OldboyStudent('andy',18,'male') stu2=OldboyStudent('xiaohui',17,'female') stu3=OldboyStudent('刘银弹',28,'male') print(stu1.count) print(stu2.count) print(stu3.count)
1
二:面向对象之继承与派生
二.(一) : 继承
1 什么是继承
继承是一种新建类的方式,新建的类称之为子类,被继承的类称之为父类\基类\超类
Python 中继承的特点
1 子类可以遗传/重用父类的属性
2 Python 中一个子类可以同时继承多个父类
3 在继承背景下说,Python中的类可分为两种:新式类,经典类
新式类: 但凡继承了objict的类Foo以及该类的子类 都是新式类
在python3中一个类即便是没有显式地继承任何类,默认就会继承object
即python3中所有的类都是新式类
经典类: 没有继承object的类,以及该类的子类...都是经典类
在python2中才区分新式类与经典类,
python2中一个类如果没有显式地继承任何类,也不会继承object
2 为何要用继承:
减少类与类之间代码冗余
3
# 在子类中调用父类的方法:
# 方式一:指名道姓的,即父类名,父类方法
class Vehicle: Country='China' def __init__(self,name,speed,load,power): self.name=name self.speed =speed self.load=load self.power=power def run(self): print("哥哥要开始咯") class Subway(Vehicle): def __init__(self,name,speed,load,power,line): super().__init__(name,speed,load,power) self.line=line def run(self): print('该地铁的名字是%s,速度为%s,最大装载量是%s,动力来源是%s,%s线路'%(self.name,self.speed,self.load,self.power,self.line)) car1=Subway('中国高铁','100km/h','1000人/厢','100匹','12') car1.run()
4 在子类派生出的新方法中重用父类功能的方式一:
指名道姓的引用某一个类中的函数
总结:
1 与继承无关
2访问是类的函数,没有自动传值得效果
代码如下
class home: sate='河北省张家口市阳原县东城镇七马坊村' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class xiaohui(home): def __init__(self,name,age,sex,hobby='run'): home.__init__(self,name,age,sex) def f1(self): print("%s是我的名字"%self.name) pass class yong(home): def __init__(self,name,age,sex,hobby='play game'): home.__init__(self,name,age,sex) pass num1=xiaohui('晖晖',18,'女') num2=xiaohui('勇哥',18,'男') print(num1.__dict__) print(num2.__dict__)
5 在单继承背景下属性的查找优先级:对象-->对象的类-->父类-->父类
class f1: x=1 class f2(f1): # x=2 pass class f3(f2): # x=1 pass class f4(f3): # x=0 pass obj=f4() # obj.x=5 print(obj.x) print() class Foo: def f1(self): print('Foo.f1') def f2(self): print("Foo.f2") self.f1() class Bar(Foo): def f1(self): print('Bar.f1') obj=Bar() obj.f2()
6 在多继承背景下属性的查找优先级:
如果一个子类继承多个分支(多个分支没有共同继承一个非object的类)
此时属性查找的优先级是:对象-->对象的类-->按照从右到左的顺序一个分支一个分支的找下去
class G: # x='G' pass class E(G): # x='E' pass class F: # x='F' pass class B(E): # x='B' pass class C(F): # x='C' pass class D: x='D' pass class A(B,C,D): # x='A' pass obj=A() # obj.x=111 print(obj.x)
7 在子类派生出的新方法中重用父类功能的方式二:super() 必须在类中使用
在Python2中 super(自己的类名,自己的对象)
在Python3 中:super()
调用该函数会得到一个特殊的对象,该对象专门用来访问父类中的属性,完全参展mro 类表
总结:
1 严格依赖集成的mro列表
2 访问是绑定方法,有自定传值的效果
class OldboyPeople: school = 'Oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class OldboyStudent(OldboyPeople): def __init__(self,name,age,sex,score=0): super().__init__(name,age,sex) self.score=score def choose_course(self): print("%s choosing course"%self.name) class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex): super().__init__(name,age,sex) def score(self,stu,num): stu,score=num # stu1=OldboyStudent('泽强',18,'male') print(stu1.__dict__) teal=OldboyTeacher('egon',18,'male') print(teal.__dict__)
二(一) 派生
子类添加自己新的属性或者在自己这里重新定义这些属性而且不会影响到父类,需要注意的是,要是自己定义的属性和父类的同名,
在调用新增属性是,就以自己的为准
三.isinstance(obj,cls) 和 issubclass(sup,super)
1 .isinstance(obj,cls) 检查obj是否是cls 的类
class Foo(object): pass obj=Foo() isinstance(obj,Foo)
2. issubclass (sub,super) 检查sub类是否是super 类的派生类
class Foo(object): pass class Bar(Foo): pass print(issubclass(Bar,Foo))
四.反射
1.Python面向对象中的反射:通过字符串的形式操作对象相关的属性,python中的一切事物都是对象
hasattr(object,name) : 判断object中有没有一个name字符串对应的方法或者属性
getattr(object,name,default=None) : 从对象中获取命名属性;getattr(x, 'y')等于x。y。
当给定一个默认参数时,它会在属性没有给出时返回
存在;如果没有它,就会在这种情况下引发异常。
setattr(x,y,z) 将给定对象上的命名属性设置为指定的值。setattr(x, y, v)等于x。y = v”
delattr(x,y) 从给定对象中删除命名属性。
四个方法的演示如下
#反射:通过字符串来反射/映射到对象/类的属性上 class People: def __init__(self,name,age): self.name=name self.age=age def run(self): print('%s is running' %self.name) obj=People('egon',18) # print(obj.__dict__) # print(obj.name) #obj.__dict__['name'] # obj.name='EGON' #obj.__dict__['name']='EGON' # # del obj.name # del obj.__dict__['name'] # # obj.sex='male' #obj.__dict__['sex']='male' # attr=input('>>>: ').strip() #attr='name' # obj.'name' # print(hasattr(obj,'name')) # 'name' in obj.__dict__ # print(getattr(obj,'name')) # obj.__dict__['name'] # print(getattr(obj,'xxx',None)) # obj.__dict__['xxx'] # setattr(obj,'name','EGON') #obj.__dict__['name']='EGON' # setattr(obj,'xxx',1111) #obj.__dict__['xxx']=111 # print(obj.name) # print(obj.__dict__) # delattr(obj,'name') # print(obj.__dict__) # import os # os.remove # print(hasattr(os,'remove')) class Ftp: def get(self): print('get') def put(self): print('put') def login(self): print('login') def run(self): while True: cmd=input('>>>: ').strip() #cmd='get' if hasattr(self,cmd): method=getattr(self,cmd) method() else: print('输入的方法不存在') obj=Ftp() obj.run()
三.__setattr__,__delattr__,__getattr__
class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value): print('----> from setattr') # self.key=value #这就无限递归了,你好好想想 # self.__dict__[key]=value #应该使用它 def __delattr__(self, item): print('----> from delattr') # del self.item #无限递归了 self.__dict__.pop(item) #__setattr__添加/修改属性会触发它的执行 f1=Foo(10) print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 f1.z=3 print(f1.__dict__) #__delattr__删除属性的时候会触发 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作 del f1.a print(f1.__dict__) #__getattr__只有在使用点调用属性且属性不存在的时候才会触发 f1.xxxxxx
四> 内置方法:
1 .__str__:在对象被打印时自动触发,可以用来风衣对象被打印时的输出信息
注意:必须返回一个字符串类型的值
# class People: # def __init__(self, name, age): # self.name = name # self.age = age # # def __str__(self): # # print('run..........') # return '<name:%s age:%s>' % (self.name, self.age) # obj1 = People('egon', 18) # print(obj1) # print(obj1.__str__()) # obj2=list([1,2,3]) # print(obj2)
2.__del__:在对象被删除时先自动触发该方法,可以用来回收对象以外其他相关资源,比如系统资源
# class Foo: # def __init__(self,x,filepath,encoding='utf-8'): # self.x=x # self.f=open(filepath,'rt',encoding=encoding) # # def __del__(self): # print('run.....') # # 回收对象关联的其他资源 # self.f.close() # # obj=Foo(1,'a.txt') # # del obj # print('主===========>')
3.__call__:在对象被调用时自动触发该方法
class Foo: def __init__(self,x,y): self.x=x self.y=y def __call__(self,*args,**kwargs) print(self,args,kwargs) obj=Foo(1,2) obj(1,2,a=3,b=4) # obj.__call__(obj,1,2,a=3,b=4)
五:Proper:
一个静态属性proper的本质就是实现了get,set,delete
class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 获取商品价格 obj.price = 200 # 修改商品原价 print(obj.price) del obj.price
# property装饰器是用来将类内的函数属性伪装成数据属性 # class People: # def __init__(self,name,weight,height): # self.name=name # self.weight=weight # self.height=height # # @property # def bmi(self): # return self.weight / (self.height ** 2) # # obj=People('egon',80,1.83) # obj.height=1.85 # obj.weight=75 # print(obj.bmi()) # print(obj.bmi) # 了解.... # class People: # def __init__(self,name): # self.__name=name # # @property # def name(self): # return '<名字:%s>' %self.__name # # @name.setter # def name(self,obj): # if type(obj) is not str: # print('name必须为str类型') # return # self.__name=obj # # @name.deleter # def name(self): # # print('不让删') # del self.__name # # obj=People('egon') # # # print(obj.name) # # obj.name='EGON' # # obj.name=123 # # print(obj.name) # # del obj.name # print(obj.__dict__) class People: def __init__(self,name): self.__name=name def get_name(self): return '<名字:%s>' %self.__name def set_name(self,obj): if type(obj) is not str: print('name必须为str类型') return self.__name=obj def del_name(self): # print('不让删') del self.__name name=property(get_name,set_name,del_name) obj=People('egon') # print(obj.name) # obj.name='EGON' # obj.name=123 # print(obj.name) del obj.name print(obj.__dict__)
六:__next__和__iter__实现迭代器协议
class Foo: def __init__(self,start,stop): self.num=start self.stop=stop def __iter__(self): return self def __next__(self): if self.num >= self.stop: raise StopIteration n=self.num self.num+=1 return n f=Foo(1,5) from collections import Iterable,Iterator print(isinstance(f,Iterator)) for i in Foo(1,5): print(i)
七:元类
1.什么是元类 : Python 中一切皆对象,
所有的对象都是类的实例化或者说调用类得到的(调用类的过程称为类的实例化)
2 class关键字创建类的流程分析
3exec用法:三个参数
参数一: 包含一系列的pytohn 代码的字符串
参数二:全局作用域字典形式(字典形式) 如果不指定,默认为globals()
参数三: 局部作用域(字典形式),如果不指定,默认为locals()
可以把exec命令的执行当做是一个函数的执行,会将执行期间产生的名字存放到局部名称空间中
g={ 'x':1, 'y':2 } l={} exec(''' global x,z x=100 z=200 m=300 ''',g,l) print(g) #{'x': 100, 'y': 2,'z':200,......} print(l) #{'m': 300}
4 自定义元类来空盒子类的产生:
# 模板 # class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类 # def __init__(self,class_name,class_bases,class_dic): # print(self) # print(class_name) # print(class_bases) # print(class_dic) # # class OldboyTeacher(object,metaclass=Mymeta): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...}) # school = 'Oldboy' # # def __init__(self,name,age,sex): # self.name=name # self.age=age # self.sex=sex # # def score(self): # print('%s is scoring' %self.name) # 控类的产生 # 1.类名必须用驼峰体 # 2.类体必须有文档注释,且文档注释不能为空 class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类 def __init__(self,class_name,class_bases,class_dic): if class_name.islower(): raise TypeError('类名必须使用驼峰体') doc=class_dic.get('__doc__') if doc is None or len(doc) == 0 or len(doc.strip('\n ')) == 0: raise TypeError('类体中必须有文档注释,且文档注释不能为空') class OldboyTeacher(object,metaclass=Mymeta): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...}) school = 'Oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def score(self): print('%s is scoring' %self.name) print(OldboyTeacher.__dict__)
5自定义元类来控制类调用的过程
''' class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类 pass class OldboyTeacher(object): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...}) school = 'Oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def score(self): print('%s is scoring' %self.name) def __call__(self, *args, **kwargs): print(self) print(args) print(kwargs) tea1=OldboyTeacher('egon',18,'male') tea1(1,2,a=1,b=2) #__call__(tea1,(1,2).{'a':1,'b':2}) ''' #总结:对象之所以可以调用,是因为对象的类中有一个函数__call__ #推导:如果一切皆对象,那么OldboyTeacher也是一个对象,该对象之所可以调用,肯定是这个对象的类中也定义了一个函数__call__ ''' class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类 def __call__(self, *args, **kwargs): #self=OldboyTeacher这个类,args=('egon',18,'male'),kwargs={} # 1. 先产生一个空对象 tea_obj=self.__new__(self) #tea_obj是OldboyTeacher这个类的对象 # 2. 执行__init__方法,完成对象的初始属性操作 self.__init__(tea_obj,*args,**kwargs) # 3. 返回初始化好的那个对象 return tea_obj class OldboyTeacher(object,metaclass=Mymeta): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...}) school = 'Oldboy' # tea_obj,'egon',18,'male' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def score(self): print('%s is scoring' %self.name) tea1=OldboyTeacher('egon',18,'male') # 会触发OldboyTeacher的类(即元类)中的__call__函数 print(tea1) print(tea1.__dict__) ''' # 实例化OldboyTeacher,或者说调用OldboyTeacher会 # 1. 先产生一个空对象 # 2. 执行__init__方法,完成对象的初始属性操作 # 3. 返回初始化好的那个对象 # 推导:调用OldboyTeacher(...)就是在调用OldboyTeacher的类中的__call__,那么在该__call__中就需要做上述三件事 #自定义元类来控制类的调用(即类的实例化过程) class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类 def __call__(self, *args, **kwargs): #self=OldboyTeacher这个类,args=('egon',18,'male'),kwargs={} # 1. 先产生一个空对象 tea_obj=self.__new__(self) #tea_obj是OldboyTeacher这个类的对象 # 2. 执行__init__方法,完成对象的初始属性操作 self.__init__(tea_obj,*args,**kwargs) # print(tea_obj.__dict__) tea_obj.__dict__={('_%s__%s' %(self.__name__,k)):v for k,v in tea_obj.__dict__.items()} # 3. 返回初始化好的那个对象 return tea_obj class OldboyTeacher(object,metaclass=Mymeta): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...}) school = 'Oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def score(self): print('%s is scoring' %self.name) tea1=OldboyTeacher('egon',18,'male') # 会触发OldboyTeacher的类(即元类)中的__call__函数 # print(tea1) print(tea1.__dict__)
6 属性查找
class Mymeta(type): # 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类 # n=444 def __call__(self, *args, **kwargs): #self=OldboyTeacher这个类 # 1. 先产生一个空对象 tea_obj = self.__new__(self) # tea_obj是OldboyTeacher这个类的对象 # print(self.__new__ is object.__new__) # tea_obj=object.__new__(self) # 2. 执行__init__方法,完成对象的初始属性操作 self.__init__(tea_obj, *args, **kwargs) # 3. 返回初始化好的那个对象 return tea_obj class Bar: # n = 33 pass class Foo(Bar): # n = 222 pass class OldboyTeacher(Foo, metaclass=Mymeta): # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...}) # n = 111 school = 'Oldboy' def __init__(self, name, age, sex): self.name = name #None.name='egon' self.age = age self.sex = sex def score(self): print('%s is scoring' % self.name) def __new__(cls, *args, **kwargs): # print('=====>') return super().__new__(cls) tea1 = OldboyTeacher('egon', 18, 'male') # print(tea1) print(tea1.__dict__) # print(OldboyTeacher.n) # print(object.__new__)
八 单例模式
单例模式 :多次实例化的结果指向同一个实例
单例模式实现方式一:
import settings class MySQL: __instance=None def __init__(self,ip,port): self.ip=ip self.port=port @classmathod def from_conf(cls): if cls._insteance 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('1.1.1.3',3302) print(obj1) print(obj2) print(obj3) # print(obj4)
单例模式实现方式二:
import settings def singleton(cls): _instance=cls(settings.IP,settings.PORT) def wrapper(*args,**kwargs): if len(args) !=0 or len(kwargs) !=0: obj=cls(*args,**kwargs) return obj return _instance return wrapper @singleton #MySQL=singleton(MySQL) #MySQL=wrapper class MySQL: def __init__(self, ip, port): self.ip = ip self.port = port # obj=MySQL('1.1.1.1',3306) #obj=wrapper('1.1.1.1',3306) # print(obj.__dict__) obj1=MySQL() #wrapper() obj2=MySQL() #wrapper() obj3=MySQL() #wrapper() obj4=MySQL('1.1.1.3',3302) #wrapper('1.1.1.3',3302) print(obj1) print(obj2) print(obj3) print(obj4)
单例模式实现方式三
import settings class Mymeta(type): def __init__(self,class_name,class_bases,class_dic): #self=MySQL这个类 self.__instance=self(settings.IP,settings.PORT) def __call__(self, *args, **kwargs): # self=MySQL这个类 if len(args) != 0 or len(kwargs) != 0: obj=self.__new__(self) self.__init__(obj,*args, **kwargs) return obj else: return self.__instance class MySQL(metaclass=Mymeta): #MySQL=Mymeta(...) def __init__(self, ip, port): self.ip = ip self.port = port obj1=MySQL() obj2=MySQL() obj3=MySQL() obj4=MySQL('1.1.1.3',3302) print(obj1) print(obj2) print(obj3) print(obj4)
单例模式实现方式四:
- def f1(): from singleton import instance print(instance) def f2(): from singleton import instance,My SQL print(instance) obj=MySQL('1.1.1.3',3302) print(obj) f1() f2()