类与对象(二)
创建类的两个关键点
特殊参数:self
正式揭秘特殊参数self的作用:self会接收实例化过程中传入的数据,当实例对象创建后,实例便会代替 self,在代码中运行。
换言之,self 是所有实例的替身,“替身”是什么意思呢?我们来看一个例子。
刚刚我们列举的类方法都只有一个self参数,实际上和一般函数一样,类的方法也可以设置多个参数:(直接运行即可 )
class Chinese: name = '大师兄' # 类属性name def say(self, someone): # 带有两个参数的方法 print(someone + '是中国人') person = Chinese() print(person.name) person.say('大师兄') # self调用时要忽略,'大师兄'传给参数someone
运行结果:
大师兄 大师兄是中国人
# 以下代码会报错 class Chinese: name = '大师兄' # 类属性name def say(self): print(name + '是中国人') # 打印出'大师兄是中国人' person = Chinese() person.say()
但这样会报错,系统会告诉你name在say方法中没有被定义,那怎么办呢?
还记得我们刚说的,如果要在类的外部调用类属性,我们得先创建一个实例,再用实例名.属性的格式调用吗?
那么如果想在类的内部调用类属性,而实例又还没创建之前,我们就需要有个变量先代替实例接收数据,这个变量就是参数self。
正确的写法是这样子的:(留意第六行)
class Chinese: name = '吴枫' # 类属性name def say(self): print(self.name + '是中国人') #留意这行代码 person = Chinese() # 创建Chinese的实例person person.say() # 调用实例方法
当最后一行代码运行时,实例person会像参数一样传给self,替换掉self,第六行的self.name等价于person.name。
person.name就相当于调用了类属性name(即’大师兄’),然后跑完整个方法。
它的作用相当于:(对比上面的代码,直接运行即可)
class Chinese: name = '大师兄' # 类属性name def say(person): print(person.name + '是中国人') person = Chinese() # 创建Chinese的实例person person.say()
运行结果:
大师兄是中国人
可见,self的作用相当于先给实例占了个位置,等到实例创建好就“功成身退,退位让贤”。
同理,如果想在类的方法内部调用其他方法时,我们也需要用到self来代表实例。
阅读代码后点击运行:(重点看第七行)
class Chinese: def greeting(self): print('很高兴遇见你') def say(self): self.greeting() #重点看这行代码 print('我来自中国') person = Chinese() # 创建实例person person.say() # 调用say()方法
运行结果:
很高兴遇见你 我来自中国
当最后一行实例person调用say()方法时,便会执行say()内部的语句(第七行开始)。
此时self.greeting()就变成person.greeting(),也就是调用实例方法greeting(),打印出’很高兴遇见你’,再打印出’我来自中国’。
小结
综上,所以我们说self代表的是类的实例本身,方便数据的流转。对此,我们需要记住两点:
第一点:只要在类中用def创建方法时,就必须把第一个参数位置留给 self,并在调用方法时忽略它(不用给self传参)。
第二点:当在类的方法内部想调用类属性或其他方法时,就要采用self.属性名或self.方法名的格式。
好,self这个神奇的参数就讲解到这里。对初学者来说,确实不是那么容易理解,如果不熟悉,可以多多温习,多多联系巩固一下哦。
在self的基础上,下面我们来看第二个特殊点:初始化方法(也叫构造函数)
特殊方法:初始化方法
定义初始化方法的格式是def init(self),是由init加左右两边的【双】下划线组成( initialize “初始化”的缩写)。
初始化方法的作用在于:当每个实例对象创建时,该方法内的代码无须调用就会自动运行。
# 阅读代码后直接运行 class Chinese: def __init__(self): print('很高兴遇见你,我是初始化方法') person = Chinese()
运行结果:
很高兴遇见你,我是初始化方法
是不是很神奇?我们只是创建了实例,还没有调用,初始化方法就自动执行了!
利用这个特性,在编写习惯上,我们会在初始化方法内部完成类属性的创建,为类属性设置初始值,这样类中的其他方法就能直接、随时调用。我们来看个例子:(阅读后直接运行)
class Chinese: def __init__ (self): self.mouth = 1 # self.不能丢 self.eye = 2 def body(self): print('我有%s张嘴巴' % self.mouth) print('我有%s只眼睛' % self.eye) person = Chinese() person.body()
运行结果:
我有1张嘴巴 我有2只眼睛
除了设置固定常量,初始化方法同样可以接收其他参数,让传入的这些数据能作为属性在类的方法之间流转。我们再来看个例子:
class Chinese: def __init__(self, name, birth, region): self.name = name # self.name = '大师兄' self.birth = birth # self.birth = '山西' self.region = region # self.region = '北京' def born(self): print(self.name + '出生在' + self.birth) def live(self): print(self.name + '居住在' + self.region) person = Chinese('大师兄','山西','北京') # 传入初始化方法的参数 person.born() person.live()
先看14行:
person = Chinese('大师兄','山西','北京') # 传入初始化方法的参数
当初始化方法有多个参数的时候,在实例化的时候就要传入相应的值,这里’大师兄’传给参数name, '山西’传给birth,'北京’传给region。
当实例person创建完成后,初始化方法会自动执行,此时第三行的self.name = name就等价于self.name = ‘大师兄’,以此类推。(self.name中的name可以换成其他名称,只是我们习惯上这么写)
如此一来,类的其他方法就能通过self.属性名的形式调用传入的数据了。(还记得self是实例的替身吧)
我猜你可能会有这样的疑惑:不用初始化方法不是也能实现吗?写多个方法不是更麻烦吗?
确实可以,比如上述的代码,我们也可以这么写:
class Chinese: def born(self, name, birthplace): print(name + '出生在' + birthplace) def live(self, name, region): print(name + '居住在' + region) person = Chinese() person.born('大师兄','山西') person.live('大师兄','北京')
虽然代码量并没有减少,但我们可以看到使用初始化方法,至少我们不必重复传参,传入的数据还可以被多次调用,比如这里的’大师兄’。
class Chinese: def __init__(self, name, birth, region): self.name = name # self.name = '大师兄' self.birth = birth # self.birth = '山西' self.region = region # self.region = '北京' def born(self): print(self.name + '出生在' + self.birth) def live(self): print(self.name + '居住在' + self.region) person = Chinese('大师兄','山西','北京') # 传入初始化方法的参数 person.born() person.live()
随着我们想实现的功能愈发复杂,我们会在类内部编写很多的方法,如果我们需要传入的数据能在类中长久保存并能被随时调用,初始化方法就是一个不错的解决方案。
等你自己开始用类来写代码时,就会发现初始化方法又实在又好用。所以只要用到了类,一般都少不了它。
练习题
说了这么多,我们来做个小练习吧。请你在下列代码的基础上补充一个初始化方法(其余部分不变),要求最后的打印结果是:你在哪里出生?我出生在山西。
class Chinese: def __init__(self,hometown): #此处请补充你的代码,达到题目要求 def born(self): print('我出生在%s。' % self.hometown) dashixiong = Chinese('山西') dashixiong.born()
看下参考代码,多看多写,慢慢熟悉。
class Chinese: # 初始化方法的创建,init两边双下划线。 def __init__(self, hometown): self.hometown = hometown print('你在哪里出生?') def born(self): print('我生在%s。' % self.hometown) dashixiong = Chinese('山西') # 传给参数hometown dashixiong.born()
再次恭喜~你已经掌握了创建类的两个特殊点。至此,你已经将课堂的主要知识都收入囊中了。
结语
学到这,可能你会觉得类看起来平平无奇,这主要是老师为了让你能快速掌握相关概念和语法,课堂上的案例都很简单,而类一般是用在较复杂的项目里。
所以下一篇文章,我会具体阐述类与实例在实际编程中的应用,也对一开始提出的问题:什么是面向对象编程做一个具体的阐释。