python __call__(可调用对象理解)

@[TOC](python call(可调用对象理解))

前言

在Python中,方法也是一种高等的对象(python:万物皆对象)。我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable。如果在类中实现了 __call__方法,那么实例对象也将成为一个可调用对象。我们可以自定义可调用对象,比如pytorch中的nn.Module类就是利用了__call__实现了实例的可调用。

model=nn.Module()
model(x)

实际上在Module里实现了__call__,并调用了forward函数,进行前向传播。

具体说明

允许一个类的实例像函数一样被调用。实质上说,这意味着 x()x.__call__()是相同的。注意 __call__ 参数可变。这意味着你可以定义__call__为其他你想要的函数,无论有多少个参数。__call__在那些类的实例经常改变状态的时候会非常有效。调用这个实例是一种改变这个对象状态的直接和优雅的做法。用一个实例来表达最好不过了:

class Entity(object):
    '''调用实体来改变实体的位置。'''

    def __init__(self, size, x, y):
        self.x, self.y = x, y
        self.size = size

    def __call__(self, x, y):
        '''改变实体的位置'''
        self.x, self.y = x, y
        
e = Entity(1, 2, 3)
e(4, 5)

实际上,每一个可调用对象都有一个__call__方法。比如我随便定义一个函数,然后通过两种方式来调用它:

def print_msg(msg):
    print(msg)


print_msg.__call__('hello')
print('hello')

结果是一样的。

同时,用 call() 弥补 hasattr() 函数的短板。 hasattr() 函数的功能是查找类的实例对象中是否包含指定名称的属性或者方法,但该函数有一个缺陷,即它无法判断该指定的名称,到底是类属性还是类方法。
要解决这个问题,我们可以借助可调用对象的概念。要知道,类实例对象包含的方法,其实也属于可调用对象,但类属性却不是。举个例子

class CLanguage:
    def __init__ (self):
        self.name = "C语言中文网"
        self.add = "http://c.biancheng.net"
    def say(self):
        print("我正在学Python")
clangs = CLanguage()
if hasattr(clangs,"name"):
    print(hasattr(clangs.name,"__call__"))
print("**********")
if hasattr(clangs,"say"):
    print(hasattr(clangs.say,"__call__"))
程序执行结果为:
False
**********
True

可以看到,由于 name 是类属性,它没有以 call 为名的 call() 方法;而 say 是类方法,它是可调用对象,因此它有 call() 方法。

另外,我们可以通过__call__中调用我们想要调用的方法。参数传递可以利用*args**kwards

class Entity(object):
    '''调用实体来改变实体的位置。'''

    def __init__(self, x,y):
        self.x,self.y=x,y

    def __call__(self, *args,**kwargs):
        '''改变实体的位置'''
        self.change_loc(*args,**kwargs)

    def change_loc(self,*args,**kwargs):
        self.x,self.y=args[0],args[1]
        print(self.x,self.y)


e = Entity(1, 2)
e(4, 5)
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值