面向对象
面向过程编程
核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么然后干什么。。。
基于该思想编写程序好比在设计一条流水线,是一种机械式的思维方式
优点:复杂的问题流程化、进而简单化
缺点:扩展性差
面向对象编程
核心对象二字,对象是特征与技能的结合体
基于该思想编写程序就好比是在创造一个世界,你就是这个世界的上帝,是一种上帝式的思维方式
优点:可扩展性强
缺点:编程的复杂度要高于面向过程
类:
种类、分类、类别
对象是特征与技能的结合体,类是一系列对象相似的特征与技能的结合体
强调:站的角度不同,总结出的类是截然不同的
在现实世界中:先有的一个个具体存在的对象,然后随着人类文明的发展才了分类的概念
在程序中:必须先定义类,后调用类来产生对象
#1、先定义类 class OldboyStudent: school='oldboy' def choose_course(self): print('is choosing course') #强调:类定义阶段会立刻执行类体代码,会产生类的名称空间,将类体代码执行过程中产生的名字都丢进去 # print(OldboyStudent.__dict__) # 类本质就是一个名称空间/容器,从类的名称空间中增/删/改/查名字 # python为我们提供专门访问属性(名称空间中的名字)的语法,点后的都是属性 # OldboyStudent.school #OldboyStudent.__dict__['school'] # OldboyStudent.x=1 #OldboyStudent.__dict__['x']=1 # OldboyStudent.school='Oldboy' #OldboyStudent.__dict__['school']='Oldboy' # del OldboyStudent.x #del OldboyStudent.__dict__['x'] # 类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个 # OldboyStudent.choose_course(123) #2、后调用类产生对象,调用类的过程称之为实例化,实例化的结果称为类的一个实例或者对象 stu1=OldboyStudent() stu2=OldboyStudent() stu3=OldboyStudent() # print(stu1) # print(stu2) # print(stu3) # print(OldboyStudent.school) # OldboyStudent.school='OLDBOY' # print(stu1.school) # print(stu2.school) # print(stu3.school)
对象初始化自己属性
''' # 例1 class OldboyStudent: school='oldboy' def choose_course(self): print('is choosing course') stu1=OldboyStudent() stu2=OldboyStudent() stu3=OldboyStudent() #对象本质也就是一个名称空间而已,对象名称空间是用存放对象自己独有的名字/属性,而 #类中存放的是对象们共有的属性 # print(stu1.__dict__) # print(stu2.__dict__) # print(stu3.__dict__) stu1.name='耗哥' stu1.age=18 stu1.sex='male' # print(stu1.name,stu1.age,stu1.sex) # print(stu1.__dict__) stu2.name='猪哥' stu2.age=17 stu2.sex='male' stu3.name='帅翔' stu3.age=19 stu3.sex='female' # 例2 class OldboyStudent: school='oldboy' def choose_course(self): print('is choosing course') stu1=OldboyStudent() stu2=OldboyStudent() stu3=OldboyStudent() def init(obj,x,y,z): obj.name=x obj.age=y obj.sex=z # stu1.name='耗哥' # stu1.age=18 # stu1.sex='male' init(stu1,'耗哥',18,'male') # stu2.name='猪哥' # stu2.age=17 # stu2.sex='male' init(stu2,'诸哥',17,'male') # stu3.name='帅翔' # stu3.age=19 # stu3.sex='female' init(stu3,'帅翔',19,'female') print(stu1.__dict__) print(stu2.__dict__) print(stu3.__dict__) ''' class OldboyStudent: school='oldboy' def __init__(obj, x, y, z): #会在调用类时自动触发 obj.name = x #stu1.name='耗哥' obj.age = y #stu1.age=18 obj.sex = z #stu1.sex='male' def choose_course(self): print('is choosing course') #调用类时发生两件事 #1、创造一个空对象stu1 #2、自动触发类中__init__功能的执行,将stu1以及调用类括号内的参数一同传入 stu1=OldboyStudent('耗哥',18,'male') #OldboyStudent.__init__(stu1,'耗哥',18,'male') stu2=OldboyStudent('猪哥',17,'male') stu3=OldboyStudent('帅翔',19,'female') print(stu1.__dict__) print(stu2.__dict__) print(stu3.__dict__)
属性查找
class OldboyStudent: school='oldboy' count=0 def __init__(self, x, y, z): #会在调用类时自动触发 self.name = x #stu1.name='耗哥' self.age = y #stu1.age=18 self.sex = z #stu1.sex='male' OldboyStudent.count+=1 def choose_course(self): print('is choosing course') # 先从对象自己的名称空间找,没有则去类中找,如果类也没有则报错 stu1=OldboyStudent('耗哥',18,'male') stu2=OldboyStudent('猪哥',17,'male') stu3=OldboyStudent('帅翔',19,'female') print(OldboyStudent.count) print(stu1.count) print(stu2.count) print(stu3.count)
绑定方法
class OldboyStudent: school='oldboy' def __init__(self, x, y, z): #会在调用类时自动触发 self.name = x #stu1.name='耗哥' self.age = y #stu1.age=18 self.sex = z #stu1.sex='male' def choose_course(self,x): print('%s is choosing course' %self.name) def func(): pass # 类名称空间中定义的数据属性和函数属性都是共享给所有对象用的 # 对象名称空间中定义的只有数据属性,而且时对象所独有的数据属性 stu1=OldboyStudent('耗哥',18,'male') stu2=OldboyStudent('猪哥',17,'male') stu3=OldboyStudent('帅翔',19,'female') # print(stu1.name) # print(stu1.school) # 类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个 # print(OldboyStudent.choose_course) # OldboyStudent.choose_course(123) # 类中定义的函数是共享给所有对象的,对象也可以使用,而且是绑定给对象用的, #绑定的效果:绑定给谁,就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入 # print(id(stu1.choose_course)) # print(id(stu2.choose_course)) # print(id(stu3.choose_course)) # print(id(OldboyStudent.choose_course)) # print(id(stu1.school)) # print(id(stu2.school)) # print(id(stu3.school)) # # print(id(stu1.name),id(stu2.name),id(stu3.name)) # stu1.choose_course(1) # stu2.choose_course(2) # stu3.choose_course(3) stu1.func() # 补充:类中定义的函数,类确实可以使用,但其实类定义的函数大多情况下都是绑定给对象用的,所以在类中定义的函数都应该自带一个参数self
类与类型
#在python3中统一了类与类型的概念,类就是类型 class OldboyStudent: school='oldboy' def __init__(self, x, y, z): #会在调用类时自动触发 self.name = x #stu1.name='耗哥' self.age = y #stu1.age=18 self.sex = z #stu1.sex='male' def choose_course(self,x): print('%s is choosing course' %self.name) stu1=OldboyStudent('耗哥',18,'male') # stu1.choose_course(1) #OldboyStudent.choose_course(stu1,1) # OldboyStudent.choose_course(stu1,1) l=[1,2,3] #l=list([1,2,3]) # print(type(l)) # l.append(4) #list.append(l,4) list.append(l,4) print(l)
继承与派生
''' 1、什么是继承 继承是一种新建类的方式,新建的类称为子类,被继承的类称为父类 继承的特性是:子类会遗传父类的属性 强调:继承是类与类之间的关系 2、为什么用继承 继承的好处就是可以减少代码的冗余 3、如何用继承 在python中支持一个类同时继承多个父类 在python3中 如果一个类没有继承任何类,那默认继承object类 在python2中: 如果一个类没有继承任何类,不会继承object类 新式类 但凡继承了object的类以及该类的子类,都是新式类 经典类 没有继承object的类以及该类的子类,都是经典类 在python3中都是新式类,只有在python2中才区别新式类与经典类 新式类vs经典类? ''' class Parent1(object): pass class Parent2(object): pass class Sub1(Parent1,Parent2): pass # print(Sub1.__bases__) print(Parent1.__bases__) print(Parent2.__bases__)
继承的应用
#派生:子类中新定义的属性,子类在使用时始终以自己的为准 class OldboyPeople: school = 'oldboy' def __init__(self,name,age,sex): self.name = name #tea1.name='egon' self.age = age #tea1.age=18 self.sex = sex #tea1.sex='male' class OldboyStudent(OldboyPeople): def choose_course(self): print('%s is choosing course' %self.name) class OldboyTeacher(OldboyPeople): # tea1,'egon',18,'male',10 def __init__(self,name,age,sex,level): # self.name=name # self.age=age # self.sex=sex OldboyPeople.__init__(self,name,age,sex) self.level=level def score(self,stu_obj,num): print('%s is scoring' %self.name) stu_obj.score=num stu1=OldboyStudent('耗哥',18,'male') tea1=OldboyTeacher('egon',18,'male',10) #对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。 # print(stu1.school) # print(tea1.school) # print(stu1.__dict__) # print(tea1.__dict__) tea1.score(stu1,99) print(stu1.__dict__) # 在子类派生出的新功能中重用父类功能的方式有两种: #1、指名道姓访问某一个类的函数:该方式与继承无关 # 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() # ''' # Foo.f2 # Bar.f1 # '''
组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
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,stu_id): OldboyPeople.__init__(self,name,age,sex) self.stu_id=stu_id def choose_course(self): print('%s is choosing course' %self.name) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level): OldboyPeople.__init__(self,name,age,sex) self.level=level def score(self,stu,num): stu.score=num print('老师[%s]为学生[%s]打分[%s]' %(self.name,stu.name,num)) stu1=OldboyStudent('猪哥',19,'male',1) tea1=OldboyTeacher('egon',18,'male',10) stu1.choose_course() tea1.score(stu1,100) print(stu1.__dict__) ''' class Course: def __init__(self,name,period,price): self.name=name self.period=period self.price=price def tell_info(self): msg=""" 课程名:%s 课程周期:%s 课程价钱:%s """ %(self.name,self.period,self.price) print(msg) 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,stu_id): OldboyPeople.__init__(self,name,age,sex) self.stu_id=stu_id def choose_course(self): print('%s is choosing course' %self.name) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level): OldboyPeople.__init__(self,name,age,sex) self.level=level def score(self,stu,num): stu.score=num print('老师[%s]为学生[%s]打分[%s]' %(self.name,stu.name,num)) # 创造课程 python=Course('python全栈开发','5mons',3000) linux=Course('linux运维','5mons',800) # python.tell_info() # linux.tell_info() # 创造学生与老师 stu1=OldboyStudent('猪哥',19,'male',1) tea1=OldboyTeacher('egon',18,'male',10) # 将学生、老师与课程对象关联/组合 stu1.course=python tea1.course=linux stu1.course.tell_info() tea1.course.tell_info()
菱形继承问题
1、菱形继承
当一个子继承多个父类时,多个父类最终继承了同一个类,称之为菱形继承
2、菱形继承的问题:
python2区分经典类与新式类,如果子的继承是一个菱形继承,那么经典类与形式的区别为?
经典类下查找属性:深度优先查找
新式类下查找属性:广度优先查找
class G(object): # def test(self): # print('from G') pass class E(G): # def test(self): # print('from E') pass class B(E): # def test(self): # print('from B') pass class F(G): # def test(self): # print('from F') pass class C(F): # def test(self): # print('from C') pass class D(G): # def test(self): # print('from D') pass class A(B,C,D): def test(self): print('from A') # pass obj=A() print(A.mro()) # obj.test() #A->B->E-C-F-D->G-object
子类调用父类的方法
# 在子派生的新方法中重用父类功能的两种方式 # 方式一:与继承无关 #指名道姓法,直接用:类名.函数名 # 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,stu_id): # OldboyPeople.__init__(self,name,age,sex) # self.stu_id=stu_id # # def choose_course(self): # print('%s is choosing course' %self.name) # 方式二:严格以来继承属性查找关系 # super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系) # super().__init__(不用为self传值) # 注意: # super的完整用法是super(自己的类名,self),在python2中需要写完整,而python3中可以简写为super() # 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,stu_id): # # OldboyPeople.__init__(self,name,age,sex) # super(OldboyStudent,self).__init__(name,age,sex) # self.stu_id=stu_id # # def choose_course(self): # print('%s is choosing course' %self.name) # # # stu1=OldboyStudent('猪哥',19,'male',1) # print(stu1.__dict__) # # print(OldboyStudent.mro()) class A: def f1(self): print('A.f1') class B: def f2(self): super().f1() print('B.f2') class C(B,A): pass obj=C() print(C.mro()) #C-》B->A->object obj.f2()
当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)
多态和多态性
''' 1 什么是多态 多态指的是同一种事物的多种形态 水-》冰、水蒸气、液态水 动物-》人、狗、猪 2 为和要用多态 多态性: 继承同一个类的多个子类中有相同的方法名 那么子类产生的对象就可以不用考虑具体的类型而直接调用功能 3 如何用 ''' import abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def speak(self): pass @abc.abstractmethod def eat(self): pass # Animal() #强调:父类是用来指定标准的,不能被实例化 class People(Animal): def speak(self): print('say hello') def eat(self): pass class Dog(Animal): def speak(self): print('汪汪汪') def eat(self): pass class Pig(Animal): def speak(self): print('哼哼哼') def eat(self): pass peo1=People() dog1=Dog() pig1=Pig() # # # peo1.speak() # dog1.speak() # pig1.speak() # def my_speak(animal): # animal.speak() # # my_speak(peo1) # my_speak(dog1) # my_speak(pig1) # # l=[1,2,3] # s='helllo' # t=(1,2,3) # # print(l.__len__()) # print(s.__len__()) # print(t.__len__()) # # # def len(obj): # # return obj.__len__() # # print(len(l)) # l.__len__() # print(len(s)) #s.__len__() # print(len(t)) # python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子 class Disk: def read(self): print('disk read') def write(self): print('disk wirte') class Process: def read(self): print('process read') def write(self): print('process wirte') class File: def read(self): print('file read') def write(self): print('file wirte') obj1=Disk() obj2=Process() obj3=File() obj1.read() obj1.write()
封装
''' 1、什么封装 封:属性对外是隐藏的,但对内是开放的 装:申请一个名称空间,往里装入一系列名字/属性 2、为什么要封装 封装数据属性的目的 首先定义属性的目的就是为了给类外部的使用使用的, 隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口 然后让类外部的使用通过接口来间接地操作隐藏的属性。 精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作 封装函数属性 首先定义属性的目的就是为了给类外部的使用使用的, 隐藏函数属性是为了不让外不直接使用,需要类内部开辟一个接口 然后在接口内去调用隐藏的功能 精髓在于:隔离了复杂度 3、如何封装 ''' # 如何隐藏:在属性前加上__开头 #1、 这种隐藏仅仅只是一种语法上的变形操作 #2、 这种语法上的变形只在类定义阶段发生一次,因为类体代码仅仅只在类定义阶段检测一次 #3、 这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外则无法直接访问,原因是 # 在类定义阶段,类体内代码统一发生了一次变形 #4、 如果不想让子类的方法覆盖父类的,可以将该方法名前加一个__开头 # class People: # __country='China' #_People__country='China' # __n=100 #_People__n=100 # def __init__(self,name,age,sex): # self.__name=name #self._People__name=name # self.age=age # self.sex=sex # # def eat(self): # print('eat.....') # print(People.__country) #People._People__country # print(self.__name) #self._People__name # People.eat(123) # print(People.__country) # peo1=People('egon',18,'male') # peo1.eat() # print(peo1.__name) # print(People.__dict__) # print(People.__country) # print(People._People__country) # People.__x=11 # print(People.__dict__) # peo1=People('egon',18,'male') # print(peo1.__dict__) # peo1.__x=111 # print(peo1.__dict__) # class Foo: # def __f1(self): #_Foo__f1 # print('Foo.f1') # # def f2(self): # print('Foo.f2') # self.__f1() #self._Foo__f1 # # class Bar(Foo): # def __f1(self): #_Bar__f1 # print('Bar.f1') # # obj=Bar() # obj.f2() class People: def __init__(self,name,age): self.__name=name self.__age=age def tell_info(self): print('%s:%s' %(self.__name,self.__age)) def set_info(self,name,age): if type(name) is not str: # print('用户名必须为str类型') # return raise TypeError('用户名必须为str类型') if type(age) is not int: # print('年龄必须为int类型') # return raise TypeError('年龄必须为int类型') self.__name=name self.__age=age peo1=People('egon',18) # peo1.name=123 # peo1.age # peo1.tell_info() peo1.set_info('egon',19) # peo1.tell_info()
property
#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) # # peo1=People('egon',75,1.8) # # peo1.height=1.85 # print(peo1.bmi) ''' class People: def __init__(self,name): self.__name=name @property # 查看obj.name def name(self): return '<名字是:%s>' %self.__name @name.setter #修改obj.name=值 def name(self,name): if type(name) is not str: raise TypeError('名字必须是str类型傻叉') self.__name=name @name.deleter #删除del obj.name def name(self): # raise PermissionError('不让删') print('不让删除傻叉') # del self.__name peo1=People('egon') # print(peo1.name) # print(peo1.name) # peo1.name='EGON' # print(peo1.name) del peo1.name ''' class People: def __init__(self,name): self.__name=name def tell_name(self): return '<名字是:%s>' %self.__name def set_name(self,name): if type(name) is not str: raise TypeError('名字必须是str类型傻叉') self.__name=name def del_name(self): print('不让删除傻叉') name=property(tell_name,set_name,del_name) peo1=People('egon') print(peo1.name) peo1.name='EGON' print(peo1.name) del peo1.name
绑定方法与非绑定方法
''' 1、绑定方法 特性:绑定给谁就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入 《《《精髓在于自动传值》》》 绑定方法分为两类: 1.1 绑定给对象方法 在类内部定义的函数(没有被任何装饰器修饰的),默认就是绑定给对象用的 1.2 绑定给类的方法: 在类内部定义的函数如果被装饰器@classmethod装饰, 那么则是绑定给类的,应该由类来调用,类来调用就自动将类当作第一个参数自动传入 2、非绑定方法 类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就变成非绑定方法 既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用 但是无论谁来调用,都没有任何自动传值的效果,就是一个普通函数 3 应用 如果函数体代码需要用外部传入的类,则应该将该函数定义成绑定给类的方法 如果函数体代码需要用外部传入的对象,则应该将该函数定义成绑定给对象的方法 如果函数体代码既不需要外部传入的类也不需要外部传入的对象,则应该将该函数定义成非绑定方法/普通函数 ''' # class Foo: # @classmethod # def f1(cls): # print(cls) # # def f2(self): # print(self) # # # obj=Foo() # print(obj.f2) # print(Foo.f1) # Foo.f1() # print(Foo) #1、f1绑定给类的 # 了解:绑定给类的应该由类来调用,但对象其实也可以使用,只不过自动传入的仍然是类 # print(Foo.f1) # print(obj.f1) # Foo.f1() # obj.f1() #2、f2是绑定给对象的 # obj.f2() # Foo.f2(obj) import settings import uuid class Mysql: def __init__(self,ip,port): self.uid=self.create_uid() self.ip=ip self.port=port def tell_info(self): print('%s:%s' %(self.ip,self.port)) @classmethod def from_conf(cls): return cls(settings.IP, settings.PORT) @staticmethod def func(x,y): print('不与任何人绑定') @staticmethod def create_uid(): return uuid.uuid1() # 默认的实例化方式:类名(..) obj=Mysql('10.10.0.9',3307) # 一种新的实例化方式:从配置文件中读取配置完成实例化 # obj1=Mysql.from_conf() # obj1.tell_info() # obj.func(1,2) # Mysql.func(3,4) # print(obj.func) # print(Mysql.func) print(obj.uid)
补充内置函数
class Foo: pass obj=Foo() print(isinstance(obj,Foo)) # 在python3中统一类与类型的概念 # d={'x':1} #d=dict({'x':1} #) # print(type(d) is dict) # print(isinstance(d,dict)) # issubclass() class Parent: pass class Sub(Parent): pass print(issubclass(Sub,Parent)) print(issubclass(Parent,object))
反射
''' 1、什么是反射 通过字符串来操作类或者对象的属性 2、如何用 hasattr getattr setattr delattr ''' class People: country='China' def __init__(self,name): self.name=name def eat(self): print('%s is eating' %self.name) peo1=People('egon') # print(hasattr(peo1,'eat')) #peo1.eat # print(getattr(peo1,'eat')) #peo1.eat # print(getattr(peo1,'xxxxx',None)) # setattr(peo1,'age',18) #peo1.age=18 # print(peo1.age) # print(peo1.__dict__) # delattr(peo1,'name') #del peo1.name # print(peo1.__dict__) class Ftp: def __init__(self,ip,port): self.ip=ip self.port=port def get(self): print('GET function') def put(self): print('PUT function') def run(self): while True: choice=input('>>>: ').strip() # print(choice,type(choice)) # if hasattr(self,choice): # method=getattr(self,choice) # method() # else: # print('输入的命令不存在') method=getattr(self,choice,None) if method is None: print('输入的命令不存在') else: method() conn=Ftp('1.1.1.1',23) conn.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
__str__,__repr__,__format__
改变对象的字符串显示__str__,__repr__
自定制格式化字符串__format__
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' format_dict={ 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __repr__(self): return 'School(%s,%s)' %(self.name,self.addr) def __str__(self): return '(%s,%s)' %(self.name,self.addr) def __format__(self, format_spec): # if format_spec if not format_spec or format_spec not in format_dict: format_spec='nat' fmt=format_dict[format_spec] return fmt.format(obj=self) s1=School('oldboy1','北京','私立') print('from repr: ',repr(s1)) #from repr: School(oldboy1,北京) print('from str: ',str(s1)) #from str: (oldboy1,北京) print(s1) #(oldboy1,北京)
''' str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 注意:这俩方法的返回值必须是字符串,否则抛出异常 ''' print(format(s1,'nat')) print(format(s1,'tna')) print(format(s1,'tan')) print(format(s1,'asfdasdffd'))
自定义format练习
date_dic={ 'ymd':'{0.year}:{0.month}:{0.day}', 'dmy':'{0.day}/{0.month}/{0.year}', 'mdy':'{0.month}-{0.day}-{0.year}', } class Date: def __init__(self,year,month,day): self.year=year self.month=month self.day=day def __format__(self, format_spec): if not format_spec or format_spec not in date_dic: format_spec='ymd' fmt=date_dic[format_spec] return fmt.format(self) d1=Date(2016,12,29) print(format(d1)) print('{:mdy}'.format(d1))
自定义内置方法定制类
#1、__str__方法 # class People: # def __init__(self,name,age): # self.name=name # self.age=age # # #在对象被打印时,自动触发,应该在该方法内采集与对象self有关的信息,然后拼成字符串返回 # def __str__(self): # # print('======>') # return '<name:%s age:%s>' %(self.name,self.age) # obj=People('egon',18) # obj1=People('alex',18) # print(obj) #obj.__str__() # print(obj) #obj.__str__() # print(obj) #obj.__str__() # print(obj1) #obj1.__str__() # d={'x':1} #d=dict({'x':1}) # print(d) #1、__del__析构方法 # __del__会在对象被删除之前自动触发 class People: def __init__(self,name,age): self.name=name self.age=age self.f=open('a.txt','rt',encoding='utf-8') def __del__(self): # print('run=-====>') # 做回收系统资源相关的事情 self.f.close() obj=People('egon',18) print('主')
元类
''' 1、什么是元类 在python中一切皆对象,那么我们用class关键字定义的类本身也是一个对象 负责产生该对象的类称之为元类,即元类可以简称为类的类 class Foo: # Foo=元类() pass 2、为何要用元类 元类是负责产生类的,所以我们学习元类或者自定义元类的目的 是为了控制类的产生过程,还可以控制对象的产生过程 3、如何用元类 ''' #1、储备知识:内置函数exec的用法 # cmd=""" # x=1 # def func(self): # pass # """ # class_dic={} # exec(cmd,{},class_dic) # # print(class_dic) #2、创建类的方法有两种 # 大前提:如果说类也是对象的化,那么用class关键字的去创建类的过程也是一个实例化的过程 # 该实例化的目的是为了得到一个类,调用的是元类 #2.1 方式一:用的默认的元类type # class People: #People=type(...) # country='China' # def __init__(self,name,age): # self.name=name # self.age=age # # def eat(self): # print('%s is eating' %self.name) # print(type(People)) #2.1.1 创建类的3个要素:类名,基类,类的名称空间 class_name='People' class_bases=(object,) class_dic={} class_body=""" country='China' def __init__(self,name,age): self.name=name self.age=age def eat(self): print('%s is eating' %self.name) """ exec(class_body,{},class_dic) # 准备好创建类的三要素 # print(class_name) # print(class_bases) # print(class_dic) # People=type(类名,基类,类的名称空间) # People1=type(class_name,class_bases,class_dic) # print(People1) # obj1=People1('egon',18) # print(People) # obj=People('egon',18) # # obj1.eat() # obj.eat() ''' #2.2 方式二:用的自定义的元类 class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类 def __init__(self,class_name,class_bases,class_dic): print(self) #现在是People print(class_name) print(class_bases) print(class_dic) super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能 # 分析用class自定义类的运行原理(而非元类的的运行原理): #1、拿到一个字符串格式的类名class_name='People' #2、拿到一个类的基类们class_bases=(obejct,) #3、执行类体代码,拿到一个类的名称空间class_dic={...} #4、调用People=type(class_name,class_bases,class_dic) class People(object,metaclass=Mymeta): #People=Mymeta(类名,基类们,类的名称空间) country='China' def __init__(self,name,age): self.name=name self.age=age def eat(self): print('%s is eating' %self.name) # 应用:自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程 class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类 def __init__(self,class_name,class_bases,class_dic): 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) #重用父类的功能 class People(object,metaclass=Mymeta): #People=Mymeta('People',(object,),{....}) """这是People类""" country='China' def __init__(self,name,age): self.name=name self.age=age def eat(self): print('%s is eating' %self.name) ''' #3 储备知识:__call__ # class Foo: # def __call__(self, *args, **kwargs): # print(self) # print(args) # print(kwargs) # # # obj=Foo() # # # 要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法 # # 该方法会在调用对象时自动触发 # obj(1,2,3,x=1,y=2) # 4、自定义元类来控制类的调用的过程,即类的实例化过程 class Mymeta(type): def __call__(self, *args, **kwargs): # print(self) # self是People # print(args) # print(kwargs) # return 123 # 1、先造出一个People的空对象 obj=self.__new__(self) # 2、为该对空对象初始化独有的属性 # print(args,kwargs) self.__init__(obj,*args,**kwargs) # 3、返回一个初始好的对象 return obj class People(object,metaclass=Mymeta): country='China' def __init__(self,name,age): self.name=name self.age=age def eat(self): print('%s is eating' %self.name) def __new__(cls, *args, **kwargs): print(cls) # cls.__new__(cls) # 错误 obj=super(People,cls).__new__(cls) return obj # 分析:调用Pepole的目的 #1、先造出一个People的空对象 #2、为该对空对象初始化独有的属性 # obj1=People('egon1',age=18) # obj2=People('egon2',age=18) # print(obj1) # print(obj2) obj=People('egon',age=18) print(obj.__dict__) print(obj.name) obj.eat()