安迪Python

V1

2023/01/15阅读:8主题:默认主题

65. `__init__`方法

65. __init__方法

1. 知识回顾在类的方法中调用类的属性

【目标任务】

创建一个类,计算2个数的和。

【体验代码】

# 定义一个求和类,类名为Sum
class Sum:

    # 直接写在类里的变量称为类属性
    x = 2 
    y = 4
   
    # 在类中定义的函数称为方法
    # 方法名为qiuhe,功能是计算类里2个变量的和
    def qiuhe(self):
        # 方法中的代码块        
        print(x+y)
        
# 创建对象:对象名=类名( )
he= Sum( ) 
# 调用对象:对象名.方法名(值)
he.qiuhe( )

运行上述的代码程序报错,提示name 'x' is not defined即x没有被定义。

观察代码的第5和第6行,我已经给变量赋值了。

# 直接写在类里的变量称为类属性
x = 2 
y = 4

但程序还是提示没有被定义,这是因为xy是在类里定义的变量。

在类里定义的变量我们称之为类属性。

上节课我们学过,在类内部的方法中调用类的属性其它类的方法时,需要在前面加上slef. 如:

self.属性名

self.方法名

# 在类中定义的函数称为方法
# 方法名为qiuhe,功能是计算类里2个变量的和
def qiuhe(self):
    # 方法中的代码块        
    print(x+y)

qiuhe是在类中定义的方法。

x和y是类里的属性。

要调用类里的属性,语法为self.属性名

因此我们将代码的第12行:

# 方法中的代码块        
print(x+y)

更改如下:

# 方法中的代码块        
print(self.x+self.y)

【综合代码】

# 定义一个求和类,类名为Sum
class Sum:

    # 直接写在类里的变量称为类属性
    x = 2 
    y = 4
   
    # 在类中定义的函数称为方法
    # 方法名为qiuhe,功能是计算类里2个变量的和
    def qiuhe(self):
        # 方法中的代码块        
        print(self.x+self.y)
        
# 创建对象:对象名=类名( )
he= Sum( ) 
# 调用对象:对象名.方法名(值)
he.qiuhe()

【终端输出】

6

输出结果为6,我们成功设计了一个求和的小程序。

但这个程序只能计算2和4的和,不方便用户。

用户如果需要计算其他2个数的和,就要更改类的属性。

我们使用类的优势之一在于,代码写好后我们将它封装保存,需要的时候我们直接调用它就好。

因此,我们最好不要取修改类里的代码。

那怎么优化呢?

我们可以通过调用方法时传值的形式进行代码优化。

2. 知识回顾调用方法时传值

# 定义一个求和类,类名为Sum
class Sum:
    
    # 在类中定义的函数称为方法
    # 方法名为qiuhe,功能是计算类里2个变量的和
    def qiuhe(self,x,y):
        # 方法中的代码块        
        print(x+y)
        
# 创建对象:对象名=类名( )
he= Sum( ) 
# 调用对象:对象名.方法名(值)
he.qiuhe(2,4)

【终端输出】

6

和之前的代码相比,我做了如下改动:

  1. 我把类定义属性的语句删除了。
# 直接写在类里的变量称为类属性
x = 2 
y = 4
  1. 我修改了求和方法的参数。

将原来的:

def qiuhe(self):
    # 方法中的代码块        
    print(self.x+self.y)

修改为:

# 在类中定义的函数称为方法
# 方法名为qiuhe,功能是计算类里2个变量的和
def qiuhe(self,x,y):
    # 方法中的代码块        
    print(x+y)

和之前的方法相比,我在方法中增加了2个参数,x和y。

最后再调用方法的时候直接传入方法中需要的值。

# 调用对象:对象名.方法名(值)
he.qiuhe(2,4)

方法中的值是按位置进行传递的。

2传递给x。

4传递给y。

方法传值的优势在于不管你想计算哪两个数的和,只需要修改方法中的值即可。

【体验代码】

观察下面的代码,只用修改值我们就可成功计算出多个两位数的和。

# 定义一个求和类,类名为Sum
class Sum:
    
   # 在类中定义的函数称为方法
   # 方法名为qiuhe,功能是计算类里2个变量的和
    def qiuhe(self,x,y):
        # 方法中的代码块        
        print(x+y)
        
# 创建对象:对象名=类名( )
he= Sum( ) 
# 调用对象:对象名.方法名(值)
he.qiuhe(2,4)
he.qiuhe(4,4)
he.qiuhe(7,4)

【终端输出】

6
8
11

3.体验__init__方法

我们还可以继续优化我们的代码:

观察下面的代码,重点注意观察第6行。

# 定义一个求和类,类名为Sum
class Sum:
    
    # 在类中定义的函数称为方法
    # 方法名为__init__
    def __init__(self,x,y):        
        # 方法中的代码块        
        print(x+y)
        
# 创建对象:对象名=类名( )
he= Sum(2,4

【终端输出】

6

上面的代码较之前的代码,我做了如下几个调整:

  1. 把之前的函数名qiuhe修改为__init__

下面是之前的旧代码:

# 定义一个方法,计算类里2个变量的和
def qiuhe(self,x,y):
    # 方法中的代码块        
    print(x+y)

下面是修改后的代码:

def __init__(self,x,y):
    # 方法中的代码块        
    print(x+y)
  1. 把要传递的值放入创建对象的语句里,删除了调用方法的代码。

之前的旧代码,有调用方法语句,传入的值在调用方法语句里。

# 创建对象:对象名.类名( )
he= Sum( ) 
# 调用对象:对象名.方法名(值)
he.qiuhe(2,4)

现在的代码只有创建对象语句,传入的值在创建对象语句里。

# 创建对象:对象名=类名(值)
he= Sum(2,4

之前说过,要输出类方法里的语句,是需要一个调用方法的语句的。

那为什么这里修改方法名后,不调用也能输出呢。

那是因为__init__方法的作用就是,在类创建对象时,不需要调用方法语句,就可以自动执行__init__方法中的代码块(这是我自己对该方法的解释,仅供参考)。

大家可以试一下,同样的情况下,如果方法名不为__init__,程序是会报错的:

# 定义一个求和类,类名为Sum
class Sum:
    
    # 在类中定义的函数称为方法    
    def qiuhe(self,x,y):
        # 方法中的代码块        
        print(x+y)
        
# 创建对象:对象名=类名( )
he= Sum(2,4

【终端输出】

TypeError: Sum() takes no arguments

运行上述代码,程序报错,提示Sum() takes no arguments即Sum不接受参数。

同样的代码,方法名不一样,输出结果就不一样,这就是__init__方法在作怪。

4. __init__的作用

Python本身有内置函数和自定义函数两种。

自定义函数我们可以根据自己的喜好命名。

但内置函数就不能随便更改名字。只有单词拼写正确了,我们才能使用该函数本身具有的功能。例如type、input、print函数。

其实类中也可以这样理解。

上节课我用的drive ,stop,back都是我自己定义的方法名。

这里的 __init__我们可以理解成它是类中的内置方法,方法名是固定的。

init是initialization的缩写。

initialization [ɪˌnɪʃəlaɪ'zeɪʃn] :初始化。

__init__方法通常称为初始化方法。

__init__方法的作用官方解释是支持带参数类的初始化,声明该类的属性(类中的变量)。

如果你是小白,这样的话术很难理解。

那我们可以这样理解它:

类中的属性不是一成不变的,是一个可能会变化的值。

我们不想在类中定义属性,而想在创建对象时传入,这时可以用init方法在类中声明属性即类里的变量。

当然我还有一种简单粗暴的理解。

你就把它当做一个类中的普通方法,这个方法有以下几个作用:

1. init方法接收创建对象时传入的值。

2. init方法中的代码块不需要调用语句,创建对象就会被自动执行。

【举例说明】

class Test:
    
    def __init__ (self):
        print("只要有创建对象语句,我就会被输出。")
    
    def A(self):               
        print("要调用方法A,我才输出。")
        
# 创建对象:对象名=类名( )
ceshi= Test( )

【终端输出】

只要有创建对象语句,我就会被输出。

上述代码因为只有创建对象语句,没有调用方法语句。

因此,下面这个语句被输出了,因为init方法中的代码块会自动被执行。

print("只要有创建对象语句,我就会被输出。")

下面的语句没有输出,因为没有调用方法A。

print("要调用方法A,我才输出。")

【增加一个调用方法A的语句】

class Test:
    
    def __init__ (self):
        print("只要有创建对象语句,我就会被输出")
    
    def A(self):               
        print("要调用方法A,我才输出。")

# 创建对象:对象名=类名( )
ceshi= Test( )
# 调用方法:对象名.方法名
ceshi.A()

【终端输出】

只要有创建对象语句,我就会被输出
要调用方法A,我才输出。

两句话都被输出了,因为我增加了调用方法A的语句,如下:

# 调用方法:对象名.方法名
ceshi.A()

5. __init__方法的写法

定义__init__方法的语法和定义其它方法的语法是一样的。

有两个需要特别注意的地方。

  1. 方法名是init,很多初学者容易错写成int

  2. 方法名前后格有2条小横线,注意是前面2条,后面2条,总的4条。初学者易写成2条小横线。

65-1
65-1

6. __init__方法调用类的属性

这是我刚才写的代码:

# 定义一个求和类,类名为Sum
class Sum:
    
    # 在类中定义的函数称为方法
    # 方法名为__init__
    def __init__(self,x,y):        
        # 方法中的代码块        
        print(x+y)
        
# 创建对象:对象名=类名( )
he= Sum(2,4

上述的代码运行虽然没有错误,但其实是不规范的。

下面的代码是规范的:

# 定义一个求和类,类名为Sum
class Sum:  

    # 在类中定义的函数称为方法
    # 方法名为__init__
    def __init__(self,x,y):
        self.x = x
        self.y = y              
        # 方法中的代码块        
        print(self.x+self.y)
        
# 创建对象:对象名=类名( )
he= Sum(2,4

【终端输出】

6

我是这样理解的,仅供大家参考:

2和4是在创建对象时传入的值,理论上等同于类的属性。

是类的属性,在类中调用类的属于就需要用self.属性名

上述方法有self,x,y三个参数。

self.x中的x表示的是类的属性。

等号后面的x表示的是值。

self.属性=值

self.x = x
self.y = y 
65-2
65-2

按照位置,2传递给x。self.x相当于类里的变量x。

按照位置,4传递给y。self.y相当于类里的变量y。

按照语法规则在init中我们是要带着self.走的。

但没有目前也没有报错。

至于为什么没报错,或者self.在这里存在的意义我目前还没有语言给大家解释清楚。

但建议所有学者都带上self.,我相信存在既有意义,只是我水平不够,解释不清楚。

7. 课堂实操

下面是我们上节课生产各种汽车的代码:

# 定义一个车类,类名为Cars
class Cars:

    # 直接写在类里的变量称为类属性
    color_1 = "红色"
    color_2 = "黑色"
    color_3 = "黄色"
    color_4 = "绿色"
    type_1 = "小轿车"
    type_2 = "越野车"
    type_3 = "公交车"
    type_4 = "跑车"
   
    # 在类中定义的函数称为方法
    # 方法的第1个参数必须是slef    
    def drive(self, speed):
        # 方法中的代码块
        print(f"经测试,{self.color_4}{self.type_4}的最高时速是{speed}公里每小时。")
        print("经测试,{}的{}的最高时速是{}公里每小时。".format(self.color_2, self.type_4, speed))
        print("经测试,{}的{}的最高时速是{}公里每小时。".format(self.color_1, self.type_4, speed))
# 创建对象:对象名=类名( )
paoche = Cars( )      

# 调用对象:对象名.方法名(值)
# 测试车速
paoche.drive(230)

【终端输出】

经测试,绿色的跑车的最高时速是230公里每小时。
经测试,黑色的跑车的最高时速是230公里每小时。
经测试,红色的跑车的最高时速是230公里每小时。

下面,我对上面的代码就行优化:

# 定义一个车类,类名为Cars
class Cars: 
   
    # 使用初始化方法init  
    def __init__(self, color, type, speed):
        self.color = color
        self.type = type
        self.speed =speed
        # 方法中的代码块
        print(f"经测试,{self.color}{self.type}的最高时速是{self.speed}公里每小时。")        
        
# 创建对象:对象名=类名( )
che = Cars("红色","公交车",160 )       
che = Cars("黑色","跑车",280 )   
che = Cars("黄色","卡车",180 )   
che = Cars("紫色","小轿车",240)   
che = Cars("黑色","小轿车",240
che = Cars("红色","小轿车",240
che = Cars("绿色","小轿车",240

【终端输出】

经测试,红色的公交车的最高时速是160公里每小时。
经测试,黑色的跑车的最高时速是280公里每小时。
经测试,黄色的卡车的最高时速是180公里每小时。
经测试,紫色的小轿车的最高时速是240公里每小时。
经测试,黑色的小轿车的最高时速是240公里每小时。
经测试,红色的小轿车的最高时速是240公里每小时。
经测试,绿色的小轿车的最高时速是240公里每小时。

对比2段代码,大家应该能感受到init方法的优势了。

终端输出了7个语句,即生产了7种汽车。

如果我们没有用init方法,要输出上面的这7个语句。

我们需要定义7个颜色变量,7个汽车类型变量,7个汽车时速变量,写7带字符串格式化的输出语句。

而用init方法,代码就相对简洁了很多。

分类:

后端

标签:

Python

作者介绍

安迪Python
V1