栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

儿童python教程145:Python self用法详解

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

儿童python教程145:Python self用法详解

在学习如何定义类的过程中,无论是显式创建类的构造方法,还是向类中添加实例方法,都要求将 self 参数作为方法的第一个参数。例如,定义如下 Dog 类:

class Dog:

    def __init__(self):

        print("正在执行构造方法")

    # 定义一个jump()实例方法

    def jump(self):

        print("正在执行jump方法")
本节将对 self 参数做详细的讲解。

Python 要求,类方法(构造方法和实例方法)中至少要包含一个参数,但并没有规定此参数的名称(完全可以叫任意参数名),之所以将类方法的第一个参数命名为 self,只是 Python 程序员约定俗成的一种习惯,这会使程序具有更好的可读性。

那么,作为类方法的第一个参数,self 参数的具体作用是什么呢?打个比方,如果把类比作造房子的图纸,那么对类实例化后的对象才是真正可以住的房子,根据一张图纸,我们可以设计出成千上万的房子,虽然每个房子长相相似,但它们都有各自的主人。而类方法的 self 参数,就相当于每个房子的门钥匙,它可以保证,每个房子的主人仅能进入自己的房子。

如果你接触过其他面向对象的编程语言(例如 C++),其实 Python 类方法中的 self 参数就相当于 C++ 中的 this 指针。

也就是说,同一个类可以产生多个对象,当某个对象调用类方法时,该对象会把自身的引用作为第一个参数自动传给该方法,换句话说,Python 会自动绑定类方法的第一个参数指向调用该方法的对象。如此,Python解释器就能知道到底要操作哪个对象的方法了。

对于构造方法来说,self 参数(第一个参数)代表该构造方法正在初始化的对象。

因此,程序在调用实例方法和构造方法时,不需要为第一个参数传值。例如,更改前面的 Dog 类,如下所示:

class Dog:

    def __init__(self):

        print(self,"在调用构造方法")

    # 定义一个jump()方法

    def jump(self):

        print(self,"正在执行jump方法")

    # 定义一个run()方法,run()方法需要借助jump()方法

    def run(self):

        print(self,"正在执行run方法")

        # 使用self参数引用调用run()方法的对象

        self.jump()

dog1 = Dog()

dog1.run()

dog2 = Dog()

dog2.run()
上面代码中,jump() 和 run() 中的 self 代表该方法的调用者,即谁在调用该方法,那么 self 就代表谁,因此,该程序的运行结果为:

<__main__.Dog object at 0x00000276B14B12B0> 在调用构造方法
<__main__.Dog object at 0x00000276B14B12B0> 正在执行run方法
<__main__.Dog object at 0x00000276B14B12B0> 正在执行jump方法
<__main__.Dog object at 0x00000276B14B1F28> 在调用构造方法
<__main__.Dog object at 0x00000276B14B1F28> 正在执行run方法
<__main__.Dog object at 0x00000276B14B1F28> 正在执行jump方法


上面程序中值得一提的是,当一个 Dog 对象调用 run() 方法时,run() 方法需要依赖该对象自己的 jump() 方法。在现实世界里,对象的一个方法依赖另一个方法的情形很常见,例如,吃饭方法依赖拿筷子方法,写程序方法依赖敲键盘方法,这种依赖都是同一个对象的两个方法之间的依赖。

注意,当 Python 对象的一个方法调用另一个方法时,不可以省略 self。也就是说,将上面的 run()方法改为如下形式是不正确的:

# 定义一个run()方法,run()方法需要借助jump()方法

def run():

    #省略self,代码会报错

    self.jump()

    print("正在执行run方法")

再比如,分析如下代码:

class InConstructor :

    def __init__(self) :

        # 在构造方法里定义一个foo变量(局部变量)

        foo = 0

        # 使用self代表该构造方法正在初始化的对象

        # 下面的代码将会把该构造方法正在初始化的对象的foo实例变量设为6

        self.foo = 6

# 所有使用InConstructor创建的对象的foo实例变量将被设为6

print(InConstructor().foo) # 输出6
在 InConstructor 的构造方法中,self 参数总是引用该构造方法正在初始化的对象。程序中将正在执行初始化的 InConstructor 对象的 foo 实例变量设为 6,这意味着该构造方法返回的所有对象的 foo 实例变量都等于 6。

需要说明的是,自动绑定的 self 参数并不依赖具体的调用方式,不管是以方法调用还是以函数调用的方式执行它,self 参数一样可以自动绑定。例如如下程序:

class User:

    def test(self):

        print('self参数: ', self) 

u = User()

# 以方法形式调用test()方法

u.test() # <__main__.User object at 0x00000000021F8240>

# 将User对象的test方法赋值给foo变量

foo = u.test

# 通过foo变量(函数形式)调用test()方法。

foo() # <__main__.User object at 0x00000000021F8240>
上面程序中,第 6 行代码以方法形式调用 User 对象的 test() 方法,此时方法调用者当然会自动绑定到方法的第一个参数(self 参数);程序中第 10 行代码以函数形式调用 User 对象的 test() 方法,看上去没有调用者,但程序依然会把实际调用者绑定到方法的第一个参数,因此输出结果完全相同。

当 self 参数作为对象的默认引用时,程序可以像访问普通变量一样来访问这个 self 参数,甚至可以把 self 参数当成实例方法的返回值。看下面程序:

class ReturnSelf :

    def grow(self):

        if hasattr(self, 'age'):

            self.age += 1

        else:

            self.age = 1

        # return self返回调用该方法的对象

        return self

rs = ReturnSelf()

# 可以连续调用同一个方法

rs.grow().grow().grow()

print("rs的age属性值是:", rs.age)
可以看出,如果在某个方法中把 self 参数作为返回值,则可以多次连续调用同一个方法,从而使得代码更加简洁。但是这种把 self 参数作为返回值的方法可能会造成实际意义的模糊,例如上面的 grow 方法用于表示对象的生长,即 age 属性的值加 1,实际上不应该有返回值。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/805973.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号