J'écris un framework et je souhaite que ma classe de base utilise différentes fonctions pour renommer les classes enfants. J'ai pensé que le meilleur moyen serait d'utiliser un attribut de classe, comme dans le cas de J'ai donc expérimenté un peu ce qui précède, et j'obtiens ce qui suit: A , mais j'ai eu des TypeError lors de son exécution comme dans rename_columns () . Cependant, cela fonctionnait avec une implémentation comme Ba = A()
a.foo # Works fine, gives back 'bar'
a.__class__.my_func_mask # Works as expected `a.__class__.my_func_mask is str.lower` is true
a.my_func_mask # throws TypeError: descriptor 'lower' for 'str' objects doesn't apply to 'A' object
import pandas as pd
class A:
my_func_mask = str.lower
foo = 'bar'
def rename_columns(self, data):
return data.rename(columns=self.my_func_mask)
class B(A):
def rename_columns(self, data):
return data.rename(columns=self.__class__.my_func_mask)
3 Réponses :
Tout ce qui est placé dans la définition de classe est lié à la classe, mais vous ne pouvez pas lier un intégré à votre propre classe.
Essentiellement, tout le code que vous placez dans une classe est exécuté lorsque la classe est créé. Tous les éléments de locaux () sont alors liés à votre classe à la fin de la classe. C'est pourquoi cela fonctionne également pour lier une méthode à votre classe:
class A:
def __init__(self):
self.my_func_mask = str.lower
Pour ne pas avoir la fonction liée à votre classe, vous devez la placer dans le __init __ méthode de votre classe:
def abc(self):
print('{} from outside the class'.format(self))
class A:
f1 = abc
f2 = lambda self: print('{} from lambda'.format(self))
def f3(self):
print('{} from method'.format(self))
Juste que l'OP n'appelle pas a.my_func_mask (ne fait pas a.my_func_mask () )
Vous stockez une méthode intégrée non liée sur votre classe, ce qui signifie qu'il s'agit d'un descripteur objet . Lorsque vous essayez ensuite d'y accéder sur Vous devez le stocker d'une manière différente; le placer dans un autre conteneur, tel qu'une liste ou un dictionnaire, éviterait la liaison. Ou vous pouvez l'envelopper dans un Mais dans ce cas, je ne stockerais pas self , la liaison de descripteur s'applique mais le __get__ méthode appelée pour terminer la liaison vous indique qu'elle ne peut pas être liée à vos instances de classe personnalisées, car la méthode ne fonctionnerait que sur str instances. C'est une limitation stricte de la plupart des méthodes de types intégrés. staticmethod descriptor a > pour avoir il être lié et renvoyer l'original. Une autre option est de ne pas stocker ceci comme attribut de classe, et simplement de créer un attribut d'instance dans __init__. str.lower comme valeur d'attribut , du tout. Je stockerais Aucun et je reviendrais à str.lower lorsque vous rencontrez toujours None:return data.rename(columns=self.my_func_mask or str.lower)
Merci, c'est très clair, je viens de me poser une question, car vous dites que c'est une limitation sur les types intégrés, mais il semble que ce ne soit pas le cas lorsque vous utilisez des méthodes ou des fonctions de classe personnalisées à la place de str.lower . Qu'est-ce qui régit ce qui peut devenir une méthode bornée et ce qui ne le peut pas?
@HodossySzabolcs: les fonctions définies dans le code Python n'ont aucune restriction sur ce à quoi elles peuvent être liées, mais évidemment elles se cassent quand elles ne s'attendent pas à ce que le premier argument soit une instance ou si cette instance n'a aucun des état attendu. C'est une bonne raison de ne pas mettre de fonctions arbitraires sur une classe de toute façon. Les méthodes intégrées sont plus strictes car elles accèdent à l'état au niveau natif (donc via le code C dans le cas de CPython, l'implémentation Python par défaut). Cela peut être dangereux car accéder au mauvais état entraîne probablement un plantage ou pire, une corruption des données.
@HodossySzabolcs: les méthodes intégrées sont donc généralement limitées à la classe pour laquelle elles sont définies et aux sous-classes (et dans ce dernier cas, elles peuvent simplement ignorer quoi que ce soit au niveau de Python si elles sont sous-classées en Python, cela dépend des détails d'implémentation exacts).
Vous devez déclarer la méthode statique.
class A:
my_func_mask = staticmethod(str.lower)
foo = 'bar'
>>> A().my_func_mask is str.lower
>>> True
Vous devez expliquer votre réponse, ne pas lancer de code. Et évitez de gâcher le '>>>', mettez-le également dans votre bloc de code.
my_func_maskest transformé en méthode liée lorsque vous instanciez la classe. Il y a quelque chose dans ce processus, mais je ne pourrais pas vous dire quoi exactement.Je suppose que
data.rename (columns = A.my_func_mask)fonctionnerait.@Sraw oui, cela fonctionnera, mais cela ne répond pas à la question