(二)self 与方法绑定
1. 同一份方法处理不同实例
self 不是关键字,而是实例方法第一个参数的惯用名称。通过哪个实例取得方法,调用时就把哪个实例交给这个位置。
# title 是本次调用的局部参数;self.title 是实例上保存的属性。
class Book:
def __init__(self, title):
self.title = title
self.finished = False
def rename(self, title):
self.title = title.strip()
def finish(self):
self.finished = True
first = Book("Python")
second = Book("NumPy")
first.rename(" Python 入门 ")
# 从类取得普通函数时,显式传入要修改的实例。
Book.finish(first)
print(first.title, first.finished)
print(second.title, second.finished)输出 Python 入门 True 与 NumPy False。在这个普通实例方法中,first.finish() 与 Book.finish(first) 对应同一次处理;first.finish(first) 则会把 first 再传一次,造成参数数量错误。
title = "新书名" 只会重新绑定局部名称,self.title = "新书名" 才更新实例属性。类定义块也不会变成方法的外层函数作用域;方法要读取实例或类中的属性,仍要通过 self.title、Book.category 这样的访问写清来源。
2. 取出方法,稍后再调用
# first.finish 不带括号,得到已经绑定 first 的方法对象。
class Book:
def __init__(self, title):
self.title = title
self.finished = False
def finish(self):
self.finished = True
first = Book("Python")
action = first.finish
print(action.__self__ is first)
print(action.__func__ is Book.finish)
action()
print(first.finished)三行都是 True。绑定方法保存两份关联:__self__ 是接收调用的实例,__func__ 是类中的原函数。调用 action() 时,这个方法对象把保存的实例补到第一个参数。
因此,上一章的回调也可以接收 first.finish。先取出方法,等到某个动作发生时再调用,它仍知道要修改哪本书;方法对象所保留的实例引用,也会影响实例继续存活的时间。