五、类和对象¶
1、类和对象之间的关系¶
这部分内容主要讲类和对象,我们先来说说类和对象之间的关系。
类是对象的模板
我们得先有了类,才能制作出对象。
类就相对于工厂里面的模具,对象就是根据模具制造出来的产品。
从模具变成产品的过程,我们就称为类的实例化。
类实例化之后,就变成对象了。也就是相当于例子中的产品。
2、类的实例化¶
这里强调一下,类的实例化和直接使用类的格式是不一样的。
之前我们就学过,直接使用类格式是这样的:
而类的实例化是怎样的呢?
是这样的,可以仔细对比一下,类的实例化和直接使用类的格式有什么不同?
class ClassA(object): # 这个可以先不管,是关于继承的,后面会说到
var1 = '两点水'
def fun1(self): # 没有了 @classmethod ,cls 变成了 self
print('var1 值为: ' + self.var1)
# 实例化,并且使用
a = ClassA()
# 实例化之后,使用它里面的方法
a.fun1()
# 或者是使用它里面的属性
print(a.var1)
输出的结果:
主要的不同点有:
- 类方法里面没有了
@classmethod声明了,不用声明他是类方法 - 类方法里面的参数
cls改为self - 类的使用,变成了先通过
实例名 = 类()的方式实例化对象,为类创建一个实例,然后再使用实例名.函数()的方式调用对应的方法 ,使用实例名.变量名的方法调用类的属性
这里说明一下,类方法的参数为什么 cls 改为 self ?
其实这并不是说一定要写这个,你改为什么字母,什么名字都可以。
不妨试一下:
class ClassA(object):
var1 = '两点水'
def fun1(aaaaaaaa): # self 改为 aaaaaaaa 了
print('var1 值为: ' + aaaaaaaa.var1)
# 实例化
a = ClassA()
# 实例化之后,使用它里面的方法
a.fun1()
# 或者是使用它里面的属性
print(a.var1)
输出结果:
你看,把 self 改为 aaaaaaaa 还是可以一样运行的。
只不过使用 cls 和 self 是我们的编程习惯,这也是我们的编程规范。
因为 cls 是 class 的缩写,代表这类 , 而 self 代表这对象的意思。
所以啊,这里我们实例化对象的时候,就使用 self 。
而且 self 是所有类方法位于首位、默认的特殊参数。
除此之外,在这里,还要强调一个概念,当你把类实例化之后,里面的属性和方法,就不叫类属性和类方法了,改为叫实例属性和实例方法,也可以叫对象属性和对象方法。
为什么要这样强调呢?
因为一个类是可以创造出多个实例对象出来的。
你看下面的例子:
class ClassA(object):
var1 = '两点水'
def fun1(self):
print('var1 值为: ' + self.var1)
# 实例化
a = ClassA()
# 实例化之后,使用它里面的方法
a.fun1()
# 或者是使用它里面的属性
print(a.var1)
# 实例化
b = ClassA()
# 实例化之后,使用它里面的方法
b.fun1()
# 或者是使用它里面的属性
print(b.var1)
输出结果:
我不仅能用这个类创建 a 对象,还能创建 b 对象
3、实例属性和类属性¶
一个类可以实例化多个对象出来。
┌──────┐
│ 对象 │
┌──→ ├──────┤
│ │ 属性 │
│ ├──────┤
┌──────┐ 实例化 │ │ 方法 │
│ 类 │ │ └──────┘
├──────┤ │
│ 属性 │ ─────────────┤
├──────┤ │ ┌──────┐
│ 方法 │ │ │ 对象 │
└──────┘ └──→ ├──────┤
│ 属性 │
├──────┤
│ 方法 │
└──────┘
根据这个图,我们探究一下实例对象的属性和类属性之间有什么关系呢?
先提出第一个问题,如果类属性改变了,实例属性会不会跟着改变呢?
还是跟以前一样,提出了问题,我们直接用程序来验证就好。
看程序:
class ClassA(object):
var1 = '两点水'
def fun1(self):
print('var1 值为: ' + self.var1)
# 实例化
a = ClassA()
# 或者是使用它里面的属性
print(a.var1)
# 改变类属性
ClassA.var1 = '三点水'
# 重新打印实例化对象 a 的属性
print(a.var1)
输出结果:
从程序运行的结果来看,类属性改变了,实例属性会跟着改变。
这很好理解,因为我们的实例对象就是根据类来复制出来的,类属性改变了,实例对象的属性也会跟着改变。
那么相反,如果实例属性改变了,类属性会改变吗?
答案当然是不能啦。因为每个实例都是单独的个体,不能影响到类的。
具体我们做下实验:
class ClassA(object):
var1 = '两点水'
def fun1(self):
print('var1 值为: ' + self.var1)
# 实例化
a = ClassA()
# 或者是使用它里面的属性
print(a.var1)
# 修改实例化的属性只
a.var1 = '三点水'
# 打印修改后实例化的属性值
print(a.var1)
# 打印类的属性值
print(ClassA.var1)
输出结果:
可以看到,不管实例对象怎么修改属性值,对类的属性还是没有影响的。
4、实例方法和类方法¶
那这里跟上面一样,还是提出同样的问题。
如果类方法改变了,实例方法会不会跟着改变呢?
看下下面的例子:
class ClassA(object):
var1 = '两点水'
def fun1(self):
print('关注十年不更新一次的公众号: ReadingWithU')
# 实例化
a = ClassA()
# 或者是使用它里面的方法
a.fun1()
# 修改类方法
# 1. 先要定义一个新函数
def newFun1(self):
print('加我个人微信号: thinktoday2019 交个好友? ')
# 2. 用新的函数替代老的函数,也就是「重写类方法」
ClassA.fun1 = newFun1
# 再次调用实例的方法
a.fun1()
输出结果:
这里建议我的例子,各位都要仔细看一下,自己重新敲一遍。相信为什么要这么做,这么证明。
还是那句话多想,多敲。
回归正题,从运行的结果来看,类方法改变了,实例方法也是会跟着改变的。
在这个例子中,我们需要改变类方法,就用到了类的重写。
我们使用了 类.原始函数 = 新函数 就完了类的重写了。
要注意的是,这里的赋值是在替换方法,并不是调用函数。所以是不能加上括号的,也就是 类.原始函数() = 新函数() 这个写法是不对的。
那么如果实例方法改变了,类方法会改变吗?
如果这个问题我们需要验证的话,是不是要重写实例的方法,然后观察结果,看看类方法有没有改变,这样就能得出结果了。
可是我们是不能重写实例方法。
你看,会直接报错。
class ClassA(object):
var1 = '两点水'
def fun1(self):
print('关注十年不更新一次的公众号: ReadingWithU')
# 实例化
a = ClassA()
# 使用它里面的方法
a.fun1()
# 1. 先要定义一个新函数
def newFun1(self):
print('加我个人微信号: thinktoday2019 交个好友? ')
# 2. 实例方法替换新函数
a.fun1 = newFun1
# 再次调用实例的方法
a.fun1()
报错如下: