Python类与对象
类与对象是面向对象中的重要概念,面向对象是一种编程思想,也就是尽量模拟按现实世界的思维方式构建件系统。
如,真实世界里有学生和老师,学生有学号、姓名、所在学院等属性(数据),还有学习、吃饭、研究课题等动作(方法),那么我们在构建软件系统学生管理系统时,就会有学生类(用来定义学生的数据与方法),也会有张同学、李同学一个一个学生的个体,这些一个一个具体的个体,被称为“对象”,“对象”也被称为“实例”。
一、定义类
在Python中数据类型都是对应一个类,也可以自定义类,创建一种新的数据类型。在Python中定义类的语法格式如下
class 类名[(父亲)]:
类体
相关结构说明:
1、类定义是以关键字class开头,其中的父类是可以省略的(省略时表示直接继承object类),在类名后以英文半角冒号结尾
2、开始类体前需要做缩进(Python中推荐使用4个半角空格)
object类是所有类的根类,在Python中任何一个类都直接或间接地继承了object。
# coding=utf-8
class Car(object):
# 类体
pass
注意:这里的pass只是表示一个占位符,在编程时不想去写某些代码,又不希望这里产生语法错误,可以使用pass语句占位
二、创建对象
类相当于一个模板,有了这个模板后就可以依据它创建对象,这就是类的实例化。所以对象也被称为“实例”。
# coding=utf-8
class Car(object):
# 类体
pass
car = Car() # 实例化一个对象出来,Car()表示调用构造方法用来初始化对象
当对象不需要使用后,Python垃圾回收在后台会释放对象,这个过程是不需要程序员工手操作的。
三、类成员
类的成员主要分为如下一些:
![](https://img-blog.csdnimg.cn/20210912215937649.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_11,color_FFFFFF,t_70,g_se,x_16)
成员变量
也被称为数据成员,保存了类或对象的数据。
成员方法
在类中定义的函数
构造方法
一种特殊的函数,用于初始化类的成员变量
属性
对类进行封装而提供的特殊方法
实例变量、实例方法与类变量、类方法有区别
实例变量和实例方法属于对象,通过对象来调用,类变量和类方法属于类,通过类来调用。
![](https://img-blog.csdnimg.cn/20210912215937664.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_15,color_FFFFFF,t_70,g_se,x_16)
实列变量
它指的是对象个体特有的数据
![](https://img-blog.csdnimg.cn/20210912215937702.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_20,color_FFFFFF,t_70,g_se,x_16)
注意这里的self,在类当中self表示当前对象,构造方法中self参数说明这个方法属于实例,其中self.name和self.age表示name和age属于实例,也就是实例成员变量。
构造方法
__init()__,它是用来创建和初始化实例变量的,这种方法就是构选方法
![](https://img-blog.csdnimg.cn/20210912215937776.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_18,color_FFFFFF,t_70,g_se,x_16)
实例方法
实例方法与实例变量一样,都是某个实例所特有的。
实例方法中第一个参数必须是self,这就把当前实例与方法绑定起来,也就是说这个方法属于实例,在实例方法的调用时则是不需要传self的。
![](https://img-blog.csdnimg.cn/20210912215937736.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_18,color_FFFFFF,t_70,g_se,x_16)
类变量
类变量是属于类的,并不属于某一个对象。
![](https://img-blog.csdnimg.cn/20210912215937651.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_20,color_FFFFFF,t_70,g_se,x_16)
类方法
类方法与类变量似,属于类,不属于某一个对象
定义类方法时,它的第一个参数不是self,而是类本身(cls)
![](https://img-blog.csdnimg.cn/20210912215937663.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_18,color_FFFFFF,t_70,g_se,x_16)
注意:类方法可以访问类变量和其它的类方法,但是不可以访问实例方法和实例变量。这是因为,在实例都没有的情况下有了类方法,但没有实例就没有实例变量和方法,这个时候强形调用访问是会出错的。
四、类特性-封装性
封装性是面向对象的重要基本特性之一。它隐藏了对象的内部细节,只保留有限的外部接口。对于外部的调用者来说无需关心对象的内部细节,从而操作对象变得更简单。
私有变量
为了防止外部调用者随意存取类内部的数据(成员变量),类会把成员变量封装为“私有变量”,外部调用者这个时候只能通过方法调用私有变量。这个在内的内部则可以控制到对类的成员变量的使用。
默认情况下Python的变量都有公有的,如果要改为私有的变量,则需要在变量前加上双下划线(__)。
# coding=utf8
class Account:
__rate = 0.567 # 类变量为私有变量
def __init__(self,account_name,amount):
self.account_name = account_name
self.__amount = amount # 实例变量为私有变量
def show(self):
print("【{0}】金额:{1},利率为:{2}。".format(self.account_name,self.__amount,Account.__rate))
account = Account('张三',750000.0)
account.show()
print('账户名称:{0}'.format(account.account_name))
# print('账户金额:{0}'.format(account.__amount)) # 这里错误,内的外部访问私有实例变量
# print('利率:{0}'.format(Account.__rate)) # 这里错误,内的外部访问私有类变量
私有变量
私有方法与私有变量的封装是类似的,在方法前加上双划线(__)就是私有方法了。
# coding=utf-8
class Account:
__rate = 0.675 # 类变量__rate
def __init__(self,account_name,amount): # 构造函数
self.account_name = account_name # 公有变量
self.__amount = amount # 私有变量
def __get_info(self): # 私有方法
return "【{0}】金额:{1},利率:{2}。".format(self.account_name,self.__amount,Account.__rate)
def desc(self):
print(self.__get_info())
account = Account('张三',350000.0)
account.desc()
# account.__get_info() # 这里会产生错误,私有方法在类外部不可以访问
使用属性
一般在做类的封装时,在一个类中不应该有公有的成员变量,这些个成员变量应该设计为私有的,然后通过公有的set(赋值),get(取值)方法来访问。
# coding=utf-8
class Student:
# 构造方法
def __init__(self,name,age,sex='男'):
self.name = name
self.__age = age
# 实例方法
def study(self):
print("{0}在学习!!".format(self.name))
# get方法用来返回私有实例变量
def get_age(self):
return self.__age
# set方法,用来对私有实例变量进行赋值
def set_age(self,age):
self.__age = age
student = Student('张三',18)
print("{0}的年龄是:{1}".format(student.name,student.get_age())) # 调用get方法获取私有变量的值
student.set_age(20) # 调用set方法来设置私有变量的值
print("{0}的年龄是:{1}".format(student.name,student.get_age()))
把上面的代码修改为使用属性的方式如下
# coding=utf-8
class Student:
# 构造方法
def __init__(self,name,age,sex='男'):
self.name = name
self.__age = age
# 实例方法
def study(self):
print("{0}在学习!!".format(self.name))
# @property代替get_age(self)
@property
def age(self):
return self.__age
# age.setter代替set_age(self,age)
@age.setter
def age(self,age):
self.__age = age
student = Student('张三',18)
print("{0}的年龄是:{1}".format(student.name,student.age)) # 获取私有变量的值
student.age = 20 # 给私有变量赋值
print("{0}的年龄是:{1}".format(student.name,student.age))
方法上的两个装饰器分别是:
@property、@age.setter
在使用的过程中则会像使用公有变量一样。
五、类特性-继承性
继承性是面向对象重要的基本特征之一,在现实世界上继承关系也常常看到,比如猫与动物之间就是一个继承关系,猫是一种特殊的动物,它有动物的全部共有特性和行为(数据与操作)。在面向对象中动物是一般类,称为父类,猫是特殊类,称为子类,特殊类有一般类的全部数据和操作,可称为特殊类继承一般类,也称子类继承父类。
Python中的继承
在Python中声明子类继承父类,语法简单,定义类时在类的后面使用一对小括号指定它的父类就可以了。
![](https://img-blog.csdnimg.cn/20210912215937737.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_15,color_FFFFFF,t_70,g_se,x_16)
注意:在子类继承父类时,会把父类的所有公有成员变量和方法继承下来
多继承
在Python中是支持多继承的,当子类继承多个父类时,如果在多个父类中同时存在相关的成员方法和成员变量,则子类优先继承左边父类中的成员方法或成员变量,从左到右继承级别从高到低。
![](https://img-blog.csdnimg.cn/20210912215937790.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlhb3hpZV9hZHZlbnQ=,size_18,color_FFFFFF,t_70,g_se,x_16)
方法重写
如果子类的方法名与父类的方法名相同,这时子类方法会重写父类的同名方法。
我们把上面的代码做如下的改造,在Mule类中添加一个与Horse中一样的方法show_info
# coding=utf-8
class Horse:
def __int__(self,name):
self.name = name # 实例变量 name
def show_info(self):
return "马的名字:{0}".format(self.name)
def run(self):
print("马跑……")
class Donkey:
def __init__(self,name):
self.name = name # 实例变量name
def show_info(self):
return "驴的名字:{0}".format(self.name)
def run(self):
print("驴跑……")
def tm(self):
print("驴推磨……")
class Mule(Horse,Donkey):
def __init__(self,name,age):
super().__init__(name)
self.age = age # 实例变量 age
def show_info(self):
return "骡,{0},{1}岁。".format(self.name,self.age)
m = Mule('小骡',1)
m.run()
m.tm()
print(m.show_info()) # 这里调用的就是Mule类中的show_info方法了
六、类特性-多态性
多态指对象可以表现出来多种形态。
在多个子类继承父类,并重写父类方法后,这些子类所创建的对象之间就是多态的,这些对象使用不同的方式来实现父类的方法。
# coding=utf-8
class Animal:
def speak(self):
print("动物叫")
class Dog(Animal):
def speak(self):
print("小狗在叫")
class Cat(Animal):
def speak(self):
print("小猫在叫")
a1 = Dog()
a2 = Cat()
a1.speak()
a2.speak()
Python中鸭子类型测试
所谓鸭子类型测试,指的是看到一只鸟,它走路、游泳、叫声都像鸭子,那么这只鸟可以被称为鸭子。
由于支持上述的这种类型测试,Python解释器不检查发生多态的对象是否继承了同一父类,只要它们的相同的行为(方法),它们之间就是多态的。
# coding=utf-8
def start(obj):
obj.speak()
class Animal:
def speak(self):
print("动物叫")
class Dog(Animal):
def speak(self):
print("小狗在叫")
class Cat(Animal):
def speak(self):
print("小猫在叫")
class Car:
def speak(self):
print("小汽车叫")
def run(self):
print("小汽车在跑")
start(Dog())
start(Car())
start(Cat())
首先这几个类中都有相应的start中调用对象的speak方法