正式揭秘特殊参数self的作用:self会接收实例化过程中传入的数据,当实例对象创建后,实例便会代替 self,在代码中运行。
换言之,self 是所有实例的替身,“替身”是什么意思呢?我们来看一个例子。
刚刚我们列举的类方法都只有一个self参数,实际上和一般函数一样,类的方法也可以设置多个参数:(直接运行即可 )
class Chinese:
name = '大师兄' # 类属性name
def say(self, someone): # 带有两个参数的方法
print(someone + '是中国人')
person = Chinese()
print(person.name)
person.say('大师兄')
# self调用时要忽略,'大师兄'传给参数someone
运行结果:
大师兄
大师兄是中国人
这样写虽然没错,但实际上是多此一举,因为只要在say方法内部调用类属性’吴枫’,就可以实现同样的功能,不必重复传参。
怎么在方法内部调用类属性呢?你可能会想着这样写:
# 以下代码会报错
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()
再次恭喜~你已经掌握了创建类的两个特殊点。至此,你已经将课堂的主要知识都收入囊中了。
学到这,可能你会觉得类看起来平平无奇,这主要是老师为了让你能快速掌握相关概念和语法,课堂上的案例都很简单,而类一般是用在较复杂的项目里。