面向过程与面向对象(一)
一.面向过程与面向对象:
面向过程:
重过程:解决问题,考虑的是解决问题的流程
解决问题的思路清晰,但拓展性不强
面向对象:
重对象:解决问题,找到解决问题的对象
解决问题的思路可能不止一条(理解解决问题的难度增加),但拓展性强
二.名称空间:
能产生名称空间的有:文件 | 函数 | 类
能产生名称空间的对象有__dict__这个值,通过该这个值访问到名字与地址的对应关系
def func(): pass func.__dict__['index'] = 10000 print(func.__dict__)
属性: print(func.__dict__['index']) print(func.index)
方法: func.add = lambda n1, n2: n1 + n2 print(func.__dict__) print(func.add(10, 20))
三.类与对象:
类:具有相同特征与行为个体集合的抽象
对象:有特征、行为的具体个体,就是类的具体体现
1.类拥有自己的名称空间,类的对象也拥有自己的名称空间
2.属性的访问顺序:对象优先加载自身的属性与方法,如果没有再考虑类的
四.对象的特有的名称空间:
class Student: # __init__方法会在实例化对象时被调用 , student=Student() # 1.会为实例化的对象形成空的名称空间 # 2.就是一个方法,可以被传参,在 类名(实参) 这种方式下调用并传参 __init__(self, 形参) # 3.第一个self就是要产生的当前对象 # 重点:在方法内部,形参拿到了实参值,利用self.属性名 = 形参 = 实参值,对对象的名称空间添加属性 def __init__(self, name, sex): print('2>>>', self) self.name = name self.sex = sex def fn(): print('fn run')
五.对象绑定类方法:
class A: def test(self): print(self) pass a = A()
#绑定的三种方式: a.test() A.test(a) A.__dict__['test'](a)
六.类方法的调用:
class Tool: # 类方法:可以被类与对象调用的方法,第一个参数一定是类 # 类方法不建议拿对象来调用 @classmethod def add(cls, n1, n2): print(id(cls)) cls.test() return n1 + n2 @classmethod def test(cls): pass print(Tool.add(10, 20)) tool = Tool() print(tool.add(100, 200)) print(id(Tool), id(tool)) # 对象调用所属类的类方法,默认第一个参数传入的是 对象.__class__ 就是所属类
七.属性与方法的总结:
class OldBoy: # 属于类的属性 name = '老男孩' # 属于对象的属性 def __init__(self, name): self.name = name # 属于类的方法 # 需求:获取机构的名字 @classmethod def get_class_name(cls): return cls.name # 属于对象的方法 # 需求:获取校区的名字 def get_school_name(self): return self.name # 先创建校区 shanghai = OldBoy('上海校区') shenzhen = OldBoy('深圳校区') # 类方法的使用 # 建议使用类调用 print(OldBoy.get_class_name()) # 类方法拿对象调用并没有多少新增的意义,不建议拿对象调用 print(shanghai.get_class_name()) print(shenzhen.get_class_name()) # 对象方法的使用 # 类调用对象方法,必须把要操作的对象手动传入,不建议使用 print(OldBoy.get_school_name(shanghai)) print(OldBoy.get_school_name(shenzhen)) # 对象调用对象方法,默认将自身传入,建议使用 print(shanghai.get_school_name()) print(shenzhen.get_school_name())
八.封装:
简单地说, 将方法与属性打包封在一个类中称为封装,方便之后调用操作.
九.类的隐藏:
隐藏:对外隐藏类中一些属性与方法的实现细节
优点:外界不能直接访问,让内部的属性与方法具有安全保障
class A:
# __开头的属性,在外界不能通过 cord | __cord 直接访问:对外隐藏了
__cord = '01012300'
# __开头的方法,在外界不能通过 get_money | __get_money 直接访问:对外隐藏了
@classmethod
def __get_money(cls):
print('输入密码,取出100w零花钱')
# 内部还是可以直接访问__开头的属性与方法
@classmethod
def test(cls, flag):
print('test方法被外界调用')
# 在调用test与访问具体数据与功能间添加安全处理的操作
if flag == '自家人':
print(cls.__cord)
cls.__get_money()
隐藏原理: 把用__开头的名字更名为 _类名__变量名
# print(A.__dict__) print(A._A__cord) A._A__get_money()
十.对象的隐藏(利用接口调用):
class AAA: def __init__(self, money): self.__money = money # 取值 @property # 在外界可以 对象.money 进行取值 def money(self): # print('走方法拿到的money') return self.__money # 赋值 @money.setter # 在外界可以 对象.money = 新值 进行赋值 def money(self, money): self.__money = money # 删除 @money.deleter def money(self): # print('逗你玩') del self.__money def get_money(self, flag): if flag == '自家人': return self.__money return 0 def set_money(self, money): self.__money += money print(a.money) a.money = 999999 print(a.money) del a.money print(a.money)
十一.组合: 自定义类的对象作为另外一个类的属性
class Teacher: def __init__(self, name, age): self.name = name self.age = age t1 = Teacher("Owen", 17) print(type(t1.name), type(t1.age)) class Student: # 学生可以有 老师 属性 def __init__(self, name, age, teacher): self.name = name self.age = age # 自定义类的对象作为类的属性:组合 self.teacher = teacher # 创建一个学生 stu = Student('Bob', 18, t1) print(stu.__dict__) # 学生的老师年龄和姓名 print(stu.name) print(stu.teacher) print(stu.teacher.name) print(stu.teacher.age)
十二.继承
1.继承语法:
继承的语法: # class 类名(父类名): pass class A: pass print(A.__bases__) # object 没有定义的类都是继承object print(Leader.__bases__) # Student 定义了父类就继承父类
2.父类隐藏后的继承:
class Sup: __num = 10 def __init__(self, name): self.__name = name @property def name(self): print(self) # <__main__.Sub object at 0x02BA8490>
print(self.__dic__) # 名称空间的key是'_Sup_name' return self.__name @classmethod def __c_fn(cls): print(cls, 'c fn') def __o_fn(self): print(self.name, 'o fn') class Sub(Sup): def test(self): print(self.__dict__) # {'_Sup__name': 'sssssssss'} print(self._Sup__name) pass sub = Sub('sssssssss') print(sub.name) sub.test()
sub._Sup__c_fn()
3.方法的重写(完全不用父类的):
有继承关系下的属性查找顺序: 1.优先找自身,自身没有找父类 2.父类没有找父类的父类 3.一直找到最顶级的父类,如果还没有报错 # 两个名词: 先写子类,抽离 出父类 先写父类,派生 出子类 class Sup: num = 10 def test(self): print('test sup') class Sub(Sup): num = 100 # 先写好父类的方法,由于父类方法的功能不满足子类需求, # 子类可以重写父类方法:方法名与父类相同,自定义方法的实现体 def test(self): print('test sub') print(Sub.num) Sub().test()
4.方法的重用(部分仍用父类的):
class Sup: def test(self): print('>>>sup', self) print('test sup') class Sub(Sup): pass # 重用:还需要父类方法的功能,在父类方法功能基础上再添加新功能 # 突破点:在子类中去调用父类的方法,还有保证调用者是子类(子类的对象) def test(self): # Sup().test() # python2中写法 # super(Sub, self).test() # python3中简化写法 super().test() print('>>>sub', self) print('test sub') Sub().test()
5.__init__结合super()使用:
# 人类:只需要初始化 - name # 老师: 要初始化 - name salary # 学生: 要初始化 - name grade class Sup: def test(self): print(self) def __init__(self, name): self.name = name class Sub(Sup): # 有继承关系下,只要名字相同,即使产生不同,还是属于同一个方法 def test(self, num): super().test() print(num) # 默认父级的__init__可以被继承过来, # 但是会出现子类对象的属性比父类多 def __init__(self, name, salary): super().__init__(name) # 父级有的共性功能通过super()交给父级做 self.salary = salary # 子类特有的自己来完成 # Sub().test(10) # Sub().test() # 使用还是使用自身带参的,不能使用父级不带参的 # (本质名字相同就是一个,优先查找自己的)
6.多继承:
# 简单的多继承 ''' # 属性的查找顺序:优先找自己的,如果没有,按照继承先后查找父级 class A: name = 'A' num = 10 class B: name = 'B' count = 100 # 子类可以继承所有父类的所有可继承属性 class C(A, B): # 自己 => A => B # name = 'C' pass print(C.num) print(C.count) print(C.name) # 打印属性查找的顺序 print(C.mro()) ''' # 复杂的多继承 ''' class A: name = "A" class B(A): name = "B" class C: name = "C" class D(C): name = "D" class E(B, D): name = "E" print(E.mro()) ''' # 经典类:python2中才有,没有继承任何类的类 # 新式类:python2中直接或间接继承object的类,python中所定义的所有类 class G: name = "G" class C(G): pass class B(C): pass class E(G): pass class D(E): name = "D" class F(G): pass class A(B, D, F): pass print(A.mro())
7.菱形继承:
经典类:python2中才有,没有继承任何类的类 - 深度优先 新式类:python2中直接或间接继承object的类,python中所定义的所有类 - 广度优先 深度优先,在查找第一个分支是就将菱形的头查找了 广度优先,菱形的头在所有分支查找接收后再被查找 通过 类.mro() 查看继承顺序图
十三.接口思想:
# 接口类:用来定义功能的类,为继承它的子类提供功能的, # 该类的功能方法一般不需要有实现体,实现体有继承它的子类自己去实现 class PetInterface: def close_master(self): pass class WatchInterface: def watch_door(self): pass class Dog(PetInterface, WatchInterface): def jiao(self): pass def chi(self): pass def pao(self): pass # 一定要重写接口的方法
十四.抽象类:
# 抽象父类:拥有抽象方法(子类共有的方法,但是父类不能有具体的实现体)的父类 # 抽象方法:方法名是具体的,但是实现体是抽象的(在子类中重写来具象化) # python中借助abc来实现抽象父类 import abc # abstract base class class Quan(metaclass=abc.ABCMeta): def __init__(self, name): self.name = name def run(self): print(self.name + 'running') # 抽象父类中的抽象方法,在继承它的子类中必须有自己的实现体 # -- 抽象父类中的抽象方法实现体就没有意义,实现与不实现都是pass填充 @abc.abstractmethod def chi(self): # print(self.name + '肉') pass @abc.abstractmethod def jiao(self): # print('汪汪汪') pass @classmethod @abc.abstractmethod def fn(cls): pass class Dog(Quan): @classmethod def fn(cls): pass def kanmen(self): print(self.name + '看门') def chi(self): super().chi() print(self.name + '狗粮') def jiao(self): print('汪汪汪') class Wolf(Quan): @classmethod def fn(cls): pass def bulie(self): print(self.name + '捕猎') def chi(self): print(self.name + '肉') def jiao(self): print('嗷嗷嗷') dog = Dog('来福') wolf = Wolf('常委') dog.jiao() # wolf.jiao() # dog.run() # wolf.run()
十五.多态:
# 多态:对象的多种状态 - 父类对象的多种(子类对象)状态 import abc class People(metaclass=abc.ABCMeta): def __init__(self, name): self.name = name @abc.abstractmethod def speak(self): pass class Chinese(People): def speak(self): print('说中国话') class England(People): def speak(self): print('说英国话') if __name__ == '__main__': # 多态的体现:功能或是需求,需要父类的对象,可以传入父类对象或任意子类对象均可以 # 注:一般都是规定需要父类对象,传入子类对象 def ask_someone(obj): print('让%s上台演讲' % obj.name) # 父类提供,自己直接继承 obj.speak() # 父类提供,只不过子类重写了 ch = Chinese('王大锤') en = England('Tom') ask_someone(ch) ask_someone(en)
十六.鸭子类型
import abc class People(metaclass=abc.ABCMeta): def __init__(self, name): self.name = name @abc.abstractmethod def speak(self): pass class Chinese(People): def speak(self): print('说中国话') class England(People): def speak(self): print('说英国话') # 鸭子类型: # 1.规定有什么属性及什么方法的类的类型叫鸭子类型 # 2.能提供出规定的属性与方法的对象就是鸭子 class Test: def __init__(self, name): self.name = name def speak(self): print('说鸟语') if __name__ == '__main__': def ask_someone(obj): print('让%s上台演讲' % obj.name) obj.speak() test = Test('鸭子') ask_someone(test)
十七.格式化与析构方法
class A: def __init__(self, name, age): self.name = name self.age = age # 格式化方法:在外界打印该类对象是被调用 # 格式化外界直接打印该类对象的字符串表示结果 def __str__(self): # return 'abc' # return super().__str__() return '<name:%s | age:%s>' % (self.name, self.age) # 析构方法:在对象被消耗的那一刹那被调用,在被消耗前可以做一些事情 def __del__(self): # del会在self代表的对象被消耗的时候被调用 # 我们可以在析构函数中释放该对象持有的其他资源, # 或者将一些持有资源持久化(保存到文件或数据库中) del self.name # 也可以将name存起来
十八.反射:通过字符串与类及类的对象的属性(方法)建立关联
class A: num = 10 print(hasattr( A ,'num')) #判断类中是否有num属性 True print(getattr(A,'num','default')) #获取类中num的属性值,没有则拿默认值 10 delattr(A,'num') #删除类中num属性 setattr(A,'tag',10) #在类中设置一个tag属性 class B: def __init__(self,name): self.name=name b = B('BOb') print(hasattr( b ,'name')) #判断对象中是否有name属性 True print(getattr(b,'name','default')) #获取对象中name的属性值,没有则拿默认值 10 delattr(b,'name') #删除对象中name属性 setattr(b,'tag',10) #在对象中设置一个tag属性 print(b.tag) class C: def fn(self): print('fn') @classmethod def func(cls): print('func') #类调对象方法,需要传入对象当做参数 fn=getattr(C,'fn') c = C() fn(c) #对象调对象方法 c = C() fn=getattr(c,'fn') fn() #类调类方法 func = getattr(C,'func') func()
十九.异常处理:
# 程序运行时的错误 # 程序中的异常处理机制: # 1.程序中的所有异常都会被处理 # 2.程序中的所有异常都需要手动处理 # 3.如果没有手动处理异常,异常会交给Python解释器处理 # -- 处理的方式就是打印异常信息,并停止接收器 # 异常信息的三部分: # 1.异常的追踪信息:提示错误位置 # 2.异常的类型:告知处理异常应该捕获什么类型 # 3.异常的内容:告知错误信息 # 处理异常的语法: ''' try: # 会出现异常的代码块 except 异常类型 as 异常别名: # 异常处理逻辑 else: # 没有出现异常会执行该分支 finally: # 无论是否出现异常都会执行该分支 ''' try: print(adsdasadsdasadsdas) except NameError as e: print('异常信息:', e) else: print('被检测的代码块正常') finally: print('异常是否出现都会执行该分支') print('end')