在类中除了
属性
还有方法
,通常情况下通过实例来进行调用类的方法。本篇札记讲解四个方面进行:
- 绑定方法
- 非绑定方法
- 静态方法
- 类方法
非绑定方法 unbound method
image.png通过
类的名字
直接来调用方法对象(函数对象),叫做非绑定方法
。其中Foo是类,bar是类中的方法。类名字---->方法对象
class Foo:
def bar(self): # 第一个参数必须是self
print("this is a method of class")
f = Foo() # 调用类
f.bar() # 调用类中方法(类中的函数也称之为方法)
this is a method of class
- 类中的函数也称之为
方法
- 当建立了实例
f
之后,当实例调用这个方法bar()
的时候,Python
解释器把实例已经作为第一个参数隐式地传给了该方法。 -
self
就是一个实例!!!!不需要显式地写出self
参数
# 实例显式地传给方法
Foo.bar(f)
this is a method of class
Foo.bar() # 通过类直接调用方法,不传递参数报错,缺少self
- 实例化之后,
self
和实例f
是一样的 - 通常在类中使用
self
,在实例中使用f - 如果用类直接调用方法则会报错:
绑定方法 bound method
绑定方法指的是通过实例得到方法对象的过程。实例---->方法对象
描述器
在类的属性中有个__dict__
的特殊属性,用来查看内部信息:
Foo.__dict__["bar"] # bar 是函数对象
image.png
-
Python
中有几个比较特殊的方法:__get__()、__set__()、__deleta__()
,通常将具有这些方法的对象称之为描述器
。描述器的使用如下:
descr.get(self, obj, type=None)--->value
descr.set(self, obj,value)--->None
descr.delete(self, obj)--->None - 描述器的使用:
Foo.dict['bar'].get(None, Foo)
结果:描述器的返回结果和Foo.bar
是相同的。其中self
指定为None
,表示没有给定实例。
Foo.__dict__["bar"].__get__(f, Foo) # 给定实例f;与实例得到方法对象结果相同
image.png
类方法
lass Foo: # 定义一个类
lang = 'Java' # 定义类的属性lang = "java"
def __init__(self): # 初始化方法__init__
self.lang = 'python' # 实例属性,self是实例对象,属性数lang = "python"
def get_class_attr(cls):
return cls.lang # 引用的对象具有lang属性
if __name__ == "__main__":
print("Foo.lang(类属性值)", Foo.lang) # 输出类lang属性值
r = get_class_attr(Foo) # 调用get_class_attr()方法,其中参数Foo刚好有lang属性
print("get class attr:", r)
f = Foo() # 创建实例f
print("instance attribute(实例属性值)", f.lang) # 参数实例的lang属性值
结果:
Foo.lang(类属性值) Java
get class attr: Java
instance attribute(实例属性值) python
缺陷:
-
get_class_attr()
方法传入的参数不是随意的,必须具有lang
属性 - 此做法使得函数和类的耦合性太强,不利于后期维护,考虑将函数和类融为一体,直接将函数放在类里面。
使用装饰器来解决上面的问题
class Foo: # 定义一个类
lang = 'Java' # 定义类的属性lang = "java"
def __init__(self): # 初始化方法__init__
self.lang = 'python' # 实例属性,self是实例对象,属性数lang = "python"
# 修改部分,加上装饰器,@classmethod装饰的函数第一个参数不是self
@classmethod
def get_class_attr(cls):
return cls.lang # 引用的对象具有lang属性
if __name__ == "__main__":
print("Foo.lang(类属性值)", Foo.lang) # 输出类lang属性值
r = get_class_attr(Foo) # 调用get_class_attr()方法,其中参数Foo刚好有lang属性
print("get class attr:", r)
f = Foo() # 创建实例f
print("instance attribute(实例属性值):", f.lang) # 参数实例的lang属性值
print("instance get_class_attr:", f.get_class_attr())
Foo.lang(类属性值) Java
get class attr: Java
instance attribute(实例属性值): python
instance get_class_attr: Java
结果:通过实例和类执行get_class_attr()
方法得到的结果都是Java
- 类方法:在类里面定义的方法,该方法
由@classmethod所装饰
,第一个参数
cls(约定俗称第一个参数为
cls)的引用对象为
类本身`。
静态方法
下面是一个有待优化的代码,因为类Foo里面使用了外面定义的函数select函数,不便于维护
import random
def select(n):
a = random.randint(0, 100) # 生成一个随机数
return a - n > 0
class Foo:
def __init__(self, name): # 初始化函数
self.name = name # 实例self的 name属性为name
def get_name(self, age): # 第一参数必须是self
if select(age) is True: # 就是返回值大于0
return self.name
else:
return "this name is secret."
if __name__ == "__main__":
f = Foo("Peter")
name = f.get_name(27)
print(name)
优化代码如下
import random
class Foo: # 定义类,首字母大写
def __init__(self, name): # 初始化函数
self.name = name # self实例的name属性为name
def get_name(self, age): # 将原来在外面的函数放在里面
if self.select(age): # 直接通过实例进行调用;也可以通过类进行调用:Foo.select()
return self.name # 返回实例self的name属性值
else:
return "the name is secret"
# 增加装饰器
@staticmethod
def select(n): # 虽然在类里面,但是第一个参数不是self
a = random.randint(1,100)
return a - n > 0
if __name__ == "__main__":
f = Foo("luolaoshi")
name = f.get_name(22)
print(name)
小结:
- 将原来在类外面的函数放到里面
- 移动到里面的方法的
第一个参数不是self
- 移到类的命名空间之内,前面必须加上
@staticmethod
进行装饰 - 调用可以通过
实例
或者类
进行调用
下面对上面的四种方法进行一个小结:
- 绑定方法:实例--->对象方法
- 非绑定方法:类--->对象方法
- 类方法:
@classmethod
,将方法写在类里面,该方法的第一个参数不是self
,通常用cls。 - 静态方法:
@staticmethod
,将方法移动到类里面,位于类的命名空间之内。第一个参数不是self
;方法可以通过实例或类进行调用。
网友评论