Python 面向对象

常见的三种编程范式

  • 函数式编程
  • 面向过程编程(函数)
  • 面向对象编程(类)

函数式编程:函数可以作为参数传递、修改,或作为返回值,函数内不修改外部变量的状态。

面向过程编程 (函数):根据操作数据的语句块来实现功能。

面向对象编程 (OOP-Object Oriented Programming):把数据和功能结合起来,用称为对象的东西包裹起来组织程序的方法。

面向对象

定义

对象:通过类定义的数据结构实例。

对象包括两个数据成员(类变量和实例变量)和方法。

python一切皆对象,类是对象,实例也是对象。

优点

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。

继承完全可以理解成类之间的类型和子类型关系。可以节省很多的代码,不需要写,直接使用,衍生出不同的子类,大部分代码一样,部分代码不一样。

面向过程和面向对象

面向过程是一件事"该怎么做",着重于做什么。

面向对象是一件事"该让谁来做",着重于谁去做。

实例

• 实例:具体的某个事物, 某个类型实实在在的一个例子。

• 实例化:创建一个类的实例,类的具体对象。

• 类是一种生产实例的工厂。

属性

• 对象的描述信息,一种状态 -> 变量。

• 车的属性: 品牌、型号、颜色、形状、尺寸。

• 人的属性:身高、体重、姓名、性别、爱好。

方法

• 对象的行为  -> 类中定义的函数

• 车的方法: 驾驶、停车、漂移、越野、运输。

• 人的方法:吃饭、睡觉、运动、打扮、娱乐。

类 (基类、子类)

类(Class): 用来描述具有相同的属性和方法(能做的事)的对象的集合。

它定义了该集合中每个对象所共有的属性和方法。

对象是类的实例。

类的基本特点

1、封装(Encapsulation)

• 在类中对数据的赋值、内部调用对外部用户是透明的。

• 把一些功能的实现细节不对外暴露。

2、继承(Inheritance)

• 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。

• 为实现代码的重用, 一个类可以派生出子类。

• 继承也允许把一个派生类的对象作为一个基类对象对待。

3、多态(Polymorphism)

• 接口重用。

• 一个接口,多种实现(重写)。

类的定义

类名的规范

• 一般首字母大写(大驼峰)

• Person, GoodsInfo

函数的命名

• 由小写字母和下划线组成

• add、book_name

类的定义方式(关键字:class)

• python2 => 经典类和新式类

• python3 => 新式类

class Bus12():
    pass
class Bus12(object):
    pass

__init__:实例初始化

• 这个名称的开始和结尾都是双下划线。

• 这个方法可以用来对你的对象做一些你希望的初始化任务。

• __init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,它在类的一个对象被建立
后,自动运行。

__new__:创建一个实例

• 这个名称的开始和结尾都是双下划线。

• 这个方法用来创建一个实例,一般情况下都不会重写。

注意:__new__必须产生和class类型一致的instance, 否则__init__是不会执行的。

执行顺序:先执行__new__,再执行__init__。

类变量与实例变量

类的变量: 由一个类的所有对象(实例)共享使用。

实例的变量: 由类的每个对象/实例拥有。

类和实例都有自己的存储空间。

所有的这些对象都有命名空间,而继承就是由下而上,从左到右原则搜索此树,来寻找属性名称所出现的最低的地方。

可以自由地给类、实例添加或删除属性。

当实例查找属性时,先找自己本身,没有找到就去类上查找,没找到再抛出异常。

类-self

类的实例方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称。

在调用这个方法的时候你不为这个参数赋值,Python会提供这个值。

这个特别的变量指对象本身,按照惯例它的名称是self。

self代表类的实例,而非类,self不必非写成self,self可以不写。

在类的继承时,self代表哪个类,表示的是实例化的类。

类的继承

定义

• 代码:父类Parent/子类Child。

• 子类有__ini__: 执行自己的初始化函数。

• 子类没有__init__: 在子类实例化的时候会自动执行父类的构造函数。

优点

如果需要给Pig/Dog同时增加新的功能时,只需要在Animal中添加即可。

如果父类方法的功能不能满足需求,可以在子类里重写父类的方法。

多态

定义

多态(Polymorphism):“多种状态”,在面向对象语言中,接口的多种不同
实现方式即为多态。

多态其实是一种行为的封装,只需知道所操纵对象能够做的事情(接口)即可。

多态以继承和重写父类方法为前提,多态是调用方法的技巧,不会影响到类的内部设计。

Python是动态语言,动态语言和静态语言最大的差别:动态语言调用实例方法,不检查类型,只要方法存在,参数正确,就可以调用。

优点

1、增加了程序的灵活性、可扩展性。

2、实现接口重用。

多态:同一种事物的多种形态,例如:动物分为人类,猪类等。

多态性:一种调用方式,不同的执行效果。

经典类与新式类

在Python 2.x及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位
置),都属于“新式类”。

不由任意内置类型派生出的类,则称之为“经典类”。

Python 3.x之后,所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”。

经典类与新式类继承原理

MRO(Method Resolution Order):方法解析顺序。Python 3.x之后,采用c3算法。

MRO是在Python类的多重继承中,当定义了多个同名的方法/属性时,为避免产生歧义,保证用户找到正确的对象所实现的一种算法。

对于定义的每一个类,Python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一
个简单的所有基类的线性顺序列表。

C3算法

合并所有父类的MRO列表并遵循如下三条准则:

• 子类会先于父类被检查。

• 多个父类会根据它们在列表中的顺序被检查。

• 如果对下一个类存在两个合法的选择,选择第一个父类。

静态方法、类方法、实例方法

定义

实例方法不能通过类名调用,但是静态方法和类方法可以通过类名调用。

实例方法:可以通过self访问实例属性。

类方法:可以通过cls访问类属性(希望取的值不受实例影响时使用)

静态方法:不可以访问,通过传值的方式。

属性包装(@propert)

把函数包装成属性,使用的时候用对象名.属性名。

Person类中有一个属性为age,控制age的范围只能在0~150之间。

应用

property广泛应用在类的定义中,可以让调用者写出简短的代码,同时对参数进行必要的检
查。

Python类中的下划线

标识符是用来标识某种对象的名称,以下划线开头的标识符是有特殊意义的。

在命名标识符时,需要遵循一定规则,标识符的第一个字符必须是字母(大小写均可),或者是一个下划线("_")。

以单下划线开头的(_foo)

类:这类成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量。

模块:如果你写了代码“from <模块/包名> import *”,那么以“_”开头的模块和包都不会被导入,除非模块或包中的“__all__”列表显式地包含了模块和包。

Python文档:以下划线“_”为前缀的名称(如_spam)应该被视为API中非公开的部分(不管是函数、方法还是数据成员)。此时,应该将它们看作是一种实现细节,在修改它们时无需对外部通知。

以双下划线开头的(__foo)

类:只有类对象自己能访问,连子类对象也不能访问到这个数据。强行访问“对象名._类名__xxx“这样的方式。

模块:不能用“from xxx import *“导入包/模块。

名称(具体为一个方法名)前双下划线(“__“)的用法并不是一种惯例,对解释器来说它有特定
的意义,为了避免与子类定义的名称冲突。

Python文档:“__spam”这种形式(至少两个前导下划线,最多一个后续下划线)的任何标识符将会被“_classname__spam”这种形式原文取代,在这里“classname”是去掉前导下划线的当前类名。

以双下划线开头和结尾的( __foo__ )

代表Python中特殊方法专用的标识。其实,这只是一种惯例,对Python系统来说,这将确保不会
与用户自定义的名称冲突。例如__init__()代表类的构造函数。

常用魔术方法和属性

构造函数(__new__/__init__)

• __new__:创建实例

• __init__:初始化实例

析构函数(__del__)

在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作, 如关闭一些数据库连接,关闭打开的临时文件。

调用方法(__call__)

把类实例化后的对象当做函数来调用的时候自动被调用。

查看类属性和方法

• dir(Person):了解Person类里的变量和方法。

• Person.__dict__ :可以区别变量和方法。

内置属性及其功能

• __dict__:类的属性(包含一个字典,由类的数据属性组成)。

• __doc__:类的文档字符串。

• __name__:类名。

• __module__:类定义所在的模块。

• __bases__:类的所有父类构成元素。

Python元类

对象在实例化的过程中,会调用__init__和__new__方法创建新对象, 一个类本身又是另一个类的实例,用于创建类的类就是元类(Metaclass)。

type创建类

type是Python的内建元类。

语法:type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

创建类:MyClass = type('MyClass', (), {})

函数type实际上是一个元类, type就是Python在背后用来创建所有类的元类(类工厂)如:1 -> int -> type。

编写元类

只需要声明一个继承自type的类。元类的行为继承自type,因此type的子类都可以作为元类。

元类的主要目的就是为了当创建类时能够自动地改变类:

• 拦截类的创建。

• 修改类,返回修改之后的类。

指定元类

1、默认元类为type:

class Foo(Bar): __metaclass__ = something

class Foo(Bar, metaclass=something):pass

2、Python会在类的定义(父类)中寻找__metaclass__属性,找到后,Python就会用它来创建类
Foo,如果没有找到,就会用内建的type来创建这个类。

3、 __metaclass__中放置可以创建一个类的东西(元类)。

抽象基类

python中并没有提供抽象类与抽象方法,但是提供了内置模块abc(abstract base class)来模拟
实现抽象类。

ABC,Abstract Base Class(抽象基类),主要定义了基本类和最基本的抽象方法,可以为子类
定义共有的API,不需要具体实现。

抽象基类提供了逻辑和实现解耦的能力,即在不同的模块中通过抽象基类来调用。

ABC类实际上是一个元类。

Python自省

什么是自省

检查某些事物以确定它是什么、它知道什么以及它能做什么。

4个方法

• getattr(obj,'name'): 获取成员,根据字符串去获取obj对象里对应方法的内存地址。

• hasattr(obj,'name'): 检查是否含有成员,判断一个对象obj里是否有对应的name_str字符串。

• setattr(obj,'age', 20): 设置成员。

• delattr(obj,'name'): 删除成员。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韩未零

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值