什么是“可调用”?

2024-12-02 08:41:00
admin
原创
179
摘要:问题描述:现在已经清楚了什么是元类,有一个相关概念我一直使用但不知道它真正的含义。我想每个人都曾经犯过使用括号的错误,导致出现“对象不可调用”异常。更重要的是,使用__init__和__new__会导致想知道这个该死的__call__能用来做什么。你能给我一些解释吗,包括使用魔法方法的例子?解决方案 1:可调...

问题描述:

现在已经清楚了什么是元类,有一个相关概念我一直使用但不知道它真正的含义。

我想每个人都曾经犯过使用括号的错误,导致出现“对象不可调用”异常。更重要的是,使用__init____new__会导致想知道这个该死的__call__能用来做什么。

你能给我一些解释吗,包括使用魔法方法的例子?


解决方案 1:

可调用对象是指任何能够被调用的东西。

内置可调用函数(objects.c 中的 PyCallable_Check)检查参数是否为:

  • 具有方法的类的实例__call__

  • 是一种具有非空tp_call (c 结构)成员的类型,该成员指示可调用性(例如在函数、方法等中)

命名的方法__call__是(根据文档)

当实例作为函数被“调用”时调用

例子

class Foo:
  def __call__(self):
    print 'called'

foo_instance = Foo()
foo_instance() #this is calling the __call__ method

解决方案 2:

来自Python的源代码object.c:

/* Test whether an object can be called */

int
PyCallable_Check(PyObject *x)
{
    if (x == NULL)
        return 0;
    if (PyInstance_Check(x)) {
        PyObject *call = PyObject_GetAttrString(x, "__call__");
        if (call == NULL) {
            PyErr_Clear();
            return 0;
        }
        /* Could test recursively but don't, for fear of endless
           recursion if some joker sets self.__call__ = self */
        Py_DECREF(call);
        return 1;
    }
    else {
        return x->ob_type->tp_call != NULL;
    }
}

它说:

  1. 如果一个对象是某个类的实例,那么当且仅当它具有属性__call__它才是可调用的。

  2. 否则该对象x可调用当且仅当 x->ob_type->tp_call != NULL

tp_call字段描述:

ternaryfunc tp_call指向实现调用对象的函数的可选指针。如果对象不可调用,则应为 NULL。签名与 PyObject_Call() 相同。此字段由子类型继承。

您始终可以使用内置callable函数来确定给定对象是否可调用;或者更好的是,直接调用它并TypeError稍后捕获。callable在 Python 3.0 和 3.1 中被删除,请使用callable = lambda o: hasattr(o, '__call__')isinstance(o, collections.Callable)

例如,一个简单的缓存实现:

class Cached:
    def __init__(self, function):
        self.function = function
        self.cache = {}

    def __call__(self, *args):
        try: return self.cache[args]
        except KeyError:
            ret = self.cache[args] = self.function(*args)
            return ret    

用法:

@Cached
def ack(x, y):
    return ack(x-1, ack(x, y-1)) if x*y else (x + y + 1) 

标准库中的示例,文件site.py,内置exit()quit()函数的定义:

class Quitter(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Use %s() or %s to exit' % (self.name, eof)
    def __call__(self, code=None):
        # Shells like IDLE catch the SystemExit, but listen when their
        # stdin wrapper is closed.
        try:
            sys.stdin.close()
        except:
            pass
        raise SystemExit(code)
__builtin__.quit = Quitter('quit')
__builtin__.exit = Quitter('exit')

解决方案 3:

可调用对象允许您使用圆括号()并最终传递一些参数,就像函数一样。

每次定义函数时,python 都会创建一个可调用对象。例如,您可以按以下方式定义函数func(相同):

class a(object):
    def __call__(self, *args):
        print 'Hello'

func = a()

# or ... 
def func(*args):
    print 'Hello'

您可以使用此方法,而不是doitrun之类的方法,我认为 obj() 比 obj.doit() 更清晰

解决方案 4:

让我反过来解释一下:

考虑一下这个...

foo()

... 作为语法糖:

foo.__call__()

其中foo可以是任何响应的对象__call__。当我说任何对象时,我指的是:内置类型、您自己的类及其实例。

对于内置类型,当你编写:

int('10')
unicode(10)

你实际上是在做:

int.__call__('10')
unicode.__call__(10)

这也是为什么在 Python 中不需要foo = new int:你只需让类对象在 上返回它的一个实例即可__call__。我认为 Python 解决这个问题的方式非常优雅。

解决方案 5:

__call__使任何对象都可以作为函数调用。

此示例将输出 8:

class Adder(object):
  def __init__(self, val):
    self.val = val

  def __call__(self, val):
    return self.val + val

func = Adder(5)
print func(3)

解决方案 6:

Callable 是具有__call__方法的对象。这意味着您可以伪造可调用函数或做一些巧妙的事情,例如部分函数应用,即获取一个函数并添加一些内容来增强它或填充一些参数,然后返回可以依次调用的内容(在函数式编程圈中称为Currying )。

某些输入错误会导致解释器尝试调用您不想要的内容,例如字符串。当解释器尝试执行不可调用的应用程序时,这可能会产生错误。您可以通过执行类似下面的脚本在 Python 解释器中看到这种情况。

[nigel@k9 ~]$ python
Python 2.5 (r25:51908, Nov  6 2007, 15:55:44) 
[GCC 4.1.2 20070925 (Red Hat 4.1.2-27)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'aaa'()    # <== Here we attempt to call a string.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
>>> 

解决方案 7:

简单来说,“可调用”是指可以像方法一样调用的东西。内置函数“callable()”会告诉您某事物是否可调用,并检查调用属性。函数是可调用的,类也是可调用的,类实例也是可调用的。有关更多信息,请参见此处和此处。

解决方案 8:

在 Python 中,可调用对象是一种具有以下方法的对象__call__

>>> class Foo:
...  pass
... 
>>> class Bar(object):
...  pass
... 
>>> type(Foo).__call__(Foo)
<__main__.Foo instance at 0x711440>
>>> type(Bar).__call__(Bar)
<__main__.Bar object at 0x712110>
>>> def foo(bar):
...  return bar
... 
>>> type(foo).__call__(foo, 42)
42

就这么简单:)

这当然可以被重载:

>>> class Foo(object):
...  def __call__(self):
...   return 42
... 
>>> f = Foo()
>>> f()
42

解决方案 9:

你可以将“(args)”放在它后面并期望它能工作。可调用函数通常是一种方法或一个类。方法被调用,类被实例化。

解决方案 10:

检查类的函数或方法是否可调用,意味着我们可以调用该函数。

Class A:
    def __init__(self,val):
        self.val = val
    def bar(self):
        print "bar"

obj = A()      
callable(obj.bar)
True
callable(obj.__init___)
False
def foo(): return "s"
callable(foo)
True
callable(foo())
False

解决方案 11:

可调用对象实现了__call__特殊方法,因此任何具有此类方法的对象都是可调用的。

解决方案 12:

Callable 是具有方法调用的“内置函数或方法”的类型或类

>>> type(callable)
<class 'builtin_function_or_method'>
>>>

例如:
print是一个可调用对象。使用内置函数调用
调用print函数时,Python 会创建一个print 类型的对象并调用其方法调用,并传递参数(如果有)。

>>> type(print)
<class 'builtin_function_or_method'>
>>> print.__call__(10)
10
>>> print(10)
10
>>>

解决方案 13:

__call__()具有可调用性的类、函数、方法和对象。

您可以使用callable()检查是否可以调用,如果可调用则返回True,如果不可调用则返回,False如下所示:

class Class1:
    def __call__(self):
        print("__call__")

class Class2:
    pass

def func():
    pass

print(callable(Class1))   # Class1
print(callable(Class2))   # Class2

print(callable(Class1())) # Class1 object
print(callable(Class2())) # Class2 object

print(callable(func))     # func

然后,只有没有可调用的Class2对象__call__()才返回,False如下所示:

True  # Class1
True  # Class2
True  # Class1 object
False # Class2 object
True  # func

此外,下面所有这些都不是可调用返回的,False如下所示:

print(callable("Hello"))  # "str" type
print(callable(100))      # "int" type
print(callable(100.23))   # "float" type
print(callable(100 + 2j)) # "complex" type
print(callable(True))     # "bool" type
print(callable(None))     # "NoneType"
print(callable([]))       # "list" type
print(callable(()))       # "tuple" type
print(callable({}))       # "dict" type
print(callable({""}))     # "set" type

输出:

False # "str" type
False # "int" type
False # "float" type
False # "complex" type
False # "bool" type
False # "NoneType"
False # "list" type
False # "tuple" type
False # "dict" type
False # "set" type
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用