前言:
在开始介绍__call__()函数时,先来看一个例子:
class TestClass(object):
a=1
def __init__(self):
self.c=4
def do_func(self):
print("这是方法")
test=TestClass()
test1=TestClass
print(test.a)
print(test.c)
print(test1().c)
print(test1.c)
程序的运行结果:

可以思考下,为什么test1.c会报错
__call__()的介绍:
__call__()函数其实就是一个特殊的实例方法,在使用的时候不需要像test.do_func()或者是像test1.do_func()方式调用,直接使用test()的方式就可以,可以很多的时候直接在实例化的对象后加()会报错,那是因为没有实现__call__()函数,如下图:

图中创建了一个类TestClass,再实例化了一个对象test3,让test3()这样会报错,因为TestClass2中没有实现__call__()方法,且继承的object类也没有实现该方法,所以这样使用就会报错如下:

我们加上这个方法,如下例子:


这样的话就很清楚的知道test3()其实就等同于test3.__call__().
()使用延伸:
在平时的使用的经常会遇到如,TestClass3() 和test3()这种的情况,下面我们就分析下:
1.TestCalss3():是类本省调用__new__()方法,来创建一个实例对象,写法等价于TestClass3().__new__()
2.test3():是实例化后的对象调用__call__()方法,来实现对这个方法的调用,写法等价于TestClass3().__new__().__call__()
具体的可以通过判断这两种调用后的类型和对应的属性来验证:
class TestClass(object):
a=1
def __init__(self):
self.c=3
def do_func(self):
print("这是方法")
def __call__(self,A,B):
self.A=A
self.B=B
return A+B
test1=TestClass
print("----type-----")
print("test1的类型:"+str(type(test1)))
print("test1()的类型:"+str(type(test1())))
print("test1.__call__()的类型:"+str(type(test1.__call__(test1,1,2))))
print("test1.__new__()的类型:"+str(type(test1.__new__(test1))))
print("--------dir-------")
print("test1的类型:"+str(dir(test1)))
print("test1()的类型:"+str(dir(test1())))
print("test1.__call__()的类型:"+str(dir(test1.__call__(test1,2,2))))
print("test1.__new__()的类型:"+str(dir(test1.__new__(test1))))
执行后的结果是:
----type-----
test1的类型:<class 'type'>
test1()的类型:<class '__main__.TestClass'>
test1.__call__()的类型:<class 'int'>
test1.__new__()的类型:<class '__main__.TestClass'>
--------dir-------
test1的类型:['A', 'B', '__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute_
_', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__
repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'do_func']
test1()的类型:['A', 'B', '__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribut
e__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '
__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'c', 'do_func']
test1.__call__()的类型:['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__',
'__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__',
'__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '
__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__
rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__size
of__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator'
, 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
test1.__new__()的类型:['A', 'B', '__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__g
etattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduc
e_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'do_func']
开始对type的分析:
1.test1的类型是type,因为test1=TestClass,指向的是类本身,而在python中一切皆对象(这也是python核心的思想),python中规定的一切皆对象,那么类本身也是对象,是对象就会有类型,我们一般的示例对象的类型就是累本身,但是当我们判断类本身时候就需要用一种类型来归纳python中所有的类,所以指定了type为所有类本身的类型,这样可能会有这样的疑问,从一切皆对象的思想出发,type也应该是对象,相应的也应该是有类型的,如果这样一直指定下去,python估计就不用玩了,所以type的类型就是它本身,如下验证:

![]()
2.test1()的类型是TestClass,test1()是TestClass的实例化对象,所以类型就是TestClass
3.test1().__call__(test1,1,2)的类型是int类型,type(test1().__call__(test1,1,2))等价于type(A+B),其中A、B是int类型的,所以返回的结果也是int类型
4.test1.__new__(test1))的类型也是TestClass,从这里就知道test1.__new__(test1))==TestClass(),只是后者匿名对象
下面是对属性的分析:
1.由于我们已经通过上面对不同的调用方式对应的类型做了分析,在对属性进行分析时,就不再重复的去看,重点看1、2、4这三个对象的属性差异,通过上面的截图可知,比较有疑问的地方是在__call__()方法中的A、B属性,和__init__()方法的c属性,对于类中全局变量a应该不用多说,不管是类本身还是实例化的对象都会有这个变量,重点是在A、B、c这三个属性中,分成两类来说明:
1.1 先说A、B这两个属性,可能会有疑问,明明是在方法内部的属性,为什么类本身、实例化对象都能调用,在此需要说明下self的作用,python中self指代的本身:
1.1.1 先分析test1是类本身,此时self.A就相当于TestClass.A,所以test1中有A、B这两个属性
1.1.2 test1()是类的实例化对象,此时的self.A就相当于test1().A,所以也有A、B这两个属性
1.1.3 test1.__new__(test1)其实质是等于test1()的,所以不做多的解释
1.2 再说c属性,这里会有很大的疑问,不是说test1()等于 test1.__new__(test1),其实这里是存在问题,从类型上判断是可以等于的,但是实际python解释器在看到这两种方式的时候,会执行不同的步骤:
1.2.1 先说test1(),python解释器在看到这个的时候会调用__new__()方法,创建一个实例对象,但是之后还用调用__init__方法对这个对象初始化一个属性c,从这里可以看出,这两个是不等价的,这也是为什么test1.__new__(test1)中没有c的原因,至于实例对象的创建相关的在新的文章中说明
问题解答:
在文章开始说的test1.c会报错,那是因为test1指向的是TestClass类本身,而类本身有的属性包含上面全局变量、方法、及通过self.x的属性,__init__()是在实例化的时候将其中的属性初始化给对象,而类本身是没有这个属性的。
内置函数dir()的用法:
1.查看当前空间的属性和方法:dir()
2.查看具体对象的属性和方法:dir(test)
3.查看不同的数据类型的属性与方法:dir("")、dir([])、dir({})
4.查看某个模块的属性和方法,先将包导入到当前空间 在使用dir(package_name)
本文深入探讨Python中的__call__方法,通过实例解释其作用,如何使得类的对象可被调用。同时,文章分析了TestClass3()与test3()的区别,包括它们的类型和属性差异,并解答了为何test1.c会报错的问题。最后,介绍了内置函数dir()的多种用法。
834

被折叠的 条评论
为什么被折叠?



