面相对象初识
面向过程编程
面向过程编程即流程式编程,根据问题进行分析,抽象出解决问题所需要的步骤,并按步骤逐步进行函数调用解决问题。
函数式编程
函数式编程是一种编程范式,即给定输入值,经过函数处理后给出返回值,即为函数式编程。比起指令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。
面向对象编程
面向对象编程是种具有对象概念的程序编程典范,同时也是一种程序开发的抽象方针。它可能包含数据、属性、代码与方法。
类与对象
类
1 2 3
| class Foo: "description of class" pass
|
对象
1 2 3 4 5 6
| class Foo: "description of class" def __init__(self, x): self.x = x
foo = Foo()
|
属性与方法
概念
在Python中 , 我们将静态属性 就称为属性
, 将动态属性就称为方法
, 以变量表示属性
, 以函数表示方法
。
调用
类/实例调用属性/方法的方式为:类名/实例名 . 属性名/方法名
特殊的类属性
属性名 |
说明 |
_dict_ |
查看类/实例成员, 返回字典 |
_name_ |
查看类名 |
_doc_ |
查看类的描述信息, 即类的注释 |
_base_ |
查看当前类的第一个父类 |
_bases_ |
查看当前类的所有父类, 返回元组 |
_module_ |
查看当前类所在模块 |
_class_ |
查看当前实例的父类 |
构造方法 & 析构方法
命名空间
命名空间它表示着一个标识符的可见范围,在定义类的时候会产生类的命名空间,同样在类实例化对象之后,对象也会对应产生命名空间。当调用类/实例的属性/方法时,Python解释器首先会到该实例的命名空间中去找对应属性/方法,如果没有找到则继续向上去类的命名空间去找,如果都没有找到对应调用的属性/方法,则抛出异常。
类/实例中的属性/方法绑定关系
- Python作为一种动态语言,其所有的赋值机制都是通过动态绑定实现。
- 类中的属性/方法可供其创建的所有实例使用
- 实例中的属性/方法只适用于实例本身
对象交互&类的组合
1 2 3 4 5 6 7 8 9 10 11 12
| class Foo: def __init__(self, x): self.x = x def interactive(self, other): print("【{}】 interactive 【{}】".format(self.x, other.x))
obj_a = Foo('obj_a') obj_b = Foo('obj_b') obj_a.interactive(obj_b)
【obj_a】 interactive 【obj_b】
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Person: def __init__(self, name): self.name = name
class Worker: def __init__(self, person): self.person = person
person = Worker(Person('Yang'))
class Person: def __init__(self, name): self.name = name
class Worker: def __init__(self, person): self.person = Person('Yang')
worker = Worker()
|
https://docs.python.org/zh-cn/3.8/reference/datamodel.html#metaclasses
概念及作用
- 概念
一种用于创建类的类。
类定义包含类名、类字典和基类列表。
元类负责接受上述三个参数并创建相应的类。
大部分面向对象的编程语言都会提供一个默认实现。
Python 的特别之处在于可以创建自定义元类。
大部分用户永远不需要这个工具,但当需要出现时,元类可提供强大而优雅的解决方案。
- 作用
它们已被用于记录属性访问日志、添加线程安全性、跟踪对象创建、实现单例,以及其他许多任务。
元类的原理及定义类的执行过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 1、解析 MRO 条目: 如果在类定义中出现的基类不是 type 的实例,则使用 __mro_entries__ 方法对其进行搜索,当找到结果时,它会以原始基类元组做参数进行调用。
2、确定适当的元类: 在类定义时确定元类的流程: ①如果没有基类且没有显式指定元类,则使用 type(); ②如果给出一个显式元类且不是 type() 的实例,则其会被直接用作元类; ③如果给出一个 type() 的实例作为显式元类,或是定义了基类,则使用最近派生的元类。
3、准备类命名空间: 在类定义之时确定元类的命名空间原则: ①如果元类具有 __prepare__ 属性,它会以 namespace = metaclass.__prepare__(name, bases, **kwds) 的形式被调用(其中如果有任何额外的关键字参数,则应来自类定义)。 __prepare__ 方法的实现应当为 classmethod()。 ②如果元类没有 __prepare__ 属性,则类命名空间将初始化为一个空的有序映射。
4、执行类主体: 类主体会以(类似于) exec(body, globals(), namespace) 的形式被执行。普通调用与 exec() 的关键区别在于当类定义发生于函数内部时,词法作用域允许类主体(包括任何方法)引用来自当前和外部作用域的名称。 但是,即使当类定义发生于函数内部时,在类内部定义的方法仍然无法看到在类作用域层次上定义的名称。类变量必须通过实例的第一个形参或类方法来访问,或者是通过隐式词法作用域的 __class__ 引用。
5、创建类对象: 一旦执行类主体完成填充类命名空间,将通过调用 metaclass(name, bases, namespace, **kwds) 创建类对象(此处的附加关键字参数与传入 __prepare__ 的相同)。
如果类主体中有任何方法引用了 __class__ 或 super,这个类对象会通过零参数形式的 super(). __class__ 所引用,这是由编译器所创建的隐式闭包引用。这使用零参数形式的 super() 能够正确标识正在基于词法作用域来定义的类,而被用于进行当前调用的类或实例则是基于传递给方法的第一个参数来标识的。
当使用默认的元类 type 或者任何最终会调用 type.__new__ 的元类时,以下额外的自定义步骤将在创建类对象之后被发起调用: ①首先,type.__new__ 将收集类命名空间中所有定义了 __set_name__() 方法的描述器; ②接下来,所有这些 __set_name__ 方法将使用所定义的类和特定描述器所赋的名称进行调用; ③最后,将在新类根据方法解析顺序所确定的直接父类上调用 __init_subclass__() 钩子。
在类对象创建之后,它会被传给包含在类定义中的类装饰器(如果有的话),得到的对象将作为已定义的类绑定到局部命名空间。
当通过 type.__new__ 创建一个新类时,提供以作为命名空间形参的对象会被复制到一个新的有序映射并丢弃原对象。这个新副本包装于一个只读代理中,后者则成为类对象的 __dict__ 属性。
|
单例模式的四种方式
1 2 3 4 5 6 7
| class Singleton(object): """单例模式""" _instance = None def __new__(cls, *args, **kw): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls, *args, **kw) return cls._instance
|
1 2 3 4 5 6 7 8 9 10
|
class My_Singleton(object): def foo(self): pass my_singleton = My_Singleton()
from mysingleton import my_singleton my_singleton.foo()
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| from functools import wraps
def singleton(cls): instances = {} @wraps(cls) def getinstance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return getinstance @singleton class MyClass(object): pass
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class SingletonType(object): """docstring for Singleton""" def __init__(self, *args,**kwargs): super(SingletonType, self).__init__(*args,**kwargs) def __call__(cls,*args,**kwargs): obj = cls.__new__(cls,*args,**kwargs) cls.__init__(obj,*args,**kwargs) return obj class Foo(metaclass=SingletonType): """docstring for Foo""" def __init__(self, name): self.name = name def __new__(cls,*args,**kwargs): return object.__new__(cls) obj = Foo('xxx')
|