Quels avantages ou implications pourrions-nous obtenir avec Python code comme ceci:
class some_class(parent_class):
def doOp(self, x, y):
def add(x, y):
return x + y
return add(x, y)
J'ai trouvé cela dans un projet open-source, faisant quelque chose d'utile à l'intérieur de la fonction imbriquée, mais ne faisant absolument rien à l'extérieur, sauf l'appeler. (Le code réel peut être trouvé ici .) Pourquoi quelqu'un pourrait-il le coder comme ça? Y a-t-il un avantage ou un effet secondaire à écrire le code à l'intérieur de la fonction imbriquée plutôt que dans la fonction externe normale?
Normalement, vous le faites pour faire fermetures:
def make_adder(x):
def add(y):
return x + y
return add
plus5 = make_adder(5)
print(plus5(12)) # prints 17
Les fonctions internes peuvent accéder aux variables à partir de la portée englobante (dans ce cas, la variable locale x
). Si vous n'accédez à aucune variable de la portée englobante, ce sont vraiment des fonctions ordinaires avec une portée différente.
Mis à part les générateurs de fonctions, où la création de fonctions internes est presque la définition d'un générateur de fonctions, la raison pour laquelle je crée des fonctions imbriquées est d'améliorer la lisibilité. Si j'ai une fonction minuscule qui ne sera invoquée que par la fonction externe, j'inline la définition pour que vous n'ayez pas à sauter pour déterminer ce que fait cette fonction. Je peux toujours déplacer la méthode interne en dehors de la méthode d'encapsulation si je trouve un besoin de réutiliser la fonction à une date ultérieure.
Exemple de jouet:
import sys
def Foo():
def e(s):
sys.stderr.write('ERROR: ')
sys.stderr.write(s)
sys.stderr.write('\n')
e('I regret to inform you')
e('that a shameful thing has happened.')
e('Thus, I must issue this desultory message')
e('across numerous lines.')
Foo()
Un avantage potentiel de l'utilisation de méthodes internes est qu'il vous permet d'utiliser des variables locales de méthode externe sans les passer comme arguments.
def helper(feature, resultBuffer):
resultBuffer.print(feature)
resultBuffer.printLine()
resultBuffer.flush()
def save(item, resultBuffer):
helper(item.description, resultBuffer)
helper(item.size, resultBuffer)
helper(item.type, resultBuffer)
peut être écrit comme suit, qui se lit sans doute mieux
def save(item, resultBuffer):
def helper(feature):
resultBuffer.print(feature)
resultBuffer.printLine()
resultBuffer.flush()
helper(item.description)
helper(item.size)
helper(item.type)
Je ne peux pas imaginer une bonne raison pour un code comme ça.
Peut-être qu'il y avait une raison pour la fonction interne dans les révisions plus anciennes, comme d'autres Ops.
Par exemple, cela rend légèrement plus logique:
class some_class(parent_class):
def doOp(self, op, x, y):
def add(x, y):
return x + y
def sub(x,y):
return x - y
return locals()[op](x,y)
some_class().doOp('add', 1,2)
mais alors la fonction interne devrait être des méthodes de classe ("privées") à la place:
class some_class(object):
def _add(self, x, y):
return x + y
def doOp(self, x, y):
return self._add(x,y)
L'idée derrière les méthodes locales est similaire aux variables locales: ne pollue pas l'espace de noms plus grand. Évidemment, les avantages sont limités car la plupart des langues ne fournissent pas directement de telles fonctionnalités.
Êtes-vous sûr que le code était exactement comme ça? La raison normale de faire quelque chose comme ça est de créer un partiel - une fonction avec des paramètres intégrés. L'appel de la fonction externe renvoie un appelable qui n'a besoin d'aucun paramètre et peut donc être stocké et utilisé quelque part, il est impossible de transmettre des paramètres. Cependant, le code que vous avez publié ne fera pas cela - il appelle la fonction immédiatement et renvoie le résultat, plutôt que l'appelable. Il pourrait être utile de publier le code réel que vous avez vu.