Python的__call__特殊方法实际示例

7 浏览
0 Comments

Python的__call__特殊方法实际示例

我知道类中的__call__方法在调用类的实例时触发。然而,我不知道什么时候可以使用这个特殊方法,因为可以简单地创建一个新方法,执行__call__方法中完成的相同操作,而不是调用实例,而是调用该方法。\n如果有人给我一个实际使用这个特殊方法的例子,我将非常感激。

0
0 Comments

Python的特殊方法__call__允许我们创建易于使用的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')

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

闭包会破坏这个例子。pastebin.com/961vU0ay是80%的代码行数,但同样清晰易懂。我不确定对于某些人来说(例如那些只用过Java的人),它是否总是同样清晰。嵌套函数和变量查找/作用域可能会让人困惑。我想说的是,__call__给了你一个工具,让你可以使用面向对象的技术来解决问题。

好吧,原帖中明确要求我们为什么要创建一个带有__call__的类,而不是使用其他方法名。或者(问题中没有提到,但是同样的问题)为什么不使用闭包。(另外一件事,如果有人在使用Python并且不知道闭包,他们应该学习一下。我编写的代码是为了让那些了解这门语言的人容易阅读,而闭包是一个非常基本的概念,绝不是什么奇特的东西。)

我认为在两种提供相同功能的情况下,为什么使用X而不是Y这个问题是非常主观的。对于某些人来说,面向对象的方法更容易理解,而对于其他人来说,闭包方法更容易理解。没有令人信服的理由去选择其中一种,除非你有一种情况,必须使用isinstance或者类似的东西。

你的闭包示例代码行数更少,但是很难说它同样清晰易懂。

一个使用__call__方法而不是闭包的例子是当你使用multiprocessing模块处理多进程时,该模块使用pickle在进程间传递信息。你不能pickle一个闭包,但是你可以pickle一个类的实例。

闭包方法也放弃了继承的所有好处。

0
0 Comments

Python的特殊方法`__call__`提供了一种实现一致API的方式,可以用于表单验证。在Django的forms模块中,可以使用`__call__`方法来实现表单验证的一致性API。可以将自定义的验证器实现为一个函数,或者使用可调用的类来实现默认的正则表达式验证逻辑。

在Django中,通过可调用的类来实现默认的正则表达式验证逻辑,并通过继承这些类来实现其他验证逻辑。例如,`RegexValidator`是一个可调用的类,它实现了正则表达式验证逻辑,而`URLValidator`和`EmailValidator`则是通过继承`RegexValidator`类来扩展验证逻辑。

使用`__call__`方法,自定义的验证函数和内置的`EmailValidator`验证器可以使用相同的语法进行调用。这种实现方式使得代码更加可读,并且对于大型框架如Django来说,也更容易扩展。

虽然可以通过其他方式实现相同的功能,但是可能会使代码可读性下降。`__call__`方法的正确使用可以使代码更易读,但是如果在错误的地方使用,可能会导致代码非常难以理解。

需要注意的是,`__call__`方法的真正价值在于能够在需要可调用对象的地方使用实例。例如,在创建装饰器时经常使用`__call__`方法。在某些情况下,使用`__call__`方法可能并不是最佳选择,可以考虑使用接口或抽象类来明确方法的存在。

`__call__`方法提供了一种实现一致API的方式,可以使代码更加可读和易于扩展。但是需要注意在适当的地方使用,以免降低代码的可读性。

0
0 Comments

Python的特殊方法__call__允许将一个对象作为函数来调用。这个特殊方法在一些特定的情况下很有用,例如在实现可调用对象时。

在上面的示例中,我们使用了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 range(10):
    print("{}! = {}".format(i, fact(i)))

输出结果为:

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

这个例子展示了如何使用`__call__`方法创建一个可调用的对象,并且它还可以保持状态。但是,有人可能更倾向于将`fact`对象作为索引,因为`__call__`函数本质上是一个索引。也可以使用列表而不是字典来实现这个功能。

这个例子还可以用闭包来实现,代码会更短,更易读。

总之,Python的`__call__`特殊方法提供了一种创建可调用对象的方式,可以在某些特定的情况下非常有用。

0