Python __call__ 特殊方法实例

发布于 2024-11-04 03:41:30 字数 149 浏览 1 评论 0原文

我知道当调用类的实例时会触发类中的 __call__ 方法。但是,我不知道什么时候可以使用这种特殊方法,因为可以简单地创建一个新方法并执行在 __call__ 方法中完成的相同操作,而不是调用实例,您可以调用该方法。

如果有人给我这种特殊方法的实际用法,我将非常感激。

I know that __call__ method in a class is triggered when the instance of a class is called. However, I have no idea when I can use this special method, because one can simply create a new method and perform the same operation done in __call__ method and instead of calling the instance, you can call the method.

I would really appreciate it if someone gives me a practical usage of this special method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

奶气 2024-11-11 03:41:30

此示例使用 memoization,基本上将值存储在表中(在本例中为字典),以便您可以查看稍后再更新,而不是重新计算。

这里我们使用一个带有 __call__ 方法的简单类来计算阶乘(通过可调用对象)而不是包含静态变量的阶乘函数(因为这在 Python 中是不可能的)。

class Factorial:
    def __init__(self):
        self.cache = {}
    def __call__(self, n):
        if n not in self.cache:
            if n == 0:
                self.cache[n] = 1
            else:
                self.cache[n] = n * self.__call__(n-1)
        return self.cache[n]

fact = Factorial()

现在您有了一个可调用的 fact 对象,就像所有其他函数一样。例如

for i in xrange(10):                                                             
    print("{}! = {}".format(i, fact(i)))

# output
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880

并且它也是有状态的。

This example uses memoization, basically storing values in a table (dictionary in this case) so you can look them up later instead of recalculating them.

Here we use a simple class with a __call__ method to calculate factorials (through a callable object) instead of a factorial function that contains a static variable (as that's not possible in Python).

class Factorial:
    def __init__(self):
        self.cache = {}
    def __call__(self, n):
        if n not in self.cache:
            if n == 0:
                self.cache[n] = 1
            else:
                self.cache[n] = n * self.__call__(n-1)
        return self.cache[n]

fact = Factorial()

Now you have a fact object which is callable, just like every other function. For example

for i in xrange(10):                                                             
    print("{}! = {}".format(i, fact(i)))

# output
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880

And it is also stateful.

小情绪 2024-11-11 03:41:30

Django 表单模块很好地使用了 __call__ 方法来实现一致的表单验证 API。您可以为 Django 中的表单编写自己的验证器作为函数。

def custom_validator(value):
    #your validation logic

Django 有一些默认的内置验证器,例如电子邮件验证器、url 验证器等,它们大致属于 RegEx 验证器的范畴。为了干净地实现这些,Django 求助于可调用类(而不是函数)。它在 RegexValidator 中实现默认的 Regex 验证逻辑,然后扩展这些类以进行其他验证。

class RegexValidator(object):
    def __call__(self, value):
        # validation logic

class URLValidator(RegexValidator):
    def __call__(self, value):
        super(URLValidator, self).__call__(value)
        #additional logic

class EmailValidator(RegexValidator):
    # some logic

现在,您的自定义函数和内置 EmailValidator 都可以使用相同的语法进行调用。

for v in [custom_validator, EmailValidator()]:
    v(value) # <-----

正如您所看到的,Django 中的这种实现与其他人在下面的答案中解释的类似。这可以通过其他方式实现吗?你可以,但恕我直言,对于像 Django 这样的大型框架来说,它的可读性或可扩展性不那么容易。

Django forms module uses __call__ method nicely to implement a consistent API for form validation. You can write your own validator for a form in Django as a function.

def custom_validator(value):
    #your validation logic

Django has some default built-in validators such as email validators, url validators etc., which broadly fall under the umbrella of RegEx validators. To implement these cleanly, Django resorts to callable classes (instead of functions). It implements default Regex Validation logic in a RegexValidator and then extends these classes for other validations.

class RegexValidator(object):
    def __call__(self, value):
        # validation logic

class URLValidator(RegexValidator):
    def __call__(self, value):
        super(URLValidator, self).__call__(value)
        #additional logic

class EmailValidator(RegexValidator):
    # some logic

Now both your custom function and built-in EmailValidator can be called with the same syntax.

for v in [custom_validator, EmailValidator()]:
    v(value) # <-----

As you can see, this implementation in Django is similar to what others have explained in their answers below. Can this be implemented in any other way? You could, but IMHO it will not be as readable or as easily extensible for a big framework like Django.

被翻牌 2024-11-11 03:41:30

我发现它很有用,因为它允许我创建易于使用的 API(您有一些需要某些特定参数的可调用对象),并且易于实现,因为您可以使用面向对象的实践。

以下是我昨天编写的代码,它生成了 hashlib.foo 方法的一个版本,该方法对整个文件而不是字符串进行哈希处理:

# filehash.py
import hashlib


class Hasher(object):
    """
    A wrapper around the hashlib hash algorithms that allows an entire file to
    be hashed in a chunked manner.
    """
    def __init__(self, algorithm):
        self.algorithm = algorithm

    def __call__(self, file):
        hash = self.algorithm()
        with open(file, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), ''):
                hash.update(chunk)
        return hash.hexdigest()


md5    = Hasher(hashlib.md5)
sha1   = Hasher(hashlib.sha1)
sha224 = Hasher(hashlib.sha224)
sha256 = Hasher(hashlib.sha256)
sha384 = Hasher(hashlib.sha384)
sha512 = Hasher(hashlib.sha512)

此实现允许我以与 hashlib 类似的方式使用这些函数.foo 函数:

from filehash import sha1
print sha1('somefile.txt')

当然我可以用不同的方式实现它,但在这种情况下,它似乎是一个简单的方法。

I find it useful because it allows me to create APIs that are easy to use (you have some callable object that requires some specific arguments), and are easy to implement because you can use Object Oriented practices.

The following is code I wrote yesterday that makes a version of the hashlib.foo methods that hash entire files rather than strings:

# filehash.py
import hashlib


class Hasher(object):
    """
    A wrapper around the hashlib hash algorithms that allows an entire file to
    be hashed in a chunked manner.
    """
    def __init__(self, algorithm):
        self.algorithm = algorithm

    def __call__(self, file):
        hash = self.algorithm()
        with open(file, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), ''):
                hash.update(chunk)
        return hash.hexdigest()


md5    = Hasher(hashlib.md5)
sha1   = Hasher(hashlib.sha1)
sha224 = Hasher(hashlib.sha224)
sha256 = Hasher(hashlib.sha256)
sha384 = Hasher(hashlib.sha384)
sha512 = Hasher(hashlib.sha512)

This implementation allows me to use the functions in a similar fashion to the hashlib.foo functions:

from filehash import sha1
print sha1('somefile.txt')

Of course I could have implemented it a different way, but in this case it seemed like a simple approach.

德意的啸 2024-11-11 03:41:30

__call__ 还用于在 python 中实现装饰器类。在这种情况下,当调用带有装饰器的方法时,将调用该类的实例。

class EnterExitParam(object):

    def __init__(self, p1):
        self.p1 = p1

    def __call__(self, f):
        def new_f():
            print("Entering", f.__name__)
            print("p1=", self.p1)
            f()
            print("Leaving", f.__name__)
        return new_f


@EnterExitParam("foo bar")
def hello():
    print("Hello")


if __name__ == "__main__":
    hello()

程序输出:

Entering hello
p1= foo bar
Hello
Leaving hello

__call__ is also used to implement decorator classes in python. In this case the instance of the class is called when the method with the decorator is called.

class EnterExitParam(object):

    def __init__(self, p1):
        self.p1 = p1

    def __call__(self, f):
        def new_f():
            print("Entering", f.__name__)
            print("p1=", self.p1)
            f()
            print("Leaving", f.__name__)
        return new_f


@EnterExitParam("foo bar")
def hello():
    print("Hello")


if __name__ == "__main__":
    hello()

program output:

Entering hello
p1= foo bar
Hello
Leaving hello
星星的軌跡 2024-11-11 03:41:30

是的,当您知道自己正在处理对象时,完全有可能(并且在许多情况下建议)使用显式方法调用。然而,有时您处理的代码需要可调用对象(通常是函数),但借助 __call__ ,您可以构建更复杂的对象,使用实例数据和更多方法来委托仍然可调用的重复任务等。

此外,有时您会同时使用对象来执行复杂任务(在这种情况下编写专用类是有意义的)和对象来执行简单任务(已经存在于函数中,或者更容易编写为函数)。要拥有一个通用接口,您要么必须编写使用预期接口包装这些函数的小类,要么保留函数的功能并使更复杂的对象可调用。我们以线程为例。标准库模块 中的 Thread 对象线程想要一个可调用的目标参数(即作为在新线程中完成的操作)。使用可调用对象,您不仅限于函数,还可以传递其他对象,例如相对复杂的工作程序,它从其他线程获取要执行的任务并按顺序执行它们:

class Worker(object):
    def __init__(self, *args, **kwargs):
        self.queue = queue.Queue()
        self.args = args
        self.kwargs = kwargs

    def add_task(self, task):
        self.queue.put(task)

    def __call__(self):
        while True:
            next_action = self.queue.get()
            success = next_action(*self.args, **self.kwargs)
            if not success:
               self.add_task(next_action)

这只是我脑海中的一个示例,但我认为它已经足够复杂,足以保证上课。仅使用函数来执行此操作很困难,至少它需要返回两个函数,而且这会慢慢变得复杂。 可以__call__重命名为其他名称并传递绑定方法,但这使得创建线程的代码稍微不那么明显,并且不会增加任何价值。

Yes, when you know you're dealing with objects, it's perfectly possible (and in many cases advisable) to use an explicit method call. However, sometimes you deal with code that expects callable objects - typically functions, but thanks to __call__ you can build more complex objects, with instance data and more methods to delegate repetitive tasks, etc. that are still callable.

Also, sometimes you're using both objects for complex tasks (where it makes sense to write a dedicated class) and objects for simple tasks (that already exist in functions, or are more easily written as functions). To have a common interface, you either have to write tiny classes wrapping those functions with the expected interface, or you keep the functions functions and make the more complex objects callable. Let's take threads as example. The Thread objects from the standard libary module threading want a callable as target argument (i.e. as action to be done in the new thread). With a callable object, you are not restricted to functions, you can pass other objects as well, such as a relatively complex worker that gets tasks to do from other threads and executes them sequentially:

class Worker(object):
    def __init__(self, *args, **kwargs):
        self.queue = queue.Queue()
        self.args = args
        self.kwargs = kwargs

    def add_task(self, task):
        self.queue.put(task)

    def __call__(self):
        while True:
            next_action = self.queue.get()
            success = next_action(*self.args, **self.kwargs)
            if not success:
               self.add_task(next_action)

This is just an example off the top of my head, but I think it is already complex enough to warrant the class. Doing this only with functions is hard, at least it requires returning two functions and that's slowly getting complex. One could rename __call__ to something else and pass a bound method, but that makes the code creating the thread slightly less obvious, and doesn't add any value.

萧瑟寒风 2024-11-11 03:41:30

基于类的装饰器使用 __call__ 来引用包装的函数。例如:

class Deco(object):
    def __init__(self,f):
        self.f = f
    def __call__(self, *args, **kwargs):
        print args
        print kwargs
        self.f(*args, **kwargs)

Artima.com

Class-based decorators use __call__ to reference the wrapped function. E.g.:

class Deco(object):
    def __init__(self,f):
        self.f = f
    def __call__(self, *args, **kwargs):
        print args
        print kwargs
        self.f(*args, **kwargs)

There is a good description of the various options here at Artima.com

万水千山粽是情ミ 2024-11-11 03:41:30

恕我直言,__call__ 方法和闭包为我们提供了一种在 Python 中创建 STRATEGY 设计模式的自然方法。我们定义一系列算法,封装每个算法,使它们可以互换,最后我们可以执行一组通用的步骤,例如计算文件的哈希值。

IMHO __call__ method and closures give us a natural way to create STRATEGY design pattern in Python. We define a family of algorithms, encapsulate each one, make them interchangeable and in the end we can execute a common set of steps and, for example, calculate a hash for a file.

恋竹姑娘 2024-11-11 03:41:30

我刚刚偶然发现了 __call__() 与 __getattr__() 的配合使用,我认为这很漂亮。它允许您在对象内隐藏多个级别的 JSON/HTTP/(however_serialized) API。

__getattr__() 部分负责迭代地返回同一类的修改实例,一次填充一个或多个属性。然后,在用尽所有信息后,__call__() 接管您传入的任何参数。

使用此模型,您可以进行像 api.v2.volumes.ssd 这样的调用.update(size=20),最终形成对 https://some.tld/api/v2/volumes/ssd/update 的 PUT 请求。

具体代码是 OpenStack 中某个卷后端的块存储驱动程序,您可以在这里查看:https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py

编辑:更新了链接以指向主修订版。

I just stumbled upon a usage of __call__() in concert with __getattr__() which I think is beautiful. It allows you to hide multiple levels of a JSON/HTTP/(however_serialized) API inside an object.

The __getattr__() part takes care of iteratively returning a modified instance of the same class, filling in one more attribute at a time. Then, after all information has been exhausted, __call__() takes over with whatever arguments you passed in.

Using this model, you can for example make a call like api.v2.volumes.ssd.update(size=20), which ends up in a PUT request to https://some.tld/api/v2/volumes/ssd/update.

The particular code is a block storage driver for a certain volume backend in OpenStack, you can check it out here: https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py

EDIT: Updated the link to point to master revision.

小忆控 2024-11-11 03:41:30

我发现使用可调用对象的好地方,即那些定义 __call__() 的对象,是在使用 Python 中的函数式编程功能时,例如 map()过滤器(),减少()。

在普通函数或 lambda 函数上使用可调用对象的最佳时机是当逻辑复杂并且需要保留某些状态或使用未传递给 __call__() 函数的其他信息时。

下面是一些使用可调用对象和 filter() 根据文件扩展名过滤文件名的代码。

可调用:

import os

class FileAcceptor(object):
    def __init__(self, accepted_extensions):
        self.accepted_extensions = accepted_extensions

    def __call__(self, filename):
        base, ext = os.path.splitext(filename)
        return ext in self.accepted_extensions

class ImageFileAcceptor(FileAcceptor):
    def __init__(self):
        image_extensions = ('.jpg', '.jpeg', '.gif', '.bmp')
        super(ImageFileAcceptor, self).__init__(image_extensions)

用法:

filenames = [
    'me.jpg',
    'me.txt',
    'friend1.jpg',
    'friend2.bmp',
    'you.jpeg',
    'you.xml']

acceptor = ImageFileAcceptor()
image_filenames = filter(acceptor, filenames)
print image_filenames

输出:

['me.jpg', 'friend1.jpg', 'friend2.bmp', 'you.jpeg']

I find a good place to use callable objects, those that define __call__(), is when using the functional programming capabilities in Python, such as map(), filter(), reduce().

The best time to use a callable object over a plain function or a lambda function is when the logic is complex and needs to retain some state or uses other info that in not passed to the __call__() function.

Here's some code that filters file names based upon their filename extension using a callable object and filter().

Callable:

import os

class FileAcceptor(object):
    def __init__(self, accepted_extensions):
        self.accepted_extensions = accepted_extensions

    def __call__(self, filename):
        base, ext = os.path.splitext(filename)
        return ext in self.accepted_extensions

class ImageFileAcceptor(FileAcceptor):
    def __init__(self):
        image_extensions = ('.jpg', '.jpeg', '.gif', '.bmp')
        super(ImageFileAcceptor, self).__init__(image_extensions)

Usage:

filenames = [
    'me.jpg',
    'me.txt',
    'friend1.jpg',
    'friend2.bmp',
    'you.jpeg',
    'you.xml']

acceptor = ImageFileAcceptor()
image_filenames = filter(acceptor, filenames)
print image_filenames

Output:

['me.jpg', 'friend1.jpg', 'friend2.bmp', 'you.jpeg']
℡Ms空城旧梦 2024-11-11 03:41:30

我是新手,但我的看法是:使用 __call__ 使组合更容易编码。如果 f, g 是具有方法 eval(self,x) 的类 Function 的实例,则使用 __call___ code> 可以写成 f(g(x)) 而不是 f.eval(g.eval(x))

神经网络可以由较小的神经网络组成,在 pytorch 中,我们的 Module 类中有一个 __call__ :

这是在实践中使用 __call__ 的示例:在 pytorch 中,当定义一个神经网络(例如,将其称为 class MyNN(nn.Module))作为 torch.nn.module.Module 的子类时,通常会定义一个 forward类的方法,但通常当将输入张量 x 应用于实例 model=MyNN() 时,我们只需编写 model(x) 而不是 model.forward(x) 但两者都给出相同的答案。如果您在此处深入了解 torch.nn.module.Module 的源代码

https://pytorch.org/docs/stable/_modules/torch/nn/modules/module.html#Module

并搜索 __call__ 最终可以追溯到 -至少在某些情况下 - 对 self.forward 的调用

import torch.nn as nn
import torch.nn.functional as F

class MyNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer1 = nn.Linear(784, 200)



    def forward(self, x):
        return F.ReLU(self.layer1(x))

x=torch.rand(10,784)
model=MyNN()
print(model(x))
print(model.forward(x))

将在最后两行打印相同的值,因为 Module 类已经实现了 __call___ 所以这就是我相信的 Python当它看到 model(x)__call__ 时转向,最终调用 model.forward(x))

I'm a novice, but here is my take: having __call__ makes composition easier to code. If f, g are instance of a class Function that has a method eval(self,x), then with __call___ one could write f(g(x)) as opposed to f.eval(g.eval(x)).

A neural network can be composed from smaller neural networks, and in pytorch we have a __call__ in the Module class:

Here's an example of where __call__ is used in practice: in pytorch, when defining a neural network (call it class MyNN(nn.Module) for example) as a subclass of torch.nn.module.Module, one typically defines a forward method for the class, but typically when applying an input tensor x to an instance model=MyNN() we just write model(x) as opposed to model.forward(x) but both give the same answer. If you dig into the source for torch.nn.module.Module here

https://pytorch.org/docs/stable/_modules/torch/nn/modules/module.html#Module

and search for __call__ one can eventually trace it back - at least in some cases - to a call to self.forward

import torch.nn as nn
import torch.nn.functional as F

class MyNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer1 = nn.Linear(784, 200)



    def forward(self, x):
        return F.ReLU(self.layer1(x))

x=torch.rand(10,784)
model=MyNN()
print(model(x))
print(model.forward(x))

will print the same values in the last two lines as the Module class has implemented __call___ so that's what I believe Python turns to when it sees model(x), and the __call__ which in turn eventually calls model.forward(x))

红衣飘飘貌似仙 2024-11-11 03:41:30

指定一个 __metaclass__ 并重写 __call__ 方法,并让指定元类的 __new__ 方法返回该类的实例,中提琴你有一个“功能”与方法。

Specify a __metaclass__ and override the __call__ method, and have the specified meta classes' __new__ method return an instance of the class, viola you have a "function" with methods.

离笑几人歌 2024-11-11 03:41:30

我们可以使用__call__方法将其他类方法用作静态方法。

    class _Callable:
        def __init__(self, anycallable):
            self.__call__ = anycallable

    class Model:

        def get_instance(conn, table_name):

            """ do something"""

        get_instance = _Callable(get_instance)

    provs_fac = Model.get_instance(connection, "users")             

We can use __call__ method to use other class methods as static methods.

    class _Callable:
        def __init__(self, anycallable):
            self.__call__ = anycallable

    class Model:

        def get_instance(conn, table_name):

            """ do something"""

        get_instance = _Callable(get_instance)

    provs_fac = Model.get_instance(connection, "users")             
回忆那么伤 2024-11-11 03:41:30

一个常见的例子是 functools.partial 中的 __call__ ,这是一个简化版本(Python >= 3.5):

class partial:
    """New function with partial application of the given arguments and keywords."""

    def __new__(cls, func, *args, **kwargs):
        if not callable(func):
            raise TypeError("the first argument must be callable")
        self = super().__new__(cls)

        self.func = func
        self.args = args
        self.kwargs = kwargs
        return self

    def __call__(self, *args, **kwargs):
        return self.func(*self.args, *args, **self.kwargs, **kwargs)

用法:

def add(x, y):
    return x + y

inc = partial(add, y=1)
print(inc(41))  # 42

One common example is the __call__ in functools.partial, here is a simplified version (with Python >= 3.5):

class partial:
    """New function with partial application of the given arguments and keywords."""

    def __new__(cls, func, *args, **kwargs):
        if not callable(func):
            raise TypeError("the first argument must be callable")
        self = super().__new__(cls)

        self.func = func
        self.args = args
        self.kwargs = kwargs
        return self

    def __call__(self, *args, **kwargs):
        return self.func(*self.args, *args, **self.kwargs, **kwargs)

Usage:

def add(x, y):
    return x + y

inc = partial(add, y=1)
print(inc(41))  # 42
攒眉千度 2024-11-11 03:41:30

这已经太晚了,但我举了一个例子。假设您有一个 Vector 类和 Point 类。两者都采用 x, y 作为位置参数。假设您想要创建一个函数来移动要放在向量上的点。

4 解决方案

  • put_point_on_vec(point, vec)

  • 使其成为向量类上的方法。 eg my_vec.put_point(point)

  • 使其成为 Point 类上的方法。 my_point.put_on_vec(vec)
  • Vector 实现了 __call__,所以你可以像 my_vec_instance(point) 一样使用它,

这是实际上,我正在编写一些示例的一部分,以获取用数学解释的 dunder 方法指南,我迟早会发布它。

我留下了移动点本身的逻辑,因为这不是这个问题的目的

This is too late but I'm giving an example. Imagine you have a Vector class and a Point class. Both take x, y as positional args. Let's imagine you want to create a function that moves the point to be put on the vector.

4 Solutions

  • put_point_on_vec(point, vec)

  • Make it a method on the vector class. e.g my_vec.put_point(point)

  • Make it a method on the Point class. my_point.put_on_vec(vec)
  • Vector implements __call__, So you can use it like my_vec_instance(point)

This is actually part of some examples I'm working on for a guide for dunder methods explained with Maths that I'm gonna release sooner or later.

I left the logic of moving the point itself because this is not what this question is about

澜川若宁 2024-11-11 03:41:30

函数调用运算符。

class Foo:
    def __call__(self, a, b, c):
        # do something

x = Foo()
x(1, 2, 3)

__call__ 方法可用于重新定义/重新初始化同一对象。它还通过将参数传递给对象来促进将类的实例/对象用作函数。

The function call operator.

class Foo:
    def __call__(self, a, b, c):
        # do something

x = Foo()
x(1, 2, 3)

The __call__ method can be used to redefined/re-initialize the same object. It also facilitates the use of instances/objects of a class as functions by passing arguments to the objects.

空名 2024-11-11 03:41:30
import random


class Bingo:

def __init__(self,items):
    self._items=list(items)
    random.shuffle(self._items,random=None)


def pick(self):
    try:
        return self._items.pop()
    except IndexError:
        raise LookupError('It is empty now!')

def __call__(self):
    return self.pick()

b= Bingo(range(3))
print(b.pick())
print(b())
print(callable(b))

现在输出可以是..(因为前两个答案不断在 [0,3] 之间移动)

2

1

True


您可以看到 Class Bingo 实现了 _call_ 方法,这是创建类似函数的简单方法具有必须在调用之间保留的内部状态的对象,例如 Bingo 中的剩余项目。 _call_ 的另一个很好的用例是装饰器。装饰器必须是可调用的,有时“记住”很方便
装饰器调用之间的一些东西。 (即,记忆化 - 缓存昂贵的计算结果以供以后使用。)

import random


class Bingo:

def __init__(self,items):
    self._items=list(items)
    random.shuffle(self._items,random=None)


def pick(self):
    try:
        return self._items.pop()
    except IndexError:
        raise LookupError('It is empty now!')

def __call__(self):
    return self.pick()

b= Bingo(range(3))
print(b.pick())
print(b())
print(callable(b))

Now the output can be..(As first two answer keeps shuffling between [0,3])

2

1

True


You can see that Class Bingo implements _call_ method, an easy way to create a function like objects that have an internal state that must be kept across invocations like remaining items in Bingo. Another good use case of _call_ is Decorators. Decorators must be callable and it is sometimes convenient to "remember"
something between calls of decorators. (i.e., memoization- caching the results of expensive computation for later use.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文