Je me demande s'il existe un moyen d'avoir des variables membres dans une instance de fonction. Par exemple,
1 2 3
imprimerait
incr_instance = incrementor(1) incr_instance() incr_instance() incr_instance()
Oui, je sais que je peux simplement utiliser une classe, mais c'est une question à propos de bizarre bizarreries du langage dans le langage python.
6 Réponses :
from itertools import count incr = count(1) incr() # 1 incr() # 2
Pas mal mais il n'y a pas d '"instances" de fonction avec ça, il n'y a qu'un seul état global (la fonction elle-même).
@alexis: Oui. J'ai mal compris la question. Je vais juste conclure cette réponse.
Vous pouvez faire ce qui suit:
incr_instance1 = incrementor(1) incr_instance2 = incrementor(1) incr_instance1() #prints 1 incr_instance1() #prints 2 incr_instance2() #prints 1 incr_instance1() #prints 3 incr_instance2() #prints 2
Vous pouvez même créer plusieurs incrémenteurs et leur faire incrémenter leurs valeurs indépendamment:
def incrementor(n): def incrementor_aux(): incrementor_aux.x += n print(incrementor_aux.x) incrementor_aux.x = 0 return incrementor_aux
Quoi se produit est une nouvelle instance de la fonction incrementor_aux
est créée chaque fois que vous appelez incrementor
, avec sa propre valeur locale x
qui reste dans la portée de chaque instance.
Vous pouvez avoir une fonction incrémenteur
qui renvoie une autre fonction qui continue d'incrémenter le compteur n
(la fonction interne utilise n non local
pour accéder à n au lieu d'utiliser incrementor.n
):
1 2 3 10 11 12 4 5 6 13 14 15
Test:
incr_instance = incrementor(1) incr_instance_2 = incrementor(10) print(incr_instance()) print(incr_instance()) print(incr_instance()) print(incr_instance_2()) print(incr_instance_2()) print(incr_instance_2()) print(incr_instance()) print(incr_instance()) print(incr_instance()) print(incr_instance_2()) print(incr_instance_2()) print(incr_instance_2())
Sortie:
def incrementor(n): def inc(): nonlocal n n += 1 return n - 1 return inc
Même problème que l'autre réponse, toutes vos instances partagent la même variable statique. +
On dirait que vous voulez une fabrique qui vous donne des fonctions avec un état local, sans utiliser de classe. Au lieu de faire de la variable d'état un membre de la fonction, j'utiliserais la syntaxe nonlocal
de python:
inc1 = incrementor(1) print(inc1()) # Yes, I can mix them print("inc7 again:", inc7(), inc7()) print("inc1 again:", inc1(), inc1())
Cela affichera 7
, puis 8
:
inc7 = incrementor(7) print(inc7()) print(inc7())
Cela affichera 1
, puis 9 10
, puis 2 3 ; chacune des fonctions inc1 ()
et inc7 ()
fonctionne à son propre rythme.
def incrementor(start): state = start -1 def interior(): nonlocal state state += 1 return state return interior
Je pense que l'OP a explicitement demandé un membre de fonction
La façon dont je l'ai lu, l'OP décrivait le comportement souhaité, pas la mise en œuvre.
En voici un qui n'utilise pas les attributs de fonction:
from functools import partial def increment(x): def gen(): y = x while True: y += 1 yield y g = gen() return partial(next, g) f1 = increment(1) f1() # 2 f1() # 3 f2 = increment(0) f2() # 1 f2() # 2 f1() # 4
Votre réponse m'a fait comprendre que l'argument x pouvait être la valeur initiale ou la valeur du pas
Dans les deux cas, il serait trivial de mettre en œuvre l'un ou les deux dans nos réponses, mais une bonne clarification.
J'avais envie d'essayer ceci et j'ai essayé d'être concis, voici ce que j'ai fini par faire. Ce n'est pas la meilleure pratique, mais vous avez demandé des excentriques!
Le but ici était de ne pas renvoyer la valeur dans la fonction, comme l'OP le demandait.
0 1 2
S'imprimera
index = 0; incr_instance = lambda: [index, exec("global index; index += 1")] print(incr_instance()[0]) print(incr_instance()[0]) print(incr_instance()[0])
L'index est notre global qui garde une trace de notre progression, l'expression lambda exécute deux instructions. La première instruction renvoie la valeur de l'index et la seconde l'incrémente, ce qui a dû être fait à l'aide de exec car vous ne pouvez pas affecter de variables à partir d'un lambda car il s'agit uniquement d'expressions. Les deux instructions sont entre crochets pour exécuter les deux; sinon, il ne retournera que l'index.
L'index [0]
nous donne la valeur de index
plutôt que le résultat de l'expression exec (toujours Aucun )
que voulez-vous accomplir?
Pouvez-vous préciser si x est la valeur initiale ou la valeur du pas?