概论
面向对象程序编程(object-oriented programming OOP)是一种程序设计规范。也是一种程序开发的方法。
- 对象是什么呢?,对象是类的实例;那类又什么什么?类是创建对象的模板,所以简单来说,面向对象程序设计就是使用模板创建一个个的实例,而这些实例就叫做对象。
类(也就是一个模板),之所以叫做模板是因为通用,适配,所以一个类可以创建多个对象,每个对象都是类-类型的一个变量;另外,创建对象的这个一个过程叫做类的实例化,就是将一个通用的类明确出一个对象。就比如人是一个类,那么男人和女人是其中的两个对象,同时也可以叫做子类,对应单个的实际的一个人就是对象。
面向堆成程序设计将对象作为程序的基本单元,将程序和数据封装在对象中,以提高软件的重用性,灵活性和扩展性
面向对象中的基本概念
- 类:class:类是定义一件事物的抽象特点。通常来说,类定义了事物的属性和它可以做到的行为,例如,鸟有翅膀是属性,鸟类会飞是行为。类可以为程序提供模板和结构,一个类中可以有成员函数和成员变量。在面向对象的术语中,成员函数被称为方法,成员变量被称为属性。
- 对象:object :是类的实例,例如:麻雀是鸟类的一个实例,就是一个对象。当一个实例被实例化时,它的属性就具有的具体的值,比如麻雀的翅膀有颜色,有大小,羽毛颜色等等,每个类可以有若干个被实例化的对象。在操作系统中,系统个对象分配内存空间,但是不会给类分配内存空间。、
- 继承: inheritance:继承是指通过一个已有的类(称为父类),在这个类的基础上定义另一个类(称为子类),子类共享父类开发的属性和方法。使用子类实例化的对象,除了是一个子类的一个实例,同时还是其子类所属的父类的一个实例。比如,人类,女人类,小红,那么人类:父类,女人类: 是子类,小红是通过女人类实例化出来的一个实例。
- 封装性 Encapsulation:封装性是指类在定义的时候可以将不能或者不需要其他类知道的成员定义成私有成员,而只是公开其他类需要知道和使用的成员,,以达到信息隐蔽和简化的作用。
- 多态性:Ploymorphism:是指同一个方法作用在不同的对象上时,可以有不同的解释,产生不同的执行结果。在具体实现方式上,多态性是允许开发者将父对象的变量设置为对子对象的引用,赋值之后,父对象变量就可以根据当前的赋值,给它的子对象的特性以不同的方式运作。
与面向对象编程(OOP)对应的是面向对象设计(OOD),OOD主要以UML为代表的标准建模语言。
类与对象
- 在定义类中,属性属于成员变量,可以对其进行赋值;类中定义的函数称为成员函数,并且该和成员函数必须带参数self,这是对本身的引用,在成员函数体中可以引用self参数获得对象的信息。但是在实例化一个对象后,直接使用该对象进行调用成员函数的时候不需要传入self参数。
- python类中定义的成员变量,即可以通过类名访问,也可以通过实例化出来的对象进行访问。故,类和所有该类的对象共享同一个成员变量。
- Python中的类构造函数用__init__命名,构造函数是一种特殊的类成员方法,主要用来在创建对象时初始化对象,即为对象成员变量赋初始值。
可以看到是先调用了构造函数,然后再去调用对象的成员函数的。因为构造函数是背解释器自动调用的。class MyClass(object): message = "Hello ,Developer" def show(self): print(self.message) def __init__(self): print("Constructor is called") # print(MyClass.message) # MyClass.message = "Good morning!!" # print(MyClass.message) inst = MyClass() inst.show() 结果是: Constructor is called Hello ,Developer
(注意:构造函数中不能有返回值,会报异常)
往构造函数中传递参数可以通过:默认,位置参数,关键字参数等方式传递。
只能定义一个构造函数,可以通过为命令参数提供默认值的方式达到多种方式构造对象的目的。构造:顾名思义就是在使用之前使用默认的值,或者自己设定的值将该对象建造好,构造一个基本的模型。def __init__(self, name="unset", color="red"): print("Constructor is called name = %s , color = %s " % (name, color)) inst1 = MyClass() inst1.show() inst2 = MyClass("David") inst2.show() inst3= MyClass("lisa", "Yellow") inst4 = MyClass(color="Green") inst4.show() 结果: Constructor is called name = unset , color = red Hello ,Developer Constructor is called name = David , color = red Hello ,Developer Constructor is called name = lisa , color = Yellow Constructor is called name = unset , color = Green Hello ,Developer
- 与构造函数相反的析构函数
在一个类中,析构函数是在销毁或者释放对象的时候才会被调用,用来做善后的操作。是一种显示销毁对象的方法。
在类中定义一个名为__del__的,没有返回值和参数的函数# -*- coding: utf-8 -*- # @Time : 2018/11/18 10:21 # @Author : 11382 # @Email : [email protected] # @File : object_test.py class MyClass(object): message = "Hello ,Developer" def show(self): print(self.message) def __init__(self, name="unset", color="red"): print("Constructor is called name = %s , color = %s " % (name, color)) def __del__(self): print("Destructor is called!!") # print(MyClass.message) # MyClass.message = "Good morning!!" # print(MyClass.message) inst1 = MyClass() inst1.show() inst2 = MyClass("David") inst2.show() inst3 = MyClass("lisa", "Yellow") inst4 = MyClass(color="Green") inst4.show() 结果是: Constructor is called name = unset , color = red Hello ,Developer Constructor is called name = David , color = red Hello ,Developer Constructor is called name = lisa , color = Yellow Constructor is called name = unset , color = Green Hello ,Developer Destructor is called!! Destructor is called!! Destructor is called!! Destructor is called!!
可见是生成了四个对象,然后显示销毁了四次,所有del也被调用了四次。
-
实例成员变量
如何要定义属于每个对象自己的实例成员变量?
在构造函数中定义self引用中的变量,这样的成员变量在Python中叫做实例成员变量,就是实例化出来的对象的自己的变量,修改后不会对其他实例成员变量有影响。
要注意区分类成员变量:因为类中的成员变量是共享,所以一个对象修改了类成员变量中的值,那么其他对象调用的时候也会被修改。类成员变量是在类成员函数的外围定义的,而实例成员变量是在构造函数内部定义的。 -
静态函数和类函数
类成员函数均匀实例绑定,所以只能通过对象访问,但不能通过类名访问;
python中支持两个基于类名访问的成员函数: 静态函数和类函数
不同点在于:类函数有一个隐性参数cls,可以用来获取类信息,静态函数没有该参数,类函数使用装饰器@classmethod
静态函数使用装饰器@staticmethod定义class MyClass(object): message = "Hello ,Developer" def show(self): print(self.message) print("Here is %s in %s!!" % (self.name, self.color)) @staticmethod def printMessage(): print("printMessage is called in static method") print(MyClass.message) @classmethod def createObject(cls, name, color): print("object will be created: %s (%s, %s)" % (cls.__name__, name, color)) return cls(name, color) def __init__(self, name="unset", color="red"): print("Constructor is called name = %s , color = %s " % (name, color)) self.name = name self.color = color def __del__(self): # print("Destructor is called!!") print("Destructor is called for %s " % self.name) MyClass.printMessage() inst = MyClass.createObject("Toby", "red") print(inst.message) del inst 结果是: printMessage is called in static method Hello ,Developer object will be created: MyClass (Toby, red) Constructor is called name = Toby , color = red Hello ,Developer Destructor is called for Toby
类方法的第一个参数必须是cls,在createObj()中可以通过隐性参数cls替代类名本身。
-
私有成员:封装性的一个特点。python使用指定变量名格式的方法来定义私有成员
即:所有以双划线__开始的命名的成员都为私有成员
例如:在一个类中的构造函数中将成员设置为私有成员,则不影响在类本身中使用该变量,但是在类以外的地方就无法使用。会报AtttibuteError异常
继承
- Python的类在定义时候可以通过在小括号中指定基类,就是指定父类,类之间的继承是面向对象设计的重要方法,通过继承可以达到简化代码设计和优化设计模式的目的。
- 子类除了具有自己定义的特性,还能从父类中继承非私有的特性。
- 在子类成员函数中使用super关键字可以访问父类成员,其引用方法是:spuer(SubClassName, self).方法名()
在子类的析构函数中调用积累的析构函数是一种最佳实践,不这样做可能会导致父类资源不能如期被释放。