面向对象+继承
内容概要
- 面向对象介绍
- 实现面向对象编程
- 属性查找
- 封装
- 选课
- property装饰器
- 继承
- 多继承带来的菱形问题
- 单继承背景下的属性查找
- classmethod
- mixins机制
- 在子类派生的新方法中如何重用父类的功能
- 多态
内容详细
-
面向对象介绍
''' 面向过程 核心是'过程'二字 过程的终极奥义就是将程序流程化 过程是'流水线',用来分步骤解决的 面向对象 核心是'对象'二字 对象的终极奥义就是将程序'整合' 对象是'容器',用来盛放数据和功能的 类也是'容器',该容器用来存放同类对象共有的数据和功能 ''' # 程序 = 数据+功能
-
实现面向对象编程
# 先定义类 # 类是对象相似数据与功能的集合体 # 所以类体中最常见的是变量与函数的定义,但是类体其实是可以包含任意其他代码的 # 注意:类体代码是在类定义阶段就会立即执行的,会产生类的名称空间 # 再调用类产出对象 # # 一、先定义类 # class Student: # # 1.变量的定义: # stu_school = 'oldboy' # # # 2.功能的定义 # def tell_stu_info(stu_obj): # print('学生信息:名字:%s 年龄:%s 性别:%s '%( # stu_obj['stu_name'], # stu_obj['stu_age'], # stu_obj['stu_gender'] # )) # # def set_info(stu_obj,x,y,z): # stu_obj['stu_name'] = x # stu_obj['stu_age'] = y # stu_obj['stu_gender'] = z # print(Student.__dict__) # # 属性访问的语法 # # 1.访问数据属性 # print(Student.stu_school) # print(Student.__dict__['stu_school']) # # 2.访问函数属性 # print(Student.set_info) # print(Student.__dict__['set_info']) # 二、再调用类产生对象 # stu1_obj = Student() # stu2_obj = Student() # stu3_obj = Student() # 为对象定制自己独有的属性 # 问题1:代码重复 # 问题2:属性的查找顺序 # stu1_obj.stu_name = 'ycc' # stu1_obj.stu_age = 18 # stu1_obj.stu_gender = 'male' # print(stu1_obj.__dict__) # # stu2_obj.stu_name = 'xixi' # stu2_obj.stu_age = 19 # stu2_obj.stu_gender = 'female' # print(stu2_obj.__dict__) # # # stu3_obj.stu_name = 'jason' # stu3_obj.stu_age = 18 # stu3_obj.stu_gender = 'male' # print(stu3_obj.__dict__) # 解决问题一: # def init(obj,stu_name,stu_age,stu_gender): # obj.stu_name = stu_name # obj.stu_age = stu_age # obj.stu_gender = stu_gender # # init(stu1_obj,'ycc',18,'male') # init(stu2_obj,'xixi',19,'female') # init(stu3_obj,'jason',20,'male') # print(stu1_obj.__dict__) # print(stu2_obj.__dict__) # print(stu3_obj.__dict__) # 二、解决问题二: # 1、先定义类 class Student: # 1.变量的定义: stu_school = 'oldboy' # 空对象,'ycc', 18, 'male' def __init__(obj,stu_name,stu_age,stu_gender): obj.stu_name = stu_name # 空对象.stu_name = 'ycc' obj.stu_age = stu_age # 空对象.stu_age = 18 obj.stu_gender = stu_gender # 空对象.stu_gender = 'male' # 2.功能的定义 def tell_stu_info(stu_obj): print('学生信息:名字:%s 年龄:%s 性别:%s '%( stu_obj['stu_name'], stu_obj['stu_age'], stu_obj['stu_gender'] )) def set_info(stu_obj,stu_name,stu_age,stu_gender): stu_obj['stu_name'] = stu_name stu_obj['stu_age'] = stu_age stu_obj['stu_gender'] = stu_gender # 2、再调用类产生对象 # 调用类的过程又称之为实例化,发生了三件事 # 1、先产生一个空对象 # 2、python会自动调用类中的__init__方法将空对象已经调用类时括号内传入的参数一同传给__init__方法 # 3.返回初始完的对象 stu1_obj = Student('ycc',18,'male') # Student.__init(空对象,'ycc',18,'male') stu2_obj = Student('xixi',19,'female') stu3_obj = Student('jason',20,'male') print(stu1_obj.__dict__) print(stu2_obj.__dict__) print(stu3_obj.__dict__) # 总结__init__方法 # 1、会在调用类时自动触发执行,用来为对象初始化自己独有的数据 # 2、__init__内应该存放是为对象初始化属性的功能,但是是可以存放任意其他代码, # 想要在类调用时就立刻执行的代码都可以放到该方法内 # 3、__init__方法必须返回None
-
属性查找
class Student: # 1.变量的定义: stu_school = 'oldboy' # 空对象,'ycc', 18, 'male' def __init__(self,stu_name,stu_age,stu_gender): self.stu_name = stu_name # 空对象.stu_name = 'ycc' self.stu_age = stu_age # 空对象.stu_age = 18 self.stu_gender = stu_gender # 空对象.stu_gender = 'male' # 2.功能的定义 def tell_stu_info(self): print('学生信息:名字:%s 年龄:%s 性别:%s '%( # stu_obj['stu_name'], # stu_obj['stu_age'], # stu_obj['stu_gender'] self.stu_name, self.stu_age, self.stu_gender )) def set_info(self,stu_name,stu_age,stu_gender): # stu_obj['stu_name'] = stu_name # stu_obj['stu_age'] = stu_age # stu_obj['stu_gender'] = stu_gender self.stu_name = stu_name self.stu_age = stu_age self.stu_gender = stu_gender def choose(self,x): print('正在选课') self.course = x stu1_obj = Student('ycc',18,'male') stu2_obj = Student('xixi',19,'female') stu3_obj = Student('jason',20,'male') # 类中存放的是对象共有的数据和功能 # 一、类可以访问: # 1.类的数据属性 # print(Student.stu_school) # # 2.类的函数属性 # print(Student.set_info) # print(Student.tell_stu_info) # 二、但其实类中的东西是给对象用的 # 1、类的数据属性是共享给所有对象用的,大家访问的地址都一样 # print(stu1_obj.stu_name) # print(stu1_obj.stu_age) # print(stu1_obj.stu_gender) # print(stu1_obj.stu_school) # 查找顺序,先在对象内找,让后去类里找 # print(Student.stu_school) # oldboy # print(stu1_obj.stu_school) # oldboy # print(stu2_obj.stu_school) # oldboy # print(stu3_obj.stu_school) # oldboy # # print(id(Student.stu_school)) # 1464557583344 # print(id(stu1_obj.stu_school)) # 1464557583344 # print(id(stu2_obj.stu_school)) # 1464557583344 # print(id(stu3_obj.stu_school)) # 1464557583344 # Student.stu_school = 'OLDBOY' # print(Student.stu_school) # OLDBOY # print(stu1_obj.stu_school) # OLDBOY # print(stu2_obj.stu_school) # OLDBOY # print(stu3_obj.stu_school) # OLDBOY # stu1_obj.stu_school = 'OLDBOY' # print(Student.stu_school) # oldboy # print(stu1_obj.stu_school) # OLDBOY # print(stu2_obj.stu_school) # oldboy # print(stu3_obj.stu_school) # oldboy # 查找顺序先对象后类,这里直接在对象内新建了一个 # # 2.类的函数属性是绑定给对象用的 # print(Student.tell_stu_info) # print(Student.set_info) # # # Student.tell_stu_info(stu1_obj) # Student.tell_stu_info(stu2_obj) # Student.tell_stu_info(stu3_obj) # # 学生信息:名字:ycc 年龄:18 性别:male # # 学生信息:名字:xixi 年龄:19 性别:female # # 学生信息:名字:jason 年龄:20 性别:male # # Student.set_info(stu1_obj,'YCC',20,'male') # Student.tell_stu_info(stu1_obj) # # 学生信息:名字:YCC 年龄:20 性别:male # 绑定方法的特殊之处在于:谁来调用绑定方法就会将谁当作第一个参数自动传入 # stu1_obj.tell_stu_info() # stu2_obj.tell_stu_info() # stu3_obj.tell_stu_info() # 学生信息:名字:ycc 年龄:18 性别:male # 学生信息:名字:xixi 年龄:19 性别:female # 学生信息:名字:jason 年龄:20 性别:male # stu1_obj.choose('python') # print(stu1_obj.course) # stu2_obj.choose('linux') # print(stu2_obj.course) # stu3_obj.choose('高级架构师') # print(stu3_obj.course) # 例: l1 = ['aa','bb','cc'] l2 = [11,22,33] print(l1.append('dd')) # print(l1) # print(list.append(l1)) # list.append() takes exactly one argument (0 given) # list.append(l1,'dd') # ['aa', 'bb', 'cc', 'dd'] # list.append(l2,'dd') # [11, 22, 33, 'dd'] # print(l1) # print(l2)
-
封装
# 一、封装的概念 # 封装是面向对象三大特性的最核心的一个特性 # 封装<->整合 # 二、封装的属性进行隐藏 # 1)如何隐藏:在属性名前加__前缀,就会实现对外隐藏属性效果 # 该隐藏需要注意的问题: # 1、在类外部无法直接访问双下滑线开头的属性, # 但知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了, # 如Foo._A__N,所以说这种操作并没有严格意义上地限制外部访问,仅仅只是一种语法意义上的变形。 # class Foo: # __x = 2 # _Foo__x # # def __f1(self): # _Foo__f1 # print('from f1') # # # print(Foo.__dict__) # 可以打印出隐藏属性 # print(Foo._Foo__x) # 虽然能,但是不要在外部这样访问 # print(Foo._Foo__f1) # 2、这种隐藏对外不对内,因为__开头的属性会在检查类体代码语法的时候统一发生变形 # class Foo: # __x = 2 # _Foo__x = 1 # 在检查语法的时候,这里会直接发生变形,下面也是如此,统一发生形变 # # def __f1(self): # _Foo__f1 # print('from f1') # # def f2(self): # print(self.__x) # print(self._Foo__x) # print(self.__f1) # print(self._Foo__f1) # 因此这里能访问到上面 # # obj = Foo() # obj.f2() # 3.这种变形操作只在检查类体语法的时候发生一次,之后定义的__开头属性都不会变形 # class Foo: # __x = 2 # # def __f1(self): # print('from f1') # # def f2(self): # print(self.__x) # print(self.__f1) # # Foo.__y = 3 # 只在检测类体语法的时候发生一次 # print(Foo.__dict__) # 可以看到__y根本没变形 # print(Foo.__y) # 3 # 对象隐藏也一样 # 1. # class Foo: # def __init__(self,name,age): # self.name = name # self.age = age # # obj = Foo('ycc',18) # print(obj.name,obj.age) # ycc 18 # 2. # class Foo: # def __init__(self,name,age): # self.__name = name # self.__age = age # # obj = Foo('ycc',18) # print(obj.name,obj.age) # 报错 # 3. # class Foo: # def __init__(self,name,age): # self.__name = name # self.__age = age # # obj = Foo('ycc',18) # print(obj.__dict__) # {'_Foo__name': 'ycc', '_Foo__age': 18} # print(obj._Foo__name,obj._Foo__age) # ycc 18 # 2)为何隐藏 # 1.隐藏数据属性:将数据隐藏起来就限制了类外部对数据的直接操作, # 然后类内应该提供相应的接口来允许类外部间接地操作数据, # 接口之上可以附加额外的逻辑来对数据的操作进行严格地控制 # 设计者: class People: def __init__(self,name): self.__name = name def get_name(self): print(self.__name) def set_name(self,val): # 设计者可以再这附加任意逻辑 if type(val) is not str: print('小垃圾,必须传字符串类型') return self.__name= val obj = People('egon') # print(obj.name) # 无法直接使用 obj.set_name('EGON') obj.get_name() # egon # 2.隐藏函数/方法属性:目的是为了隔离复杂度 ''' >>> class ATM: ... def __card(self): #插卡 ... print('插卡') ... def __auth(self): #身份认证 ... print('用户认证') ... def __input(self): #输入金额 ... print('输入取款金额') ... def __print_bill(self): #打印小票 ... print('打印账单') ... def __take_money(self): #取钱 ... print('取款') ... def withdraw(self): #取款功能 ... self.__card() ... self.__auth() ... self.__input() ... self.__print_bill() ... self.__take_money() ... >>> obj=ATM() >>> obj.withdraw() '''
-
选课
# 整合-》解耦合-》扩展性增强 # 组合 在一个类中以另外一个类的对象作为数据属性,称为类的组合。组合与继承都是用来解决代码的重用性问题 class School: school_name = 'OLDBOY' def __init__(self, nickname, address): self.nickname = nickname self.address = address self.classes = [] def related_class(self, class_obj): self.classes.append(class_obj) def tell_class(self): print(self.nickname.center(60,'=')) for class_obj in self.classes: class_obj.tell_course() # 一、学校 # 1、创建校区 school_obj1 = School('老男孩魔都校区', '上海') school_obj2 = School('老男孩帝都校区', '北京') # 2、为学校开设班级 # school_obj1.related_class('脱产18期') # school_obj1.related_class('脱产19期') # for class_name in school_obj1.classes: # print('%s %s'%(school_obj1.nickname,class_name)) # school_obj2.related_class('脱产20期') # for class_name in school_obj2.classes: # print('%s %s'%(school_obj2.nickname,class_name)) # 查看每个校区开设的班级 # school_obj1.tell_class() # school_obj2.tell_class() class Class: def __init__(self, name): self.name = name self.course = None def class_related(self, course_obj): self.course = course_obj def tell_course(self): print('班级名:%s'%self.name,end=' ') self.course.tell_info() # 二、班级 # 1.创建班级 class_obj1 = Class('脱产18期') class_obj2 = Class('脱产19期') class_obj3 = Class('脱产20期') # 2.为班级关联一个课程 # class_obj1.class_related('python全栈开发') # class_obj1.class_related('linux运维') # class_obj2.class_related('高级架构师') # class_obj3.class_related('python全栈开发') # 3.查看班级开设的课程信息 # print('%s %s'%(class_obj1.name,class_obj1.courses)) # print('%s %s'%(class_obj2.name,class_obj2.courses)) # class_obj1.tell_course() # class_obj2.tell_course() # class_obj3.tell_course() # 4.为学校开设班级 # 上海校区开了:脱产14期 上海校区开了:脱产15期 school_obj1.related_class(class_obj1) school_obj1.related_class(class_obj1) # 北京校区开了: school_obj2.related_class(class_obj2) # school_obj1.tell_class() # school_obj2.tell_class() class Course: def __init__(self,name,period,price): self.name = name self.period = period self.price = price def course_related(self): pass def tell_info(self): print('课程名:%s 课程周期:%s 课程价格:%s '%(self.name,self.period,self.price)) course_obj1 = Course('python全栈开发','6months',20000) course_obj2 = Course('linux运维','5months',18000) course_obj3 = Course('高级架构师','7months',21000) # course_obj1.tell_info() # course_obj2.tell_info() # course_obj3.tell_info() class_obj1.class_related(course_obj1) class_obj1.class_related(course_obj2) class_obj2.class_related(course_obj3) class_obj3.class_related(course_obj1) # class_obj1.tell_course() # class_obj2.tell_course() # class_obj3.tell_course() school_obj1.tell_class() school_obj2.tell_class() class Student: pass
-
property装饰器
# 装饰器是在不修改被装饰对象的源代码以及调用方式的情况下,为被装饰对象添加新功能的可调用对象 # print(property) # <class 'property'> # property是一个装饰器,是用来绑定给对象的方法伪装成一个数据属性 # 案例一: # class People: # def __init__(self,name,height,weight): # self.name = name # self.height = height # self.weight = weight # # # 定义函数的原因1: # # 1.从bmi的公式来看,bmi应该是出发功能计算得到的 # # 2.bmi是随着升高、体重的变化而动态变化的,不是一个固定的值,说白了,每次都是要临时计算得到的 # # # 而bmi听起来更像一个数据属性,而非功能 # @property # def bmi(self): # return self.weight / (self.height ** 2) # # obj = People('ycc',1.83,90) # # print(obj.bmi()) # print(obj.bmi) # 加了装饰器之后,就不用再加()了 # # 案例二: # class People: # def __init__(self,name): # self.__name = name # # # def get_name(self): # return self.__name # # def set_name(self,val): # if type(val) is not str: # print('必须传入str类型') # return # self.__name = val # # def del_name(self): # print("不让删除") # # name = property(get_name,set_name,del_name) # obj = People('ycc') # print(obj.name) # ycc # obj.name = 'YCC' # print(obj.name) # YCC # del obj.name # 不让删除 # 案例三: class People: def __init__(self,name): self.__name = name # 查删改和上面效果一样 @property def name(self): return self.__name @name.setter # 固定用法 def name(self,val): if type(val) is not str: print('必须传入str类型') return self.__name = val @name.deleter def name(self): print("不让删除") # name = property(get_name,set_name,del_name) obj = People('ycc') print(obj.name) # ycc obj.name = 'YCC' print(obj.name) # YCC del obj.name # 不让删除
-
继承
# 1.什么是继承 # 1)继承是一种创建新类的方式,新建的类可称为子类或派生类,父类又可称为基类或超类,子类会遗传父类的属性 # 2)需要注意的是:python支持多继承 # 在python中,新建的类可以继承一个或多个父类,在其他语言中是没有多继承的 # class Parent1: # # class Parent1(object): 这样使其也变成新式类,在python2中也能使用 # # pass # # class Parent2: # # class Parent1(object): # pass # # class Sub1(Parent1): # pass # # class Sub2(Parent1,Parent2): # pass # print(Sub1.__bases__) # (<class '__main__.Parent1'>,) # print(Sub2.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>) # ps1:在python2中有经典类和新式类之分 # 新式类:继承了object类的子类,以及该子类的子类子子类 # 经典:没有继承object类的子类,以及该子类的子类子子类 # ps2:在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都是新式类 # print(Parent1.__bases__) # (<class 'object'>,) # print(Parent2.__bases__) # (<class 'object'>,) # 3)python的多继承 # 优点:子类可以同时遗传多个父类的属性,最大限度的重用代码 # 缺点: # 1.违背了人的思维习惯:继承表达的是一种什么'是'什么的关系 # 2.代码的可读性变差 # 3.不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差 # 如果真的涉及到一个子类不可避免的要重用多个父类的属性,应该使用Mixins # 2.为何要用继承:用来解决代码冗余问题 # 如何实现继承 # 示范一:类与类之间出现了代码冗余的问题 # class Student: # school = 'oldschool' # def __init__(self,name ,age,gender): # self.name = name # self.age = age # self.gender = gender # # def choose_course(self): # print('学生%s 正在选课 '% self.name) # # class Teacher: # school = 'oldboy' # def __init__(self,name,age,gender,salary,level): # self.name = name # self.age = age # self.gender = gender # self.salary = salary # self.level = level # # def score(self): # print('老师%s 正在打分'%self.name) # 示范二:基于继承解决类与类之间代码冗余的问题 class OldboyPeopel: school = 'oldschool' def __init__(self,name ,age,gender): self.name = name self.age = age self.gender = gender class Student(OldboyPeopel): # school = 'oldschool' # def __init__(self,name ,age,gender): # self.name = name # self.age = age # self.gender = gender def choose_course(self): print('学生%s 正在选课 '% self.name) stu_obj = Student('ycc',18,'male') print(stu_obj.__dict__) # {'name': 'ycc', 'age': 18, 'gender': 'male'} print(stu_obj.school) # oldschool stu_obj.choose_course() class Teacher(OldboyPeopel): # school = 'oldboy' def __init__(self,name,age,gender,salary,level): # self.name = name # self.age = age # self.gender = gender OldboyPeopel.__init__(self,name,age,gender) self.salary = salary self.level = level def score(self): print('老师%s 正在打分'%self.name) tea_obj = Teacher('egon',18,'male',3000,10) print(tea_obj.__dict__) print(tea_obj.name) tea_obj.score()
-
多继承带来的菱形问题
# 一、菱形问题介绍与MRO # class A: # def test(self): # print('from A') # class B(A): # def test(self): # print('from B') # class C(A): # def test(self): # print('from C') # class D(B,C): # pass # print(D.mro()) # 类D以及类D的对象访问属性都是参照该类的mro列表 # #[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, # # <class 'object'>] # # obj = D() # obj.test() # # from B # # 查找顺序:首先先在D类里找,D类没有去其父类里找,但是这里多继承,因此通过print(D.mro()),来查看顺序 # print(C.mro()) # 类D以及类D的对象访问属性都是参照该类的mro列表 # # [<class '__main__.C'>, <class '__main__.A'>, <class 'object'>] # obj = C() # obj.test() # from C # 总结:类相关的属性查找(类名.属性,该类的对象.属性),都是参照该类的mro # 二、如果多继承是非菱形继承,经典类与新式类的属性查找顺序一样: # 都是一个分支一个分支的找下去,然后最后找object # class E: # def test(self): # print('from E') # # class F: # def test(self): # print('from F') # # class B(E): # def test(self): # print('from B') # # class C(F): # def test(self): # print('from C') # # class D: # def test(self): # print('from D') # # class A(B, C, D): # # def test(self): # # print('from A') # pass # # print(A.mro()) # # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, # # <class '__main__.F'>, <class '__main__.D'>, <class 'object'>] # # obj = A() # obj.test() # 结果为:from B # 三、如果多继承是菱形继承,经典类与新式类的属性查找顺序不一样 # 新式类:广度优先,会在检索最后一条分支的时候检索大脑袋(共同的父类) class G(object): def test(self): print('from G') class E(G): def test(self): print('from E') class F(G): def test(self): print('from F') class B(E): def test(self): print('from B') class C(F): def test(self): print('from C') class D(G): def test(self): print('from D') class A(B,C,D): # def test(self): # print('from A') pass obj = A() obj.test() # 如上图,查找顺序为:obj->A->B->E->C->F->D->G->object # 可依次注释上述类中的方法test来进行验证 # 经典类:深度优先,会在检索第一条分支的时候就直接一条道走道黑,即会检索大脑袋(共同的父类) class G: # 在python2中,未继承object的类及其子类,都是经典类 def test(self): print('from G') class E(G): def test(self): print('from E') class F(G): def test(self): print('from F') class B(E): def test(self): print('from B') class C(F): def test(self): print('from C') class D(G): def test(self): print('from D') class A(B,C,D): # def test(self): # print('from A') pass obj = A() obj.test() # 如上图,查找顺序为:obj->A->B->E->G->C->F->D->object # 可依次注释上述类中的方法test来进行验证,注意请在python2.x中进行测试 # 总结: # 多继承到底要不要用 # 要用,但是规避几点问题: # 1、继承结构尽量不要过于复杂 # 2、推荐使用mixins机制:在多继承的背景下满足继承的什么'是'什么的关系
-
单继承背景下的属性查找
# 单继承背景下的属性查找# 示范一、# class Foo:# def f1(self):# print('Foo.f1')## def f2(self):# print('FOO.f2')# self.f1() # obj.f1()## class Bar(Foo):# def f1(self):# print('Bar.f1')## obj = Bar()# obj.f2()# FOO.f2# Bar.f1# # 示范二、# class Foo:# def f1(self):# print('Foo.f1')## def f2(self):# print('FOO.f2')# Foo.f1(self) # 调用当前类中的f1### class Bar(Foo):# def f1(self):# print('Bar.f1')## obj = Bar()# obj.f2()# # FOO.f2# # Foo.f1# 示范三、# 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# Foo.f1
-
classmethod
# 一、绑定方法:特殊之处在于将调用者本身当做第一个参数自动传入# 1.绑定给对象的方法:调用者是对象,自动传入的是对象# 2.绑定给类的方法:调用者是类,自动传入的是类# import settings# class Mysql:# def __init__(self,ip,port):# self.ip = ip# self.port = port## def func(self):# print('%s %s'%(self.ip,self.port))## # obj = Mysql('192.168.1.1',80)# @classmethod# def from_conf(cls): # 将下面的函数装饰成绑定给类的方法# print(cls) # <class '__main__.Mysql'> 将其写活了# return cls(settings.IP,settings.PORT)# obj1 = Mysql.from_conf()# print(obj1.__dict__)# print(obj1.port)# 二、非绑定方法==>静态方法# 没有绑定给任何人:调用者可以是类、对象,没有自动传参的效果class Mysql: def __init__(self,ip,port): self.nid = self.create_id() self.ip = ip self.prot = port @staticmethod # 将下述函数装饰成一个静态方法 def create_id(): # print(x,y,z) import uuid return uuid.uuid4() @classmethod def f1(cls): pass def f2(self): passobj = Mysql('192.168.1.1',3306)# Mysql.create_id()# obj.create_id()# print(Mysql.create_id) # <function Mysql.create_id at 0x000002BA70B4B550># print(obj.create_id) # <function Mysql.create_id at 0x000002BA70B4B550># print(Mysql.create_id) # <function Mysql.create_id at 0x00000178B738B550># print(Mysql.f1) # <bound method Mysql.f1 of <class '__main__.Mysql'>># print(Mysql.f2) # <function Mysql.f2 at 0x00000178B738BAF0>
-
mixins机制
# 1、多继承的正确打开方式:mixins机制# mixins的机制核心:就是在多继承的背景下尽可能的提升多继承的可读性'''可以看到,上面的CivilAircraft、Helicopter类实现了多继承,不过它继承的第一个类我们起名为FlyableMixin,而不是Flyable,这个并不影响功能,但是会告诉后来读代码的人,这个类是一个Mixin类,表示混入(mix-in),这种命名方式就是用来明确地告诉别人(python语言惯用的手法),这个类是作为功能添加到子类中,而不是作为父类,它的作用同Java中的接口。所以从含义上理解,CivilAircraft、Helicopter类都只是一个Vehicle,而不是一个飞行器。使用Mixin类实现多重继承要非常小心首先它必须表示某一种功能,而不是某个物品,python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀其次它必须责任单一,如果有多个功能,那就写多个Mixin类,一个类可以继承多个Mixin,为了保证遵循继承的“is-a”原则,只能继承一个标识其归属含义的父类然后,它不依赖于子类的实现最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。(比如飞机照样可以载客,就是不能飞了) Mixins是从多个类中重用代码的好方法,但是需要付出相应的代价,我们定义的Minx类越多,子类的代码可读性就会越差,并且更恶心的是,在继承的层级变多时,代码阅读者在定位某一个方法到底在何处调用时会晕头转向'''class Vehicle: # 交通工具 passclass FlyableMixin: def fly(self): ''' 飞行功能相应的代码 ''' print("I am flying")class CivilAircraft(FlyableMixin, Vehicle): # 民航飞机 passclass Helicopter(FlyableMixin, Vehicle): # 直升飞机 passclass Car(Vehicle): # 汽车 pass# ps: 采用某种规范(如命名规范)来解决具体的问题是python惯用的套路
-
在子类派生的新方法中如何重用父类的功能
# 在子类派生的新方法中如何重用父类的功能# 方式一:指名道姓调用某一个类下的函数=》不依赖于继承关系# class OldboyPeopel:# school = 'oldschool'## def __init__(self,name ,age,gender):# self.name = name# self.age = age# self.gender = gender## class Student(OldboyPeopel):## def choose_course(self):# print('学生%s 正在选课 '% self.name)## stu_obj = Student('ycc',18,'male')# print(stu_obj.__dict__) # {'name': 'ycc', 'age': 18, 'gender': 'male'}# print(stu_obj.school) # oldschool# stu_obj.choose_course()## class Teacher(OldboyPeopel):# def __init__(self,name,age,gender,salary,level):# OldboyPeopel.__init__(self,name,age,gender)# self.salary = salary# self.level = level## def score(self):# print('老师%s 正在打分'%self.name)## tea_obj = Teacher('egon',18,'male',3000,10)# print(tea_obj.__dict__)# print(tea_obj.name)# tea_obj.score()# # 方式二:super()调用父类提供给自己的方法=》严格以来继承体系# 调用super()会得到一个特殊的对象,该对象会参照发起属性查找的那个类的mro,去当前类的父类中找属性# class OldboyPeopel:# school = 'oldschool'## def __init__(self,name ,age,gender):# self.name = name# self.age = age# self.gender = gender## class Student(OldboyPeopel):## def choose_course(self):# print('学生%s 正在选课 '% self.name)## # stu_obj = Student('ycc',18,'male')# # print(stu_obj.__dict__) # {'name': 'ycc', 'age': 18, 'gender': 'male'}# # print(stu_obj.school) # oldschool# # stu_obj.choose_course()## class Teacher(OldboyPeopel):# def __init__(self,name,age,gender,salary,level):# # super(Teacher, self).__init__(name,age,gender)# super().__init__(name,age,gender) # super()只能在新式类中使用,可以简写# # 调用的是方法,自动传入对象self# self.salary = salary# self.level = level## def score(self):# print('老师%s 正在打分'%self.name)# print(Teacher.mro())# # [<class '__main__.Teacher'>, <class '__main__.OldboyPeopel'>, <class 'object'>]# # 这里可以看到可以从类OldboyPeopel找name,age,gender# tea_obj = Teacher('egon',18,'male',3000,10)# print(tea_obj.__dict__)# print(tea_obj.name)# tea_obj.score()# super()案例class A: def test(self): super().test()class B: def test(self): print('from B')class C(A,B): passobj = C()obj.test() # from Bprint(C.mro())# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]# 调用super()会得到一个特殊的对象,该对象会参照发起属性查找的那个类的mro,去当前类的父类中找属性# 先在C类里找,没有,然后去他爹那A类去找,没有,但是这里调用super()会得到一个特殊的对象,# 该对象会参照发起属性查找的那个类的mro,去当前类的父类中找属性,虽然肉眼看B不是A的爹,# 但是注意要看C.mro(),这里面B就是A的爹# 再次强调,super()是参照发起属性查找的那个mro,即C.mro(),而不是本身的A.mro
-
多态
# 1、什么是多态:同一事物有多种形态# class Animal:# pass## class People(Animal):# pass## class Pig(Animal):# pass## class Dog(Animal):# pass# 2、为何要有多态=》多态会带来什么样的特性,多态性# 多态性指的是可以在不考虑对象具体类型的情况下而直接使用对象## class Animal: # 统一所有子类的方法# def say(self):# print('动物的发声')## class People(Animal):# def say(self):# super().say()# print('嘤嘤嘤')## class Pig(Animal):# def say(self):# super().say()# print('汪汪汪')### class Dog(Animal):# def say(self):# super().say()# print('哼哼哼')## obj1 = People()# obj2 = Dog()# obj3 = Pig()## # obj1.say()# # obj2.say()# # obj3.say()## # 定义统一的接口,接受传入的动物的对象# def animal_say(animal):# animal.say()## animal_say(obj1)# animal_say(obj2)# animal_say(obj3)# len('hello')# len([1,2,3])# len({'a':1,'b':2})## print('hello'.__len__())# print([1,2,3].__len__())# print({'a':1,'b':2}.__len__())## # 多态性的提现# def my_len(val):# return val.__len__()## print(my_len('hello'))# print(my_len([1,2,3]))# print(my_len({'a':1,'b':2}))# python 推崇的鸭子类型# 推崇不要继承父类,让这些毫无相关的类让他们做的像# class Cpu:# def read(self):# print('Cpu read')## def write(self):# print('Cpu write')## class Mem:# def read(self):# print('Mem read')## def write(self):# print('Mem write')## class Txt:# def read(self):# print('Txt read')## def write(self):# print('Txt write')## obj1 = Cpu()# obj2 = Mem()# obj3 = Txt()## obj1.read()# obj1.write()## obj2.read()# obj2.write()## obj3.read()# obj3.write()# 了解import abcclass Animal(metaclass=abc.ABCMeta): # 将其做成一个抽象基类 # 统一所有子类的标准 def say(self): print('动物的发声')# obj = Animal() # 不能实例化抽象类自己class People(Animal):# 强制继承抽象基类的子类,都必须遵循父类的标准,都必须有其规定的方法,例如下面这些类都必须继承say功能,不然就会报错 def say(self): super().say() print('嘤嘤嘤')class Pig(Animal): def say(self): super().say() print('汪汪汪')class Dog(Animal): def say(self): super().say() print('哼哼哼')obj1 = People()obj2 = Dog()obj3 = Pig()# obj1.say()# obj2.say()# obj3.say()