一.面向对象概述
面向对象是按人们认识客观世界的系统思维方式,把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
1.类
具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象,类实际上就是一种数据类型。类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。简而言之,类就是对象的灵魂。
# 类的定义,python开发规范PEP8
# 驼峰命名法: StudentCount
class People:
# 属性,一般是名词
# 类属性
country = 'china'
city = 'xian'
# 1). __init__叫构造方法,和普通的方法不通,会自动执行(在实例化对象的时候)
# 2). self是什么?其实就是实例化的对象.
# 3). 封装
def __init__(self, name, age):
print('正在执行构造方法.....')
print('self:', self)
# 实例属性
self.name = name # self.name就是将对象和属性绑定在一起的过程
self.age = age
# 方法,一般是动词
def coding(self):
print('%s正在编程中......' % (self.name))
2.对象
对象的含义是指具体的某一个事物,即在现实生活中能够看得见摸得着的事物。在面向对象程序设计中,对象所指的是计算机系统中的某一个成分。在面向对象程序设计中,对象包含两个含义,其中一个是数据,另外一个是动作。对象则是数据和动作的结合体。对象不仅能够进行操作,同时还能够及时记录下操作结果。
对象是实际存在的类,也可以说是实例化的类
实例化是指在面向对象的编程中,把用类创建对象的过程称为实例化。是将一个抽象的概念类,具体到该类实物的过程。实例化过程中一般由类名 对象名 = 类名(参数1,参数2…参数n)构成
# 对象object(实例化对象)
p1 = People()
print('类People:',People)
print('对象p1:',p1)
print(p1.city)
print(p1.country)
p1.coding()
类与对象的关系就如同装修图纸和装修的屋子:
二.面向对象特性
1.封装
封装”就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体(即类);封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,一特定的访问权限来使用类的成员。
所以,在使用面向对象的封装特性时,需要:
1). 将内容封装到某处
2). 从某处调用被封装的内容
1). 通过对象直接调用被封装的内容: 对象.属性名
2). 通过self间接调用被封装的内容: self.属性名
3). 通过self间接调用被封装的内容: self.方法名()
# 类的定义,python开发规范PEP8
# 驼峰命名法: StudentCount
class People:
# 属性,一般是名词
# 类属性
country = 'china'
city = 'xian'
# 1). __init__叫构造方法,和普通的方法不通,会自动执行(在实例化对象的时候)
# 2). self是什么?其实就是实例化的对象.
# 3). 封装
def __init__(self, name, age):
print('正在执行构造方法.....')
print('self:', self)
# 实例属性
self.name = name # self.name就是将对象和属性绑定在一起的过程
self.age = age
# 方法,一般是动词
def coding(self):
print('%s正在编程中......' % (self.name))
注:构造方法__init__与其他普通方法不同的地方在于,当一个对象被创建后,会立即调用构造方法。自动执行构造方法里面的内容
对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象中,然后通过对象直接或者self间接获取被封装的内容
2.继承
继承描述的是事物之间的所属关系,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类、扩展类(Subclass),而被继承的class称为基类、父类或超类(Baseclass、Superclass)。
继承特性
- 子类在继承的时候,在定义类时,小括号()中为父类的名字
- 父类的属性、方法,会被继承给子类。 举例如下: 如果子类没有定义__init__方法,父类有,那
么在子类继承父类的时候这个方法就被继承了,所以只要创建对象,就默认执行了那个继承过来的__init__方法 - 重写父类方法: 就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
示例:
# 父类(基类)
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def get_grade(self):
if 90 <= self.score <= 100:
return 'A'
else:
return 'B'
def learning(self):
print('每天早上8:00-18:00开始学习')
# 子类ComputerStudent继承Student父类
class ComputerStudent(Student):
def get_grade(self):
if 70 <= self.score <= 100:
return 'A'
else:
return 'B'
def learning(self):
# 3). 调用父类的方法:找到ComputerStudent的父类,执行父类的learning方法
super(ComputerStudent, self).learning()
print(' - 操作系统')
print(' - 计算机网络')
print(' - 计算机组成')
print(' - 数据结构与算法')
# 子类MathStudent继承Student父类
class MathStudent(Student):
def learning(self):
# 3).调用父类的方法:找到MathStudent的父类,执行父类的learning方法
super(MathStudent, self).learning()
print(' - 高等数学')
print(' - 线性代数')
# s = Student('张三', 100)
# print(s.name, s.score, s.get_grade())
# 1). 继承规则: 自己有get_grade方法执行自己的get_grade方法
s1 = ComputerStudent('李四', 80)
print(s1.get_grade()) # A
s1.learning()
# print(s1.aa()) # 不会执行
# 2). 继承规则: 自己没有get_grade方法执行父类的get_grade方法
s2 = MathStudent('张三', 80)
print(s2.get_grade()) # B
# print(s1.aa()) # 不会执行
s2.learning()
多继承
多继承,即子类有多个父类,并且具有它们的特征
注:一层层继承下去是多重继承
示例:
class Base(object):
def play(self):
print('Base is playing!')
class A(Base): # 继承Base
def play(self): # 自动覆盖父类的此方法
print('A is playing')
class B(Base): # 继承Base
def play(self):
print('B is playing')
class C(B, A): # 继承A,B
pass
c = C()
c.play()
结果:
注:通过C类实例的方法调用来看,当继承多个父类时,如果父类中有相同的方法,那么子类会优先使用最先被继承的方法
私有属性和私有方法
- 默认情况下,属性在 Python 中都是“public”, 大多数 OO 语言提供“访问控制符”来限定成员函数的访问。
- 在 Python 中,实例的变量名如果以 __ 开头,就变成了一个私有变量/属性(private),实例的函数名如果以 __ 开头,就变成了一个私有函数/方法(private)只有内部可以访问,外部不能访问。
- 注:子类不可以直接调用父类私有方法和属性。
示例:
# 父类(基类)
class Student:
def __init__(self, name, score):
self.name = name
self.__score = score # 1). 私有属性
def get_grade(self):
if 90 <= self.__score <= 100: # 1)类的内部可以访问私有属性self.__score(eg:子类不可以访问)
return 'A'
else:
return 'B'
def set_score(self, score):
self.__score = score
def __play_game(self): # 3). 私有方法
print('正在玩游戏')
s = Student(name='张三', score=100)
print(s.get_grade())
# print(s.__score) # 1). 类的外部不可以访问私有属性
s.set_score(80)
print(s.get_grade()) # 2). 如果想要修改私有属性,可以提供方法set_score在类的内部修改
子类调用父类私有属性和方法:
class aa: # 定义父类aa
def __init__(self):
self.__u = 10 # 父类私有数据域
def __m1(self): # 父类私有方法
self.__u += 1
print(self.__u)
class bb(aa): # 定义子类bb
def m2(self): # 访问父类私有数据域
self._aa__u = -10
print(self._aa__u)
def m3(self): # 访问父类私有方法
self._aa__m1()
p = bb()
p.m3() # 打印11
p.m2() # 打印-10
3.多态
多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。通俗来说: 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
多态的好处就是,当我们需要传入更多的子类,只需要继承父类就可以了,而方法既可以直接不重写(即使用父类的),也可以重写一个特有的。这就是多态的意思。调用方只管调用,不管细节,而当我们新增一种的子类时,只要确保新方法编写正确,而不用管原来的代码。这就是著名的“开闭”原则:
- 对扩展开放(Open for extension):允许子类重写方法函数
- 对修改封闭(Closed for modification):不重写,直接继承父类方法函数
class Animal():
def who(self):
print("I am an Animal")
class Duck(Animal):
def who(self):
print("I am a duck")
class Dog(Animal):
def who(self):
print("I am a dog")
class Cat(Animal):
def who(self):
print("I am a cat")
def func(obj):
obj.who()
if __name__ == "__main__":
duck=Duck()
dog=Dog()
cat=Cat()
func(duck)
func(dog)
func(cat)
要实现多态有两个前提:
- 1.继承:多态必须发生在父类与子类之间
- 2.重写:子类重写父类方法