Python __call__ special method practical example
我知道类中的
如果有人给我这个特殊方法的实际用法,我会非常感激的。
型
这个例子使用memoization,基本上是将值存储在一个表中(本例中是字典),这样您以后就可以查找它们,而不是重新计算它们。
这里我们使用一个带有
1 2 3 4 5 6 7 8 9 10 11 12 | 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() |
现在您有了一个可调用的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
号
它也是庄严的。
型
Django表单模块很好地使用
1 2 | def custom_validator(value): #your validation logic |
。
Django有一些默认的内置验证器,如电子邮件验证器、URL验证器等,这些验证器大体上属于regex验证器的保护范围。为了干净地实现这些,Django使用可调用类(而不是函数)。它在regexvalidator中实现默认的regex验证逻辑,然后扩展这些类以进行其他验证。
1 2 3 4 5 6 7 8 9 10 11 | 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。
1 2 | for v in [custom_validator, EmailValidator()]: v(value) # <----- |
。
如您所见,Django中的这个实现类似于其他人在下面的答案中所解释的。这能以任何其他方式实现吗?您可以,但imho对于像Django这样的大型框架来说,它的可读性和可扩展性都不高。
型
我发现它很有用,因为它允许我创建易于使用的API(您有一些需要一些特定参数的可调用对象),并且易于实现,因为您可以使用面向对象的实践。
下面是我昨天编写的代码,它生成了一个版本的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # 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) |
此实现允许我以与
1 2 | from filehash import sha1 print sha1('somefile.txt') |
。
当然,我可以用不同的方式实现它,但在本例中,它看起来像是一种简单的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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() |
型
是的,当您知道要处理对象时,使用显式方法调用是完全可能的(而且在许多情况下是明智的)。但是,有时处理期望可调用对象的代码——通常是函数,但是由于
此外,有时您将对象用于复杂任务(在这里编写专用类很有意义),将对象用于简单任务(已经存在于函数中,或者更容易编写为函数)。要有一个公共接口,要么编写用预期接口包装这些函数的小类,要么保留函数函数并使更复杂的对象可调用。让我们以线程为例。来自标准libary模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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) |
这只是我头脑中的一个例子,但我认为它已经足够复杂,足以证明这门课。只对函数执行此操作是困难的,至少需要返回两个函数,这会慢慢变得复杂。可以将
型
基于类的修饰符使用
1 2 3 4 5 6 7 | 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上可以很好地描述各种选项。
我只是偶然发现了一种使用
使用此模型,您可以进行一个类似于
特定代码是OpenStack中某个卷后端的块存储驱动程序,您可以在这里查看:https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py
编辑:更新链接指向主版本。
型
imho
我们可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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") |
指定一个
我发现使用可调用对象(定义
在普通函数或lambda函数上使用可调用对象的最佳时间是逻辑复杂,需要保留某些状态或使用未传递给
下面是一些使用可调用对象和
Callable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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) |
用途:
1 2 3 4 5 6 7 8 9 10 11 | filenames = [ 'me.jpg', 'me.txt', 'friend1.jpg', 'friend2.bmp', 'you.jpeg', 'you.xml'] acceptor = ImageFileAcceptor() image_filenames = filter(acceptor, filenames) print image_filenames |
输出:
1 | ['me.jpg', 'friend1.jpg', 'friend2.bmp', 'you.jpeg'] |
函数调用运算符。
ZZU1〔4〕
_uuu call_uuu方法可用于重新定义/重新初始化同一对象。它还通过向对象传递参数,方便将类的实例/对象用作函数。
一个常见的例子是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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) |
用途:
1 2 3 4 5 | def add(x, y): return x + y inc = partial(add, y=1) print(inc(41)) # 42 |