第三模块第24章 面向对象
book.luffycity.com/python-book/index.html
https://www.cnblogs.com/linhaifeng/articles/6182264.html
1.3 编程范式
# 编程范式:
# 按照某种语法风格+数据结构+算法来编写程序
1.4 面向过程编程
面向过程: 核心是过程二字, 过程指的是解决问题的步骤, 设计一条流水线, 机械式的思维.
优点: 复杂的问题流程化, 进而简单化
缺点: 可扩展性差
1.5 面向对象编程介绍
面向对象: 核心是对象二字, 对象是特征与技能的结合体
优点: 可扩展性强
缺点: 编程复杂度高
应用场景: 用户需求经常变化, 如互联网应用, 游戏, 企业内部应用
1.6 定义类与实例化出对象
类是一系列对象相似特征与技能的结合体
强调: 站在不同的角度, 得到的分类是不一样的
在现实世界中, 先有对象, 后有类
在程序中, 先定义类, 后调用类来产生对象
# 先定义类 class LuffyStudent: school = 'luffycity' def learn(self): print('is learning') def eat(self): print('is eating') def sleep(self): print('is sleeping') # 后实例化出对象 stu1 = LuffyStudent() stu2 = LuffyStudent() print(stu1) # <__main__.LuffyStudent object at 0x000001EB53893D68> print(stu2) # <__main__.LuffyStudent object at 0x000001EB538C6FD0>
1.7 如何使用类
''' 类在定义阶段就会运行代码 类内定义的变量称为数据属性, 定义的函数称为函数属性 ''' class LuffyStudent: school = 'luffycity' # 数据属性 def learn(self): # 函数属性 print('is learning') def eat(self): print('is eating') def sleep(self): print('is sleeping') # 在类的定义阶段代码就会运行 print(LuffyStudent.__dict__) # 查看类的名称空间 ''' 结果: {'__module__': '__main__',
'school': 'luffycity', 'learn': <function LuffyStudent.learn at 0x0000019A2BC41488>, 'eat': <function LuffyStudent.eat at 0x0000019A2BC41A60>, 'sleep': <function LuffyStudent.sleep at 0x0000019A2BC41B70>, '__dict__': <attribute '__dict__' of 'LuffyStudent' objects>, '__weakref__': <attribute '__weakref__' of 'LuffyStudent' objects>, '__doc__': None} ''' # 1. 查看类的属性 print(LuffyStudent.school) # luffycity print(LuffyStudent.learn) # <function LuffyStudent.learn at 0x0000019A2BC41488> # 2. 增加属性 LuffyStudent.country = 'china' # 3. 删除属性 del LuffyStudent.country # 4. 修改属性 LuffyStudent.school = 'Luffycity'
1.8 如何使用对象
# __init__方法用来为对象定制对象独有的特征 class LuffyStudent: school = 'luffycity' # 对象共有的特征 def __init__(self, name, gender, age): # 实例化对象时自动调用本方法 self.name = name self.gender = gender self.age = age def learn(self): print('is learning') def eat(self): print('is eating') def sleep(self): print('is sleeping') stu1 = LuffyStudent('egon','male',18) # 加上__init__后, 实例化的步骤 # 1. 先产生一个空对象 # 2. 触发Luffycity.__init__, 将空对象传给self, 并将后面的参数传进来 print(stu1.__dict__) # 查看对象stu1的名称空间 # 结果: {'name': 'egon', 'gender': 'male', 'age': 18} # 1.查看对象的属性 print(stu1.name) # 2. 修改对象的属性 stu1.name = 'alex' # 3. 删除 del stu1.name # 4. 增加 stu1.name = 'egon'
1.9 属性查找与绑定方法
class LuffyStudent: school = 'luffycity' def __init__(self, name, gender, age): self.name = name self.gender = gender self.age = age def learn(self, x): print('%s is learning %s'%(self.name,x)) def eat(self): print('%s is eating'%self.name) def sleep(self): print('%s is sleeping'%self.name) stu1 = LuffyStudent('egon','male',18) stu2 = LuffyStudent('alex','male',28) # 类中的数据属性: 是所有对象共有的 print(LuffyStudent.school, id(LuffyStudent.school)) # luffycity 2210760573872, 类可以访问 print(stu1.school, id(stu1.school)) # luffycity 2210760573872, 对象可以访问 # 类中的函数属性: 是绑定给对象使用的, 绑定到不同的对象是不同的绑定方法, 对象调用绑定方法时会将对象本身当成第一个参数传入 print(LuffyStudent.learn) # <function LuffyStudent.learn at 0x00000214BB8E1B70> print(stu1.learn) # <bound method LuffyStudent.learn of <__main__.LuffyStudent object at 0x00000214BB8DF978>> print(stu2.learn) # <bound method LuffyStudent.learn of <__main__.LuffyStudent object at 0x00000214BB8DF9B0>> LuffyStudent.learn(stu1, '英语') # 类名调用函数, 需将对象传进去, egon is learning 英语 stu1.learn('数学') # 对象调用方法, 无需传对象, 只需传self后的参数, egon is learning 数学 stu2.learn('语文') # alex is learning 语文 # 类中定义的函数属性, 在未经处理的情况下, 不是给类用的, 是绑定给对象使用的. # 如果对象中和类中的属性存在重名, 则优先查找对象自己中的, 没有则去类中找, 自己的类中没有则去父类中去找, 都找不到会报错, 不会去全局中找.
1.10 python中一切皆对象
1. 站在不同的角度, 定义出来的类是截然不同的
2. 现实中的类不完全等于程序中的类
3. 有时为了变成需要, 程序中可能会出现现实中不存在的类
# python中一切皆对象, python3中统一了类与类型的概念, 类型就是类. print(type([1,2])) # <class 'list'> l = [1, 2, 3] # l = list([1, 2, 3]), 类list实例化对象 l.append(5) #l对象调用绑定方法append
1.11 面向对象可扩展性总结
1.12 小练习1
''' 练习1: 编写一个学生类, 产生一堆学生对象 要求: 有一个计数器(属性), 统计总共实例了多少对象 ''' class Student: school = 'luffycity' count = 0 def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender # self.count += 1 会为对象创建私有属性count Student.count+=1 def learn(self): print('%s is learning' %self.name) stu1 = Student('egon', 'male', 18) stu2 = Student('alex', 'female', 28) print(Student.count) # 2 print(stu1.count) # 2 print(stu2.count) # 2
1.13 小练习2
''' 练习2: 模仿王者荣耀定义两个英雄类 要求: 英雄需要有昵称, 攻击力, 生命值等属性 实例化出两个英雄对象 英雄之间可以互殴, 被殴打的一方掉血, 血量小于0则判定为死亡. ''' class Garen: camp = 'Demacia' def __init__(self, nickname, life_value, aggresivity): self.nickname = nickname self.life_value = life_value self.aggresivity = aggresivity def attack(self, enemy): enemy.life_value -= self.aggresivity class Riven: camp = 'Noxus' def __init__(self, nickname, life_value, aggresivity): self.nickname = nickname self.life_value = life_value self.aggresivity = aggresivity def attack(self, enemy): enemy.life_value -= self.aggresivity g1 = Garen('草丛伦', 100, 30) r1 = Riven('瑞文', 80, 50) g1.attack(r1) print(r1.life_value) # 50
1.14 继承与重用性
''' 什么是继承? 继承指的是类与类之间的关系, 是一种'什么是什么的关系', 继承的功能之一就是用来解决代码重用问题. 继承是一种创建新类的方式, 在python中, 新建的类可以继承一个或多个父类, 父类又可以称为基类或超类, 新建的类称为派生类或子类. ''' class ParentClass1: pass class ParentClass2: pass class SubClass1(ParentClass1): pass class SubClass2(ParentClass1, ParentClass2): pass print(SubClass1.__bases__) # 查看父类, (<class '__main__.ParentClass1'>,) print(SubClass2.__bases__) # (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>) class Hero: def __init__(self, nickname, life_value, aggresivity): self.nickname = nickname self.life_value = life_value self.aggresivity = aggresivity def attack(self, enemy): enemy.life_value -= self.aggresivity class Garen(Hero): camp = 'Demacia' class Riven(Hero): camp = 'Noxus' g1 = Garen('草丛伦', 100, 30) r1 = Riven('瑞文', 80, 50) g1.attack(r1) print(g1.nickname) # 从对象自己这找, 如果没有则去类中找, 如果没有则去父类中找, 否则报错, 不会去全局找. print(r1.life_value) # 50 # 属性查找小练习 class Foo: def f1(self): print('from Foo.f1') def f2(self): print('from FOO.f2') self.f1() # b.f1() class Bar(Foo): def f1(self): print('from Bar.f1') b = Bar() b.f2() ''' 结果: from FOO.f2 from Bar.f1 '''
1.15 派生
# 如果子类中派生出新的属性, 则以新的属性为主 class Hero: def __init__(self, nickname, life_value, aggresivity): self.nickname = nickname self.life_value = life_value self.aggresivity = aggresivity def attack(self, enemy): enemy.life_value -= self.aggresivity class Garen(Hero): camp = 'Demacia' def attack(self, enemy): print('from Garen class') class Riven(Hero): camp = 'Noxus' g1 = Garen('草丛伦', 100, 30) r1 = Riven('瑞文', 80, 50) g1.attack(r1) print(g1.nickname) # 从对象自己这找, 如果没有则去类中找, 如果没有则去父类中找, 否则报错, 不会去全局找. print(r1.life_value) # 80
1.16 继承的实现原理
python到底是如何实现继承的? 对于定义的每一个类, python会计算出一个方法解析顺序(MRO)列表, 该列表是一个简单的所有基类的线性排序列表, 例如:
>>> F.mro() #等同于F.__mro__ [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
为了实现继承, python会在MRO列表上从左到右开始查找基类, 查找到第一个匹配这个属性的类为止, 而这个MRO列表的构造是通过一个C3线性算法来实现的. 它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1. 子类会先于父类被检查
2. 多个父类会根据它们在列表中的顺序被检查
3. 如果对下一个类存在两个合法的选择, 选择第一个父类.
在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如果继承了多个父类,那么属性的查找方式有两种,分别是:深度优先和广度优先
python中类分为两种: 新式类和经典类, python2中有这两种分法, python3中只有新式类.
python2中的经典类: 没有继承object的类, 以及它的子类都称为经典类.
python2中的新式类: 继承了object的类, 以及它的子类都称为新式类.
python3中默认继承object类, 都是新式类
class Foo: pass print(Foo.__bases__) # (<class 'object'>,)


class Foo: pass print(Foo.__bases__) # (<class 'object'>,) # 验证多继承情况下的属性查找 class A(object): 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): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 ''' 结果: (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) ''' #新式类继承顺序:F->D->B->E->C->A #经典类继承顺序:F->D->B->A->E->C #python3中统一都是新式类 #pyhon2中才分新式类与经典类
1.17 在子类中重用父类的方法或属性
# 在子类派生出的新的方法中重用父类的方法, 有两种实现方式: # 方式一: 指名道姓(不依赖继承) # 方式二: super()(依赖继承), super会在MRO列表中寻找关系 class Hero: def __init__(self, nickname, life_value, aggresivity): self.nickname = nickname self.life_value = life_value self.aggresivity = aggresivity def attack(self, enemy): enemy.life_value -= self.aggresivity class Garen(Hero): camp = 'Demacia' def __init__(self, nickname, life_value, aggresivity, weapon): # Hero.__init__(self, nickname, life_value, aggresivity) # 指明道姓的方式 super(Garen, self).__init__(nickname, life_value, aggresivity) # super(Garen, self)创建了一个对象, python2中需要这么写, 但是在python3中可以简写成以下方式: # super().__init__(nickname, life_value, aggresivity) self.weapon = weapon def attack(self, enemy): # Hero.attack(self, enemy) # 指明道姓的方式, 不依赖于继承关系 super(Garen, self).attack(enemy) print('from Garen class') class Riven(Hero): camp = 'Noxus' g1 = Garen('草丛伦', 100, 30, '金箍棒') r1 = Riven('瑞文', 80, 50) g1.attack(r1) print(r1.life_value) # 50 class A: def f1(self): print('from A') super().f1() class B: def f1(self): print('from B') class C(A, B): pass print(C.mro()) # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>] c = C() c.f1() ''' 结果: from A from B ''' # 说明, 在查找时基于C的MRO列表进行查找.
1.18 组合
# 组合: 解决谁有谁的类之间的关系. class Person: school = 'luffycity' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class Teacher(Person): school = 'luffycity' def __init__(self, name, age, gender, level, salary): super().__init__(name, age, gender) self.level = level self.salary = salary def teach(self): print('%s is teaching' %self.name) class Student(Person): school = 'luffycity' def __init__(self, name, age, gender, clas): super().__init__(name, age, gender) self.clas = clas def teach(self): print('%s is teaching' %self.name) class Course: def __init__(self, cname, price, period): self.cname = cname self.price = price self.period = period def tell_info(self): print('课程名<%s>'%self.cname) t1 = Teacher('alex', 18, 'female', 10, 3000) s1 = Student('egon', 28, 'female', '一班') c1 = Course('语文', 100, 20) c2 = Course('数学', 200, 50) t1.course1 = c1 # t1的属性指向了一个对象 print(t1.course1.cname) t1.course1.tell_info() t1.course2 = c2 # t1的属性指向了一个对象 print(t1.course2.cname) t1.course2.tell_info() s1.courses = [] s1.courses.append(c1) s1.courses.append(c2)
1.19 抽象类与归一化
import abc class Animal(metaclass=abc.ABCMeta): # 抽象类, 只能被继承, 不能被实例化. 其作用是规范子类. all_type = 'animal' @abc.abstractmethod def run(self): pass @abc.abstractmethod def eat(self): pass class People(Animal): def run(self): # 必须包含父类中的run和eat方法. print('People is running') def eat(self): print('People is eating') class Pig(Animal): def run(self): print('Pig is running') def eat(self): print('Pig is eating') peop1 = People() pig1 = Pig() peop1.run() # People is running pig1.run() # Pig is running
1.20 多态与多态性
# 多态: 同一类事物的多种形态 import abc class Animal(metaclass=abc.ABCMeta): all_type = 'animal' @abc.abstractmethod def run(self): pass class People(Animal): def run(self): print('People is running') class Pig(Animal): def run(self): print('Pig is running') # 多态性: 指的是可以在不考虑对象类型的情况下直接使用对象 # peop1, pig1都是动物, 只要是动物肯定有run方法, 于是我们可以不用考虑它们具体是什么类型, 可以直接使用 peop1 = People() pig1 = Pig() peop1.run() # People is running pig1.run() # Pig is running # 以上称为动态多态性 # 静态多态性: 如任何类型都可以使用运算符+进行运算 # 更进一步, 我们可以定义一个统一的接口进行使用 def func(animal): animal.run() func(peop1) func(pig1) # 以上示例中继承了同一父类, 子类受父类的约束 ''' 多态性的好处: 1. 增加了程序的灵活性 以不变应万变, 不论对象千变万化, 使用者都是同一形式去调用 2. 增加了程序的可扩展性 ''' class File: def read(self): print('file read') def write(self): print('file write') class Disk: def read(self): print('disk read') def write(self): print('disk write') class Text: def read(self): print('text read') def write(self): print('text write') f = File() d = Disk() t = Text() def f1(x): x.read() x.write() f1(f) f1(d) f1(t) # 以上示例没有继承同一父类, 但是彼此存在相似之处. ''' python崇尚鸭子类型, 只要长得像鸭子, 就是鸭子. 类与类之间不继承同一父类, 只要有相似之处, 就可以了. '''
1.21 封装之如何隐藏属性
class A: __x = 1 # 变形隐藏 _A__x = 1 def __init__(self, name): self.__name = name def __foo(self): # 定义阶段, 检测语法时转化: def _A__foo(self): print('run foo') def bar(self): self.__foo() # self._A__foo() print('from bar') # print(A.__x) # AttributeError: type object 'A' has no attribute '__x', 说明已经隐藏了 a = A('egon') print(A.__dict__) print(a.__dict__) # {'_A__name': 'egon'} a.bar() # run foo from bar a._A__foo() # run foo ''' 这种变形的特点: 1. 在类外部无法直接通过obj.__AttriName访问 2. 在类内部可以直接通过obj.__AttriName访问 3. 子类无法覆盖父类__开头的属性 ''' class Foo: def __func(self): # _Foo__func print('from foo') class Bar(Foo): def __func(self): # _Bar__func print('from bar') # 加__会在类的定义阶段进行变形 ''' 总结这种变形需要注意的问题: 1. 这种机制并没有真正意义上限制我们从外部直接访问属性, 知道了类名和属性名就可以拼出名字: _类名__属性名,然后就可以访问了. 2. 变形的过程只在类的定义阶段发生一次, 在定义后的赋值操作, 不会变形. 3. 在继承中, 父类如果不想让子类覆盖自己的方法, 可以将方法定义为私有 ''' # 验证问题2 class B: __x = 1 def __init__(self, name): self.__name = name B.__y = 2 print(B.__dict__) # {..., '__y': 2} # 验证问题3 class C: def foo(self): print('C.foo') def bar(self): print('C.bar') self.foo() class D(C): def foo(self): print('D.foo') d = D() d.bar() #C.bar D.foo class C: def __foo(self): # _C__foo print('C.foo') def bar(self): print('C.bar') self.__foo() # self._C__foo class D(C): def __foo(self): # _D__foo print('D.foo') d = D() d.bar() # C.bar C.foo
1.22 封装的意义
# 一, 封装数据属性的目的: 明确地区分内外, 控制外部对隐藏属性的操作行为. class People: def __init__(self, name, age): self.__name = name self.__age = age def tell_info(self): print('Name:<%s>, Age:<%s>' %(self.__name, self.__age)) def set_info(self, name, age): if not isinstance(name,str): print('名字必须是字符串类型') return if not isinstance(age, int): print('年龄必须是数字类型') return self.__name = name self.__age = age p = People('egon', 18) p.tell_info() # 加了__后则无法直接访问或修改属性, 必须通过特定的接口(如tell_info, set_info)来间接进行访问和修改. # 接口上附加一些逻辑, 来控制外部对隐藏属性的访问和修改. # 二, 封装方法的目的: 隔离复杂度 # 不让直接接触到零散的方法, 如__card, __auth, 可以直接接触到封装好的方法, 如withdraw. class ATM: def __card(self): print('插卡') def __auth(self): print('用户认证') def __input(self): print('输入取款金额') def __print(self): print('打印账单') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print() self.__take_money() a = ATM() a.withdraw()
1.23 封装与可扩展性
class Room: def __init__(self, name, owner, height, weight, length): self.name = name self.owner = owner self.__height = height self.__weight = weight self.__length = length def tell_area(self): return self.__weight * self.__length r=Room('卫生间','alex',10,10,10) print(r.tell_area()) # 使用者只需要记住接口即可, 无需关注里面的原理.
1.24 property的使用
class People: def __init__(self, name, weight, height): self.name = name self.weight = weight self.height = height @property # 将bmi的调用方式由bmi()转为bmi, 使使用者感觉调用的不是一个功能, 而是一个属性. def bmi(self): return self.weight / (self.height ** 2) p = People('egon', 75, 1.81) print(p.bmi) # 注意: bmi本质是一个方法, 不能对其进行赋值. class People: def __init__(self, name): self.__name = name @property def name(self): return self.__name # 注意: name本质是一个方法, 不能对其进行赋值. # 不过, 通过以下方法可以实现赋值. @name.setter def name(self, val): if not isinstance(val, str): print('名字必须是字符串类型') self.__name = val @name.deleter def name(self): print('不允许删除') p = People('egon') p.name = 'EGON' print(p.name) # EGON del p.name # 不允许删除
1.25 绑定方法与非绑定方法介绍
''' 在类内部定义的函数, 分为两大类: 一: 绑定方法: 绑定给谁, 就应该由谁来调用, 谁来调用就自动把谁当作第一个参数传入. 绑定到对象的方法: 在类内定义的没有被任何装饰器修饰的方法 绑定到类的方法: 在类内定义的被装饰器classmethod修饰的方法 二: 非绑定方法: 没有自动传值这么一说, 就是在类中定义的一个普通工具, 对象和类都可以使用. 非绑定方法: 不与类或者对象绑定 ''' class Foo: def __init__(self, name): self.name = name def tell(self): # 绑定到对象的方法 print('名字是%s' %self.name) @classmethod def func(cls): # 绑定到类的方法 print(cls) @staticmethod def func1(x, y): #括号里面可以写参数, 也可以不写参数. 没有自动传递的参数. print(x+y) f = Foo('egon') print(Foo.tell) # <function Foo.tell at 0x0000026860001A60> Foo.tell(f) # 此处, 必须对self进行传值, self不能自动传值. print(f.tell) # <bound method Foo.tell of <__main__.Foo object at 0x000002B04F8B3CC0>> f.tell() print(Foo.func) # <bound method Foo.func of <class '__main__.Foo'>> Foo.func() # <class '__main__.Foo'> print(Foo.func1) # <function Foo.func1 at 0x000002BF6F551BF8> print(f.func1) # <function Foo.func1 at 0x000002BF6F551BF8> Foo.func1(1,2) # 3 f.func1(1,3) # 4
1.26 绑定方法与非绑定方法的使用
import settings import hashlib import time class People: def __init__(self, name, age, gender): self.id = self.create_id() self.name = name self.age = age self.gender = gender def tell_info(self): # 绑定到对象的方法 print('Name: %s, Age:%s, Gender:%s'%(self.name, self.age, self.gender)) @classmethod def from_conf(cls): obj = cls(settings.name, settings.age, settings.gender) return obj @staticmethod def create_id(): time.sleep(0.01) m = hashlib.md5(str(time.time()).encode('utf-8')) return m.hexdigest() p1 = People('egon', 18, 'male') # 绑定给对象, 就应该由对象来调用, 自动将对象本身当作第一个参数传入 p1.tell_info() # Name: egon, Age:18, Gender:male # 绑定给类, 就应该由类来调用, 自动将类本身当作第一个参数传入 p2 = People.from_conf() p2.tell_info() # Name: alex, Age:10, Gender:male # 非绑定方法, 不与类或者对象绑定, 谁都可以来调用, 没有自动传值一说. p3 = People('aaa', 12, 'female') p4 = People('bbb', 22, 'male') p5 = People('ccc', 18, 'female') print(p3.id) # e4487e9a7fed738946cd85e9d38bd795 print(p4.id) # b02113fa5ebd6a9e1c50b25c2e7c48f3 print(p5.id) # 8f157e0fd5d76047055fc5f77fc90b98
# settings.py name = 'alex' age = 10 gender = 'male'
1.27 反射
# 反射: 通过字符串映射到对象的属性 class People: country = 'china' def __init__(self, name, age): self.name = name self.age = age def talk(self): print('%s is talking' %self.name) obj = People('egon', 18) # 1. hasattr print(hasattr(obj,'name')) # True, 判断obj下是否有name属性 print(hasattr(obj,'talk')) # True, 判断obj下是否有talk # 2. getattr print(getattr(obj, 'name')) # egon 有则返回结果, 没有则报错, 如果不想让其报错, 可以使用default print(getattr(obj, 'namex', None)) # None, 没有返回None # 3. setattr setattr(obj, 'age', 50) print(obj.age) # 50 setattr(obj, 'gender', 'male') print(obj.__dict__) # {'name': 'egon', 'age': 50, 'gender': 'male'} print(obj.gender) # male # 4. delattr delattr(obj, 'gender') print(obj.__dict__) # {'name': 'egon', 'age': 50} # 以上方法也适用于类 print(getattr(People, 'country')) # china # 反射的应用: class Service: def run(self): while True: inp = input('>>>:').strip() cmds = inp.split() if hasattr(self, cmds[0]): func=getattr(self, cmds[0]) func(cmds) def get(self, cmds): print('get...', cmds) def put(self, cmds): print('put...', cmds) obj = Service() # 接收用户输入并触发后面的方法 obj.run() ''' 结果: >>>:get get... ['get'] >>>:get a.txt get... ['get', 'a.txt'] '''
1.28 内置方法介绍
https://www.cnblogs.com/linhaifeng/articles/6204014.html
一: isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
1 class Foo(object): 2 pass 3 4 obj = Foo() 5 6 isinstance(obj, Foo)
issubclass(sub, super)检查sub类是否是 super 类的派生类
1 class Foo(object): 2 pass 3 4 class Bar(Foo): 5 pass 6 7 issubclass(Bar, Foo)
二: item系列
# item系列 # 将对象模拟地像字典 class Foo: def __init__(self, name): self.name = name def __getitem__(self, item): return self.__dict__.get(item) def __setitem__(self, key, value): self.__dict__[key] = value def __delitem__(self, key): # del self.__dict__[key] self.__dict__.pop(key) obj = Foo('egon') # 查看属性 print(obj['name']) # 设置属性 obj['gender'] = 'male' # 删除属性 del obj['name']
# __str__方法: class People: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return '<name:%s, age:%s>'%(self.name, self.age) obj = People('egon', 18) print(obj) # 打印对象时触发对象下的__str__方法, 并且要求返回的一定是字符串类型的数据
# __del__方法 # 在python自动回收对象之前触发__del__, 回收跟对象相关联的某些资源. class Open: def __init__(self, filename): print('open file...') self.filename = filename def __del__(self): print('回收操作系统等资源: f.close()') f = Open('settings.py') print('--------main---------') # del f 会手动触发__del__, 不使用这种方法则自动调用__del__ ''' 结果: open file... --------main--------- del... '''
1.29 元类
https://www.cnblogs.com/linhaifeng/articles/8029564.html
# 元类介绍 ''' 储备知识exec命令的使用, 有三个参数 参数1: 字符串形式的命令 参数2: 全局作用局(字典形式), 如果不指定就默认使用globals() 参数3: 局部作用局(字典形式), 如果不指定就默认使用locals() ''' g = { 'x':1, 'y':2 } l = {} exec(''' global x,m x = 10 m = 100 z = 3 ''', g, l) print(g) # 可以将exec当作函数看待 ''' python中一切皆对象, 对象可以怎么用? 1. 都可以被引用, x = obj 2. 都可以当作函数的参数传入 3. 都可以当作函数的返回值 4. 都可以当作容器类型的元素 ''' # 类也是对象, 对象是经过实例化类得来的, 那么Foo也应该是由类实例化得到的. class Foo: # Foo = type(...) pass obj = Foo() print(type(obj)) # <class '__main__.Foo'> print(type(Foo)) # <class 'type'> #产生类的类称之为元类, 默认所有用class定义的类, 它们的元类是type. # 定义类的两种方式: # 方式一: class class Chinese: # Chinese = type(...) country = 'china' def __init__(self, name, age): self.name = name self.age = age def talk(self): print('%s is talking' %self.name) # 方式二: # 定义类的三要素: 类名, 类的基类们, 类的名称空间 class_name = 'Chinese' class_bases = (object,) class_body = ''' country = 'china' def __init__(self, name, age): self.name = name self.age = age def talk(self): print('%s is talking' %self.name) ''' class_dic = {} exec(class_body,globals(),class_dic) print(class_dic) # {'country': 'china', '__init__': <function __init__ at 0x0000022563A21EA0>, 'talk': <function talk at 0x0000022563A380D0>} Chinese1 = type(class_name,class_bases,class_dic) print(Chinese1) # <class '__main__.Chinese'> obj1 = Chinese1('alex', 20) print(obj1, obj1.name, obj1.age) # <__main__.Chinese object at 0x0000018894F4FF98> alex 20
# 定义元类控制类的创建 class Mymeta(type): def __init__(self, class_name, class_bases, class_dic): if not class_name.istitle(): raise TypeError('类名的首字母必须大写') if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): raise TypeError('必须有注释, 且注释不能为空') super(Mymeta, self).__init__(class_name, class_bases, class_dic) class Chinese(object,metaclass=Mymeta): # Chinese = Mymeta(class_name, class_bases, class_dic) '''''' country = 'china' def __init__(self, name, age): self.name = name self.age = age def talk(self): print('%s is talking' %self.name)
# 自定义元类控制类的实例化行为 # 知识储备__call__方法 class Foo: def __call__(self, *args, **kwargs): print(args, kwargs) obj = Foo() obj(1, 2, x = 'aa') # (1, 2) {'x': 'aa'}, 在调用对象时会自动触发执行__call__方法 # 元类内部也应该有一个__call__方法, 会在调用Foo时触发执行. class Mymeta(type): def __init__(self, class_name, class_bases, class_dic): if not class_name.istitle(): raise TypeError('类名的首字母必须大写') if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): raise TypeError('必须有注释, 且注释不能为空') super(Mymeta, self).__init__(class_name, class_bases, class_dic) def __call__(self, *args, **kwargs): # 第一件事: 先造出一个空对象obj obj = object.__new__(self) # 第二件事: 初始化obj self.__init__(obj,*args,**kwargs) # 第三件事: 返回obj return obj class Chinese(object,metaclass=Mymeta): # Chinese = Mymeta(class_name, class_bases, class_dic) ''' xxx ''' country = 'china' def __init__(self, name, age): self.name = name self.age = age def talk(self): print('%s is talking' %self.name) obj = Chinese('egon', age=18) print(obj.__dict__)
# 自定义元类控制类的实例化行为的应用 # 单例模式 # 实现方式一: class MySQL: __instance = None def __init__(self): self.host = '127.0.0.1' self.port = 3306 @classmethod def singleton(cls): if not cls.__instance: obj = cls() cls.__instance=obj return cls.__instance obj1 = MySQL.singleton() obj2 = MySQL.singleton() # 实现方式二: 元类的方式 class Mymeta(type): def __init__(self, class_name, class_bases, class_dic): if not class_name.istitle(): raise TypeError('类名的首字母必须大写') if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): raise TypeError('必须有注释, 且注释不能为空') super(Mymeta, self).__init__(class_name, class_bases, class_dic) self.__instance = None def __call__(self, *args, **kwargs): if not self.__instance: obj = object.__new__(self) self.__init__(obj) self.__instance = obj return self.__instance class Mysql(object,metaclass=Mymeta): ''' xxx ''' def __init__(self): self.host = '127.0.0.1' self.port = 3306 obj1 = Mysql() obj2 = Mysql() obj3 = Mysql() print(obj1 is obj2 is obj3) # True
面向对象实战:
https://www.cnblogs.com/linhaifeng/articles/6182264.html#_label15
浙公网安备 33010602011771号