-
面向对象与面向过程
- 区别
- 面向过程又被称为top-down languages, 就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题
- 利用“类”和“对象”来创建各种模型来实现对真实世界的描述
- 面向过程,复杂的问题流程化,进而简单化,扩展性和维护性较差,适用于写一些简单的脚本,去做一些一次性任务。如 Linux內核,git,以及Apache HTTP Server等
- 面向对象特点
- 使程序更加容易扩展和易更改,使开发效率变的更高
- 基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容
- 适用于互联网应用,企业内部软件,游戏等
- 编程范式 特定的语法+数据结构+算法
- 区别
-
类 对一类拥有相同属性的对象的抽象、蓝图、原型、模板
- 调用类,或称为实例化,得到程序中的对象
- 在类定义阶段便会开辟内存空间,因而会产生新的名称空间,用来存放类的变量名与函数名
- python中一切皆为对象,且python3中类与类型是一个概念,类型就是类
- 对象实例
- 判断对象类型,使用
type()
函数 - 要判断class的类型,可以使用
isinstance()
函数 - 获得一个对象的所有属性和方法,可以使用
dir()
函数 - 调用
len()
函数试图获取一个对象的长度 - __dict__
- 反射
- 判断对象类型,使用
- 属性 类的特征
- 类的数据属性是所有对象共享的
- 类的函数数据是绑定给对象用的,称为绑定到对象的方法
- 方法 类的功能
- 绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self
- 构造方法 __init__ 自动给实例一些初始化参数,或执行一些其它的初始化工作
- 析构方法 __del__ 实例在内存中被删除
class Student: school = '北大' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def learn(self): print('%s is learning' % self.name) # 新增self.name def eat(self): print('%s is eating' % self.name) def sleep(self): print('%s is sleeping' % self.name) s1 = Student('周瑜', '男', 28) s2 = Student('小乔', '女', 18) s3 = Student('鲁肃', '男', 38) Student.learn(s1) Student.learn(s2) Student.learn(s3) s1.learn() # 等同于Student.learn(s1) s2.learn() # 等同于Student.learn(s2) s3.learn() # 等同于Student.learn(s3)
- 三大特性
- 封装 Encapsulation
- 使用构造方法将内容封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容
- 用双下划线开头的方式将属性设置成私有 双下划线开头的名称会自动变成_类名__xxx
- 目的是隔离复杂度
class Other(Foo): __T = 't' # 变形 _Other__T def __init__(self, name): super(Other, self).__init__(name) self.name = name self.__lname = name # 变形 self._Other__lname def __foo(self): # 变形为_Other__foo print('Other __foo') return 123 j = Other('java') print(j.name) # print(Other.__T) print(Other._Other__T) print(Other._Other__foo(j)) print(j._Other__T) print(j._Other__foo())
print(Other.__dict__)
print(j.__dict__)""" java t Other __foo 123 t Other __foo 123
{'__module__': '__main__', '_Other__T': 't', '__init__': <function Other.__init__ at 0x00000284E3B97268>, '_Other__foo': <function Other.__foo at 0x00000284E3B972F0>, '__doc__': None}
{'name': 'java', '_Other__lname': 'java'}"""
#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱 #对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做 #隔离了复杂度,同时也提升了安全性 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() a=ATM() a.withdraw()
- 继承 Inheritance
- 继承指的是类与类之间的关系,用来解决代码重用问题
- 类可以继承一个或多个父类,父类又可以成为基类或超类,新建的类称为派生类或子类
- Python单继承(Java,PHP)和多继承(C++)
- 经典类与新式类
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
4.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类 - 先抽象再继承
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
- 属性查找 先从实例中查找再去类中找,然后再去父类中找...直到最顶级的父类
>>> 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,属性的查找方式有两种,分别是:深度优先和广度优先
- 派生 子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式
- 实现原理
- python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表
- python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止
- 子类调用父类
- 父类名.父类方法() 跟继承没有关系的
- super() 依赖于继承的,并且即使没有直接继承关系,super仍然会按照mro继续往后查找
""" super() -> same as super(__class__, <first argument>) super(type) -> unbound super object super(type, obj) -> bound super object; requires isinstance(obj, type) super(type, type2) -> bound super object; requires issubclass(type2, type) Typical use to call a cooperative superclass method: class C(B): def meth(self, arg): super().meth(arg) This works for class methods too: class C(B): @classmethod def cmeth(cls, arg): super().cmeth(arg) """
class A: # A没有继承B,但是A内super会基于C.mro()继续往后找 def test(self): super().test() class B: def test(self): print('from B') class C(A, B): pass c = C() c.test() # 打印结果:from B print(C.mro()) # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
多态 Polymorphism 是一类事物的多种形态。一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现
- 多态性是指在不考虑实例类型的情况下使用实例,多态性分为静态多态性和动态多态性
- 增加了程序的灵活性和可扩展性
- 静态语言和动态语言
- 鸭子类型与file-like object
# 序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系 # str,list,tuple都是序列类型 s = str('hello') l = list([1, 2, 3]) t = tuple((4, 5, 6)) # 我们可以在不考虑三者类型的前提下使用s,l,t s.__len__() l.__len__() t.__len__() len(s) len(l) len(t)
- 封装 Encapsulation
- 组合 在一个类中以另外一个类的对象作为数据属性
- 当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
class Classes(BaseModel): def __init__(self, title): self.sn = utils.sn() self.title = title self.__students__ = [] self.__duties__ = [] def add_duty(self, duty): """ 执勤记录 :param duty: :return: """ self.__duties__.append(duty) def add_student(self, student_sn): """ 添加学生 :param student_sn: :return: """ self.__students__.append(student_sn)
- 当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
- 归一化
- 归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样
- 降低了使用者的使用难度
- 使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合
- python中没有interface的关键字,借助第三方模块zope.interface
- 抽象类
- 只能被继承,不能被实例化
- 抽象类的本质还是类,指的是一组类的相似性,包括数据属性和函数属性,而接口只强调函数属性的相似性
- 抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
import abc class Service(metaclass=abc.ABCMeta): """ 定义服务接口 """ @classmethod @abc.abstractmethod def run(cls): pass @classmethod @abc.abstractmethod def interactive(cls, user=None): pass
- 特性 property 一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
- 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
class Foo: def __init__(self,val): self.__NAME=val #将所有的数据属性都隐藏起来 @property def name(self): return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置) @name.setter def name(self,value): if not isinstance(value,str): #在设定值之前进行类型检查 raise TypeError('%s must be str' %value) self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter def name(self): print("deleted") raise TypeError('Can not delete') f=Foo('bar') print(f.name) # f.name=10 #抛出异常'TypeError: 10 must be str' del f.name #抛出异常'TypeError: Can not delete'
- 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
- 绑定与非绑定方法
- 绑定到对象的方法(普通方法:self),绑定到类的方法(@classmethod:cls)
- @staticmethod() 不与类或对象绑定,类和对象都可以调用.就是一个普通工具
import settings class MySQL: def __init__(self,host,port): self.host=host self.port=port @classmethod def from_conf(cls): print(cls) return cls(settings.HOST,settings.PORT) print(MySQL.from_conf) # <bound method MySQL.from_conf of <class '__main__.MySQL'>> conn=MySQL.from_conf() # <class '__main__.MySQL'> conn.from_conf() # 对象也可以调用,但是默认传的第一个参数仍然是类
- 反射 映射到对象的成员属性
- hasattr(obj,key) 是否存在 obj.__dict__[key]
- getattr(obj,key,default) 获取或返回默认
- setattr(obj,key,value) 设置 添加修改
- delattr(obj,key) 删除 del obj.key
- 内置方法
- isinstance,isubclass(sub, super)检查sub类是否是 super 类的派生类
- item系列 __getitem__,__setitem__,__delitem__以字典的形式访问成员属性 主要是操作obj.__dict__[key]
- __str__ toString,__del__ 析构方法,回收资源
- __call__ 对象后面加括号,触发执行。 构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
- 其他
- 元类
- 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}
- 将类当作一个对象去使用:赋值给一个变量,作为函数参数进行传递,作为函数的返回值,动态地创建类
- 元类是类的类,是类的模板,type 是一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
# 方式1:手动模拟class创建类的过程 # 类名 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 0x000001BEC710E510>, 'talk': <function talk at 0x000001BEC710E598>} """ # 方式2:实例化type得到对象Foo,即我们用class定义的类Foo Foo = type(class_name, class_bases, class_dic) print(Foo) print(type(Foo)) print(isinstance(Foo, type)) obj = Foo('鬼谷子',68) obj.talk() """ <class '__main__.Chinese'> <class 'type'> True 鬼谷子 is talking """
- 自定义元类的创建 metaclass=MyMeta __init__
- 自定义元类的实例化 ___call__
- 空对象obj __new__(self)
- 初始化obj __init__(obj,*args,**kwargs)
- 返回obj
- exec
- 面向对象
- 开发规范
- 设计
- 编程
- 测试
- 维护
- 领域建模
- 开发规范