Python学习笔记
面向对象(2)
实例方法与自动绑定
- 使用对象调用实例方法时,python会自动绑定方法的第一个参数(通常建议将该参数命名为self)
- 根据第一个参数出现位置的不同,第一个参数所绑定的对象略有区别。但是总之,方法中的self总是代表该方法的调用者。实例方法的第一个self不需要传入,由系统自动绑定,总是绑定到方法调用者。
- 在构造方法中引用该构造方法正在初始化的对象。
- 在普通实例方法中引用调用该方法的对象
class User:
def __init__(self, name = "tiger"):
# self代表该构造器正在构造的对象
self.name = name
def info(self):
print(self)
print(self.name)
# User构造的对象,赋值给了u,因此User构造器中的self实际上就代表u
u = User()
print(u.name)
# User够早的对象,赋值给了u2,在User构造器中的self实际上就代表u2
u2 = User("scott")
print(u2.name)
print(u2)
# 程序用u2调用了info方法,那么info方法中的self就代表了u2
u2.info()
# 程序用u1调用了info方法,那么info方法中的self就代表了u1
u1 = User()
u1.info()
- 注意:当python的一个方法调用另一个方法时,不可以省略self;python的类、对象有点类似于一个命名空间,因此在调用类、对象的方法时,一定要加上
.
,也就是类.
或者对象.
的形式。
class Dog:
def run(self):
# 一个方法调用其他方法,也需要使用self来调用
self.jump()
print("狗在跑")
def jump(self):
print("狗在跳")
d = Dog()
d.run()
返回self
- self参数可当成实例方法的返回值
- 把self参数作为返回值,则可多次连续调用方法(只要该方法也返回self)
class Plant:
def __init__(self, height = 2):
self.height = height
def grow(self):
# 每grow一次,height增加10
self.height += 10
p = Plant()
print(p.height)
p.grow()
print(p.height)
- 上面的程序是正常的,没有返回值self的,运行结果是
2
,12
。如果方法grow
返回值是self
,那么就是grow方法返回了调用者本身,那么就可以写成以下形式:
class Plant:
def __init__(self, height = 2):
self.height = height
def grow(self):
# 每grow一次,height增加10
self.height += 10
return self
p = Plant()
p.grow().grow().grow().grow()
print(p.height)
- 运行结果是
42
,这是一种非常神奇的python语法现象。
使用类来调用实例方法
- 前面说过,实例方法要用对象来调用,但是其实类也是可以调用实例方法的(python是动态语言)。
class Role:
def test(self):
print("test方法")
# 这样的调用是错的,因为test方法本身是实例方法,应该是使用对象来调用
# python允许使用类来调用实例方法,此时变成了“未绑定的方法”
# 因此必须显式为self传入参数值
# Role.test()
# 这是正确的调用方法
r = Role()
Role.test(r)
- 注意:使用类调用实例方法时,python不会绑定方法的第一个参数;如果实例方法定义了一个self参数,使用类调用实例方法时,必须手动传入参数值。
类方法与静态方法
- 类方法和静态方法有点相似,他们都推荐使用类来调用(其实也可以使用对象来调用)
- 定义类方法:
- 使用
@classmethod
修饰,这个东西叫函数装饰器 - 方法的第一个参数定义为
cls
(class缩写),用类调用该方法时该参数会自动绑定
。
- 使用
class Tiger:
# 类方法两个注意点,第一个参数是cls,前面必须要@classmethod修饰
@classmethod
def info(cls):
print("info类方法")
print(cls)
print(Tiger)
# 类方法属于类本身,所以使用类来调用
# 类方法的第一个参数也会自动绑定,绑定到调用该方法的类
Tiger.info()
t = Tiger()
# 对象调用类方法也是可以的,但是注意第一个参数绑定的还是类
# 对象调用实际上也相当于用类调用类方法,第一个参数绑定当前类
t.info()
- 定义静态方法:
- 使用
@staticmethod
修饰 - 对方法参数没有要求,无论如何都不会自动绑定。
- 使用
class Tiger:
# 静态方法两个注意点,无需定义任何形参,,前面必须要@staticmethod修饰
# 即使这里写了若干个形参,也不会自动绑定。
@staticmethod
def info(p):
print("info静态方法")
print(p)
# 静态方法就相当于是一个函数,因此不会自动绑定
# 用类调用静态方法
Tiger.info("lancibe")
t = Tiger()
# 对象调用静态方法,也不会自动绑定,也要传入参数值
t.info(t)
- 所以把静态方法当做一个函数完全没有问题
- 关于形参会不会自动绑定的问题,有如下表格:
实例方法 | 类方法 | 静态方法 | |
---|---|---|---|
对象调用 | 自动绑定 | 自动绑定 | 不自动绑定 |
类调用 | 不自动绑定 | 自动绑定 | 不自动绑定 |
总结
- 类方法和静态方法的共性:都可以使用类和对象调用
- 类方法的自动绑定与不绑定
- 静态方法总是不绑定