一、什么是对象?
- 对象是内存中专门用来存储数据的一块区域。
- 对象中可以存放各种数据(比如:数字、布尔值、代码)
- 对象由三部分组成:
1.对象的标识(id)
2.对象的类型(type)
3.对象的值(value)
二、面向对象和面向过程
面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。
而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
面向对象有三大支柱:封装、继承和多态
三、面向对象技术简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 方法:类中定义的函数。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。
Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
对象可以包含任意数量和类型的数据。
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
四、类(class)
- 我们目前所学习的对象都是Python内置的对象
- 但是内置对象并不能满足所有的需求,所以我们在开发中经常需要自定义一些对象
- 类,简单理解它就相当于一个图纸。在程序中我们需要根据类来创建对象
- 类就是对象的图纸!
- 我们也称对象是类的实例(instance)
- 如果多个对象是通过一个类创建的,我们称这些对象是一类对象
- 像 int() float() bool() str() list() dict() .... 这些都是类
- a = int(10) # 创建一个int类的实例 等价于 a = 10
- 我们自定义的类都需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名
- 类也是一个对象!
- 类就是一个用来创建对象的对象!
- 类是type类型的对象,定义类实际上就是定义了一个type类型的对象
五、类定义
语法格式如下:
class ClassName:
<statement-1>
.
.
.
<statement-N>
类的基本结构:
class 类名([父类]) :
公共的属性...
# 对象的初始化方法
def __init__(self,...):
...
# 其他的方法
def method_1(self,...):
...
def method_2(self,...):
...
...
六、创建和使用对象
当我们定义好一个类之后,可以通过下面的方式来创建对象并给对象发消息。
创建类:
class Student(object):
# __init__是一个特殊方法用于在创建对象时进行初始化操作
# 通过这个方法我们可以为学生对象绑定name和age两个属性
def __init__(self, name, age):
self.name = name
self.age = age
def study(self, course_name):
print('%s正在学习%s.' % (self.name, course_name))
# PEP 8要求标识符的名字用全小写多个单词用下划线连接
# 但是部分程序员和公司更倾向于使用驼峰命名法(驼峰标识)
def watch_movie(self):
if self.age < 18:
print('%s只能观看《熊出没》.' % self.name)
else:
print('%s正在观看岛国爱情大电影.' % self.name)
创建和使用对象:
def main():
# 创建学生对象并指定姓名和年龄
stu1 = Student('骆昊', 38)
# 给对象发study消息
stu1.study('Python程序设计')
# 给对象发watch_av消息
stu1.watch_movie()
stu2 = Student('王大锤', 15)
stu2.study('思想品德')
stu2.watch_movie()
if __name__ == '__main__':
main()
七、封装
封装是面向对象的三大特性之一
封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法
如何隐藏一个对象中的属性?
- 将对象的属性名,修改为一个外部不知道的名字
如何获取(修改)对象中的属性?
- 需要提供一个getter和setter方法使外部可以访问到属性
- getter 获取对象中的指定属性(get_属性名)
- setter 用来设置对象的指定属性(set_属性名)
使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性
1.隐藏了属性名,使调用者无法随意的修改对象中的属性
2.增加了getter和setter方法,很好的控制的属性是否是只读的
如果希望属性是只读的,则可以直接去掉setter方法
如果希望属性不能被外部访问,则可以直接去掉getter方法
3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
4.使用getter方法获取属性,使用setter方法设置属性
可以在读取属性和修改属性的同时做一些其他的处理
5.使用getter方法可以表示一些计算的属性
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
,在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。双下划线的一般不使用。
有些时候,你会看到以一个下划线开头的实例变量名,比如_name
,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
class Person:
def __init__(self,name,age):
self._name = name
self._age = age
# property装饰器,用来将一个get方法,转换为对象的属性
# 添加为property装饰器以后,我们就可以像调用属性一样使用get方法
# 使用property装饰的方法,必须和属性名是一样的
@property
def name(self):
print('get方法执行了~~~')
return self._name
# setter方法的装饰器:@属性名.setter
@name.setter
def name(self , name):
print('setter方法调用了')
self._name = name
@property
def age(self):
return self._age
@age.setter
def age(self , age):
self._age = age
p = Person('猪八戒',18)
p.name = '孙悟空'
p.age = 28
print(p.name,p.age)
八、继承
语法:
class DerivedClassName(BaseClassName1):
<statement-1>
.
.
.
<statement-N>
有一个类,能够实现我们需要的大部分功能,但是不能实现全部功能
如何能让这个类来实现全部的功能呢?
① 直接修改这个类,在这个类中添加我们需要的功能
- 修改起来会比较麻烦,并且会违反OCP原则
② 直接创建一个新的类
- 创建一个新的类比较麻烦,并且需要大量的进行复制粘贴,会出现大量的重复性代码
③ 直接从Animal类中来继承它的属性和方法
- 继承是面向对象三大特性之一
- 通过继承我们可以使一个类获取到其他类中的属性和方法
- 在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类、super)
子类(衍生类)可以直接继承父类中的所有的属性和方法
通过继承可以直接让子类获取到父类的方法或属性,避免编写重复性的代码,并且也符合OCP原则
所以我们经常需要通过继承来对一个类进行扩展
#!/usr/bin/python3
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
#单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
s = student('ken',10,60,3)
s.speak()
结果:
ken 说: 我 10 岁了,我在读 3 年级
九、多态
# 定义两个类
class A:
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class B:
def __init__(self,name):
self._name = name
def __len__(self):
return 10
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class C:
pass
a = A('孙悟空')
b = B('猪八戒')
c = C()