J'essaie de définir certaines méthodes de classe en utilisant une autre méthode de classe plus générique comme suit:
class RGB(object):
def __init__(self, red, blue, green):
super(RGB, self).__init__()
self._red = red
self._blue = blue
self._green = green
def _color(self, type):
return getattr(self, type)
red = functools.partial(_color, type='_red')
blue = functools.partial(_color, type='_blue')
green = functools.partial(_color, type='_green')
Mais lorsque j'essaie d'invoquer l'une de ces méthodes, j'obtiens:
rgb = RGB(100, 192, 240)
print rgb.red()
TypeError: _color() takes exactly 2 arguments (1 given)
Je suppose que self n'est pas passé à _color
Puisque rgb.red(rgb)
fonctionne.
Vous créez des partiels sur la fonction , pas sur la méthode. Les objets functools.partial()
ne sont pas des descripteurs, ils n'ajouteront pas eux-mêmes l'argument self
et ne pourront pas faire office de méthodes eux-mêmes. Vous pouvez uniquement encapsuler les méthodes ou fonctions liées, elles ne fonctionnent pas du tout avec les méthodes non liées. C'est documenté :
Les objets
partial
sont similaires aux objetsfunction
dans la mesure où ils peuvent être appelés, référencés faiblement et peuvent avoir des attributs. Il existe des différences importantes. Par exemple, les attributs__name__
Et__doc__
Ne sont pas créés automatiquement. De plus, les objetspartial
définis dans les classes se comportent comme des méthodes statiques et ne se transforment pas en méthodes liées lors de la recherche d'attributs d'instance.
Utilisez plutôt property
s; ces sont des descripteurs :
class RGB(object):
def __init__(self, red, blue, green):
super(RGB, self).__init__()
self._red = red
self._blue = blue
self._green = green
def _color(self, type):
return getattr(self, type)
@property
def red(self): return self._color('_red')
@property
def blue(self): return self._color('_blue')
@property
def green(self): return self._color('_green')
À partir de Python 3.4, vous pouvez utiliser le nouvel objet functools.partialmethod()
ici; il fera la bonne chose lorsqu'il sera lié à une instance:
class RGB(object):
def __init__(self, red, blue, green):
super(RGB, self).__init__()
self._red = red
self._blue = blue
self._green = green
def _color(self, type):
return getattr(self, type)
red = functools.partialmethod(_color, type='_red')
blue = functools.partialmethod(_color, type='_blue')
green = functools.partialmethod(_color, type='_green')
mais il faudrait les appeler, tandis que les objets property
peuvent être utilisés comme de simples attributs.
Le problème avec partialmethod
est qu'il n'est pas compatible avec inspect.signature
, functools.wraps
, ...
Curieusement, si vous réimplémentez functools.partial
Vous-même en utilisant exemple d'implémentation de documentation partielle , cela fonctionnera:
# Implementation from:
# https://docs.python.org/3/library/functools.html#functools.partial
def partial(func, /, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = {**keywords, **fkeywords}
return func(*args, *fargs, **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
class RGB(object):
def __init__(self, red, blue, green):
super(RGB, self).__init__()
self._red = red
self._blue = blue
self._green = green
def _color(self, type):
return getattr(self, type)
red = partial(_color, type='_red')
blue = partial(_color, type='_blue')
green = partial(_color, type='_green')
rgb = RGB(100, 192, 240)
print(rgb.red()) # Print red
La raison en est que newfunc
est une vraie fonction qui implémente le protocole descripteur avec newfunc.__get__
. Alors que type(functools.partial)
est une classe personnalisée avec __call__
Écrasé. La classe n'ajoutera pas automatiquement le paramètre self
.