1
votes

Pouvez-vous avoir des variables de membre dans une fonction python

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.


2 commentaires

que voulez-vous accomplir?


Pouvez-vous préciser si x est la valeur initiale ou la valeur du pas?


6 Réponses :


0
votes
from itertools import count

incr = count(1)
incr() # 1
incr() # 2

2 commentaires

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.



2
votes

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.


0 commentaires

3
votes

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


1 commentaires

Même problème que l'autre réponse, toutes vos instances partagent la même variable statique. +



0
votes

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


2 commentaires

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.



0
votes

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


2 commentaires

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.



0
votes

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 )


0 commentaires