Maison  >  Article  >  développement back-end  >  python decorator - une méthode pour limiter le nombre d'appels de fonction (appel une fois toutes les 10 secondes)

python decorator - une méthode pour limiter le nombre d'appels de fonction (appel une fois toutes les 10 secondes)

不言
不言original
2018-04-21 14:34:592392parcourir

Ce qui suit est un décorateur python - une méthode pour limiter le nombre d'appels de fonction (appel une fois toutes les 10 secondes). Il a une bonne valeur de référence et j'espère qu'il sera utile à tout le monde. Jetons un coup d'œil ensemble

Il s'agit d'une récente question d'entretien d'un blogueur d'une grande entreprise Écrivez à un décorateur et limitez l'appel de la fonction une fois toutes les 10 secondes. C'était un test écrit à l'époque, et je n'écrivais qu'un code approximatif. Après mon retour, j'ai révisé les connaissances de base des décorateurs Python et j'ai fini d'écrire le code. J'ai décidé d'écrire un blog pour l'enregistrer.

Les décorateurs sont divisés en décorateurs avec paramètres et décorateurs sans paramètres.

#不带参数的装饰器
@dec1
@dec2
def func():
  ...
#这个函数声明等价于
func = dec1(dec2(func))
#带参数的装饰器
@dec(some_args)
def func():
  ...
#这个函数声明等价于
func = dec(some_args)(func)

Quelques détails à noter sur les décorateurs sans paramètres

1. (décorateur) lui-même

Par conséquent, un décorateur correspond généralement à deux fonctions, l'une est la fonction décorateur, qui est utilisée pour effectuer certaines opérations d'initialisation, et l'autre est décorée_func, qui est utilisée pour implémenter le traitement supplémentaire pour les fonctions décorées func. Et afin de conserver une référence à func, decor_func est généralement utilisée comme fonction interne de decorator

def decorator(func):
  def decorator_func()
    func()
  return decorated_func

La fonction decorator n'est appelée qu'une seule fois lorsque le la fonction est déclarée

Le décorateur est en fait du sucre syntaxique. Il sera appelé après la déclaration de la fonction, générera décoré_func et remplacera la référence du symbole func par décoré_func. Chaque fois que la fonction func est appelée par la suite, decor_func est effectivement appelée (c'est très important, après la décoration, decor_func est en fait appelée à chaque fois).

>>> def decorator(func):
...   def decorated_func():
...     func(1)
...   return decorated_func
... 
#声明时就被调用
>>> @decorator
... def func(x):
...   print x
... 
decorator being called 
#使用func()函数实际上使用的是decorated_func函数
>>> func()
1
>>> func.__name__
'decorated_func'

Si vous voulez vous assurer que le nom de fonction du décoré_func renvoyé est le même que le nom de la fonction de la fonction, vous devez ajouter décoré_func.name = avant que la fonction décorateur ne renvoie décoré_func. func.name De plus, le module functools fournit le décorateur wraps pour effectuer cette action.

#@wraps(func)的操作相当于
#在return decorated_func之前,执行
#decorated_func.__name__ = func.__name__
#func作为装饰器参数传入, 
#decorated_func则作为wraps返回的函数的参数传入
>>> def decorator(func):
...   @wraps(func)
...   def decorated_func():
...     func(1)
...   return decorated_func
... 
#声明时就被调用
>>> @decorator
... def func(x):
...   print x
... 
decorator being called 
#使用func()函数实际上使用的是decorated_func函数
>>> func()
1
>>> func.__name__
'func'

La merveilleuse utilisation des variables locales de la fonction décorateur

Parce que des caractéristiques de fermeture (Voir (1) Fermeture Partielle pour plus de détails). Les variables déclarées par le décorateur seront référencées par decor_func.func_closure, donc après l'appel de la méthode décorateur, les variables locales de la méthode décorateur ne seront pas recyclées, vous pouvez donc utiliser les variables locales de la méthode decorator. Les variables font office de compteurs, de caches, etc.

Il convient de noter que si vous souhaitez modifier la valeur d'une variable, la variable doit être un objet mutable, donc même un compteur doit être implémenté avec une liste. Et déclarez que la fonction appelle la fonction décorateur une fois, pour que les compteurs des différentes fonctions n'entrent pas en conflit entre eux, par exemple :

#!/usr/bin/env python
#filename decorator.py
def decorator(func):
  #注意这里使用可变对象
  a = [0]
  def decorated_func(*args,**keyargs):
    func(*args, **keyargs)
    #因为闭包是浅拷贝,如果是不可变对象,每次调用完成后符号都会被清空,导致错误
    a[0] += 1
    print "%s have bing called %d times" % (func.__name__, a[0])
  return decorated_func
@decorator
def func(x):
  print x
@decorator
def theOtherFunc(x):
  print x

Commençons à écrire le code :

#coding=UTF-8
#!/usr/bin/env python
#filename decorator.py
import time
from functools import wraps
def decorator(func):
  "cache for function result, which is immutable with fixed arguments"
  print "initial cache for %s" % func.__name__
  cache = {}
  @wraps(func)
  def decorated_func(*args,**kwargs):
    # 函数的名称作为key
    key = func.__name__
    result = None
    #判断是否存在缓存
    if key in cache.keys():
      (result, updateTime) = cache[key]
      #过期时间固定为10秒
      if time.time() -updateTime < 10:
        print "limit call 10s", key
        result = updateTime
      else :
        print "cache expired !!! can call "
        result = None
    else:
      print "no cache for ", key
    #如果过期,或则没有缓存调用方法
    if result is None:
      result = func(*args, **kwargs)
      cache[key] = (result, time.time())
    return result
  return decorated_func
@decorator
def func(x):
  print &#39;call func&#39;

Je viens de le tester et il n'y a pratiquement aucun problème.

>>> from decorator import func
initial cache for func
>>> func(1)
no cache for func
call func
>>> func(1)
limit call 10s func
1488082913.239092
>>> func(1)
cache expired !!! can call
call func
>>> func(1)
limit call 10s func
1488082923.298204
>>> func(1)
cache expired !!! can call
call func
>>> func(1)
limit call 10s func
1488082935.165979
>>> func(1)
limit call 10s func
1488082935.165979

Recommandations associées :

Python limite le nombre d'appels de fonction

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn