Le fait que deux questions aient la même réponse ne signifie pas qu'il s'agit de doublons. Trivial pour vous répondre, mais pas trivial pour voir le raisonnement, ou s'il y a un moyen de contourner.
mehmet
Réponses:
111
Pourquoi ne pas l'essayer?
>>> defsome_func():... return2... >>> a = 2>>> if (a = some_func()):
File "<stdin>", line 1if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
ceci est intentionnellement interdit car Guido, dictateur bienveillant de python, les trouve inutiles et plus déroutants qu'utiles. C'est la même raison pour laquelle il n'y a pas d'opérateurs de post-incrémentation ou de pré-incrémentation (++).
Matt Boehm
4
il a permis l'ajout de l' attribution augmentée dans la version 2.0 car il x = x + 1nécessite un temps de recherche supplémentaire alors que x += 1c'était un peu plus rapide, mais je suis sûr qu'il n'a même pas aimé faire ça . :-)
wescpy
espérons que cela deviendra bientôt possible. Python est juste lent à évoluer
Nik O'Lai
4
"pourquoi ne pas l'essayer" - Parce que qui sait quelle pourrait être la syntaxe? Peut-être que OP a essayé cela et cela n'a pas fonctionné, mais cela ne signifie pas que la syntaxe n'est pas différente, ou qu'il n'y a pas de moyen de le faire qui n'est pas prévu
Levi H
57
MISE À JOUR - La réponse d'origine est vers le bas
Résumé
Il s'agit d'une proposition pour créer un moyen d'assigner des variables dans une expression en utilisant la notation NAME: = expr. Une nouvelle exception, TargetScopeError est ajoutée, et il y a une modification à l'ordre d'évaluation.
Le «désordre PEP 572» a été le sujet d'une session 2018 du Sommet du langage Python dirigée par le dictateur bienveillant pour la vie (BDFL) Guido van Rossum. PEP 572 cherche à ajouter des expressions d'affectation (ou "affectations en ligne") au langage, mais il a vu une discussion prolongée sur plusieurs énormes threads sur la liste de diffusion python-dev - même après plusieurs tours sur les idées python. Ces fils étaient souvent controversés et étaient clairement volumineux au point que beaucoup les ont probablement simplement exclus. Lors du sommet, Van Rossum a donné un aperçu de la proposition de fonctionnalité, qu'il semble enclin à accepter, mais il a également voulu discuter de la façon d'éviter ce type d'explosion de fils à l'avenir.
tz n'est utilisé que pour s + = tz, déplacer son affectation à l'intérieur du if aide à montrer sa portée.
Actuel:
s = _format_time(self._hour, self._minute,
self._second, self._microsecond,
timespec)
tz = self._tzstr()
if tz:
s += tz
return s
Amélioré:
s = _format_time(self._hour, self._minute,
self._second, self._microsecond,
timespec)
if tz := self._tzstr():
s += tz
return s
sysconfig.py L'appel de fp.readline () dans la condition while et l'appel de .match () sur les lignes if rendent le code plus compact sans
ce qui rend la compréhension plus difficile.
Actuel:
whileTrue:
line = fp.readline()
ifnot line:
break
m = define_rx.match(line)
if m:
n, v = m.group(1, 2)
try:
v = int(v)
except ValueError:
pass
vars[n] = v
else:
m = undef_rx.match(line)
if m:
vars[m.group(1)] = 0
Amélioré:
while line := fp.readline():
if m := define_rx.match(line):
n, v = m.group(1, 2)
try:
v = int(v)
except ValueError:
pass
vars[n] = v
elif m := undef_rx.match(line):
vars[m.group(1)] = 0
Simplification des compréhensions de liste Une compréhension de liste peut cartographier et filtrer efficacement en capturant la condition:
results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]
De même, une sous-expression peut être réutilisée dans l'expression principale, en lui donnant un nom lors de la première utilisation:
stuff = [[y := f(x), x/y] for x in range(5)]
Notez que dans les deux cas, la variable y est liée dans la portée contenant (c'est-à-dire au même niveau que les résultats ou les trucs).
Capture des valeurs de condition Les expressions d'affectation peuvent être utilisées à bon escient dans l'en-tête d'une instruction if ou while:
# Loop-and-a-halfwhile (command := input("> ")) != "quit":
print("You entered:", command)
# Capturing regular expression match objects# See, for instance, Lib/pydoc.py, which uses a multiline spelling# of this effectif match := re.search(pat, text):
print("Found:", match.group(0))
# The same syntax chains nicely into 'elif' statements, unlike the# equivalent using assignment statements.elif match := re.search(otherpat, text):
print("Alternate found:", match.group(0))
elif match := re.search(third, text):
print("Fallback found:", match.group(0))
# Reading socket data until an empty string is returnedwhile data := sock.recv(8192):
print("Received data:", data)
En particulier avec la boucle while, cela peut supprimer le besoin d'avoir une boucle infinie, une affectation et une condition. Il crée également un parallèle fluide entre une boucle qui utilise simplement un appel de fonction comme condition, et une qui l'utilise comme condition mais utilise également la valeur réelle.
Fork Un exemple du monde UNIX de bas niveau:
if pid := os.fork():
# Parent codeelse:
# Child code
Notez qu'en Python, contrairement à C, l'affectation ne peut pas se produire à l'intérieur des expressions. Les programmeurs C peuvent se plaindre à ce sujet, mais cela évite une classe courante de problèmes rencontrés dans les programmes C: taper = dans une expression lorsque == était prévu.
J'aime cette réponse car elle montre en fait pourquoi une telle "fonctionnalité" a pu être délibérément laissée en dehors de Python. Lors de l'enseignement de la programmation pour débutants, j'ai vu beaucoup de gens faire cette erreur if (foo = 'bar')en voulant tester la valeur defoo .
Jonathan Cross
2
@JonathanCross, Cette "fonctionnalité" va en fait être ajoutée en 3.8. Il est peu probable qu'il soit utilisé aussi modérément qu'il le devrait - mais au moins ce n'est pas une plaine=
John La Rooy
@JohnLaRooy: En regardant les exemples, je pense que "peu probable d'être utilisé avec parcimonie qu'il le devrait" était parfait; Sur les ~ 10 exemples, je trouve que seuls deux améliorent réellement le code. (À savoir, comme seule expression soit dans une condition while, pour éviter de dupliquer la ligne ou d'avoir la condition de boucle dans le corps, soit dans une chaîne elif pour éviter la nidification)
Aleksi Torhamo
39
Non, le BDFL n'aimait pas cette fonctionnalité.
D'où je suis assis, Guido van Rossum, "Dictateur bienveillant pour la vie", s'est battu pour garder Python aussi simple que possible. Nous pouvons chipoter avec certaines des décisions qu'il a prises - j'aurais préféré qu'il dise "Non Mais le fait qu'il n'y ait pas eu de comité de conception de Python, mais plutôt un "conseil consultatif" de confiance, basé en grande partie sur le mérite, filtrant à travers les sensibilités d' un concepteur, a produit un sacré langage sympa, à mon humble avis.
Facile? Cette fonctionnalité pourrait simplifier une partie de mon code car elle aurait pu le rendre plus compact et donc plus lisible. Maintenant, j'ai besoin de deux lignes là où j'en avais besoin d'une. Je n'ai jamais compris pourquoi Python avait rejeté les fonctionnalités d'autres langages de programmation pendant de nombreuses années (et souvent pour une très bonne raison). En particulier, cette fonctionnalité dont nous parlons ici est très, très utile.
Regis mai
6
Moins de code n'est pas toujours plus simple ou plus lisible. Prenons par exemple une fonction récursive. Son équivalent en boucle est souvent plus lisible.
FMF
1
Je n'aime pas la version C de celui-ci, mais il me manque vraiment quelque chose comme la rouille if letquand j'ai une chaîne if elif, mais j'ai besoin de stocker et d'utiliser la valeur de la condition dans chaque cas.
Thayne
1
Je dois dire que le code que j'écris maintenant (la raison pour laquelle j'ai recherché ce problème) est BEAUCOUP plus laid sans cette fonctionnalité. Au lieu d'utiliser if suivi de beaucoup d'autres ifs, je dois continuer à indenter le suivant if sous le dernier else.
MikeKulls
17
Pas directement, selon ma vieille recette - mais comme le dit la recette, il est facile de construire l'équivalent sémantique, par exemple si vous avez besoin de translittérer directement à partir d'un algorithme de référence codé C (avant de refactoriser vers Python plus idiomatique, bien sûr; -). C'est à dire:
classDataHolder(object):def__init__(self, value=None): self.value = value
defset(self, value): self.value = value; return value
defget(self):return self.value
data = DataHolder()
while data.set(somefunc()):
a = data.get()
# use a
BTW, une forme pythonique très idiomatique pour votre cas spécifique, si vous savez exactement quelle valeur falsifiée somefuncpeut renvoyer quand elle renvoie une valeur fausse (par exemple 0), est
for a in iter(somefunc, 0):
# use a
donc dans ce cas précis, le refactoring serait assez simple ;-).
Si le retour pourrait être une sorte de valeur falsish (0, None, '', ...), une possibilité est:
import itertools
for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
# use a
mais vous préférerez peut-être un simple générateur personnalisé:
defgetwhile(func, *a, **k):whileTrue:
x = func(*a, **k)
ifnot x: breakyield x
for a in getwhile(somefunc):
# use a
Je voterais deux fois si je pouvais. C'est une excellente solution pour les moments où quelque chose comme ça est vraiment nécessaire. J'ai adapté votre solution à une classe regex Matcher, qui est instanciée une fois, puis .check () est utilisé dans l'instruction if et .result () utilisé dans son corps pour récupérer la correspondance, s'il y en avait une. Merci! :)
Teekin
16
Oui, mais uniquement à partir de Python 3.8 et au-delà.
La PEP 572 propose des expressions d'affectation et a déjà été acceptée.
# Handle a matched regexif (match := pattern.search(data)) isnotNone:
# Do something with match# A loop that can't be trivially rewritten using 2-arg iter()while chunk := file.read(8192):
process(chunk)
# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]
# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) isnotNone]
@javadba le gars a eu raison beaucoup plus souvent qu'il a eu tort. J'apprécie qu'avoir une seule personne en charge de la vision aboutisse à une stratégie beaucoup plus cohérente que la conception en comité; Je peux comparer et contraster avec C ++ qui est mon pain et beurre principal.
Mark Ransom
Je sens que ruby et scala (v langues différentes) font les choses bien plus que python: mais en tout cas, ce n'est pas le lieu ..
StephenBoesch
4
Grâce à la nouvelle fonctionnalité de Python 3.8, il sera possible de faire une telle chose à partir de cette version, bien que n'utilisant pas un =opérateur d'assignation de type Ada :=. Exemple tiré de la documentation:
# Handle a matched regexif (match := pattern.search(data)) isnotNone:
# Do something with match
L'une des raisons pour lesquelles les affectations sont illégales dans les conditions est qu'il est plus facile de faire une erreur et d'attribuer Vrai ou Faux:
some_variable = 5# This does not work# if True = some_variable:# do_something()# This only works in Python 2.xTrue = some_variable
printTrue# returns 5
En Python 3, True et False sont des mots-clés, donc plus de risque.
Réponses:
Pourquoi ne pas l'essayer?
>>> def some_func(): ... return 2 ... >>> a = 2 >>> if (a = some_func()): File "<stdin>", line 1 if (a = some_func()): ^ SyntaxError: invalid syntax >>>
Donc non.
Mise à jour: c'est possible (avec une syntaxe différente) en Python 3.8
la source
x = x + 1
nécessite un temps de recherche supplémentaire alors quex += 1
c'était un peu plus rapide, mais je suis sûr qu'il n'a même pas aimé faire ça . :-)MISE À JOUR - La réponse d'origine est vers le bas
Python 3.8 apportera PEP572
https://lwn.net/Articles/757713/
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
Réponse originale
http://docs.python.org/tutorial/datastructures.html
regarde aussi:
http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm
la source
if (foo = 'bar')
en voulant tester la valeur defoo
.=
Non, le BDFL n'aimait pas cette fonctionnalité.
D'où je suis assis, Guido van Rossum, "Dictateur bienveillant pour la vie", s'est battu pour garder Python aussi simple que possible. Nous pouvons chipoter avec certaines des décisions qu'il a prises - j'aurais préféré qu'il dise "Non Mais le fait qu'il n'y ait pas eu de comité de conception de Python, mais plutôt un "conseil consultatif" de confiance, basé en grande partie sur le mérite, filtrant à travers les sensibilités d' un concepteur, a produit un sacré langage sympa, à mon humble avis.
la source
if let
quand j'ai une chaîne if elif, mais j'ai besoin de stocker et d'utiliser la valeur de la condition dans chaque cas.Pas directement, selon ma vieille recette - mais comme le dit la recette, il est facile de construire l'équivalent sémantique, par exemple si vous avez besoin de translittérer directement à partir d'un algorithme de référence codé C (avant de refactoriser vers Python plus idiomatique, bien sûr; -). C'est à dire:
class DataHolder(object): def __init__(self, value=None): self.value = value def set(self, value): self.value = value; return value def get(self): return self.value data = DataHolder() while data.set(somefunc()): a = data.get() # use a
BTW, une forme pythonique très idiomatique pour votre cas spécifique, si vous savez exactement quelle valeur falsifiée
somefunc
peut renvoyer quand elle renvoie une valeur fausse (par exemple0
), estfor a in iter(somefunc, 0): # use a
donc dans ce cas précis, le refactoring serait assez simple ;-).
Si le retour pourrait être une sorte de valeur falsish (0,
None
,''
, ...), une possibilité est:import itertools for a in itertools.takewhile(lambda x: x, iter(somefunc, object())): # use a
mais vous préférerez peut-être un simple générateur personnalisé:
def getwhile(func, *a, **k): while True: x = func(*a, **k) if not x: break yield x for a in getwhile(somefunc): # use a
la source
Oui, mais uniquement à partir de Python 3.8 et au-delà.
La PEP 572 propose des expressions d'affectation et a déjà été acceptée.
Citant la partie syntaxe et sémantique du PEP:
# Handle a matched regex if (match := pattern.search(data)) is not None: # Do something with match # A loop that can't be trivially rewritten using 2-arg iter() while chunk := file.read(8192): process(chunk) # Reuse a value that's expensive to compute [y := f(x), y**2, y**3] # Share a subexpression between a comprehension filter clause and its output filtered_data = [y for x in data if (y := f(x)) is not None]
Dans votre cas particulier, vous pourrez écrire
if a := some_func(): # Use a
la source
Non. L'affectation en Python est une instruction, pas une expression.
la source
Grâce à la nouvelle fonctionnalité de Python 3.8, il sera possible de faire une telle chose à partir de cette version, bien que n'utilisant pas un
=
opérateur d'assignation de type Ada:=
. Exemple tiré de la documentation:# Handle a matched regex if (match := pattern.search(data)) is not None: # Do something with match
la source
Vous pouvez définir une fonction pour effectuer l'affectation à votre place:
def assign(name, value): import inspect frame = inspect.currentframe() try: locals_ = frame.f_back.f_locals finally: del frame locals_[name] = value return value if assign('test', 0): print("first", test) elif assign('xyz', 123): print("second", xyz)
la source
L'une des raisons pour lesquelles les affectations sont illégales dans les conditions est qu'il est plus facile de faire une erreur et d'attribuer Vrai ou Faux:
some_variable = 5 # This does not work # if True = some_variable: # do_something() # This only works in Python 2.x True = some_variable print True # returns 5
En Python 3, True et False sont des mots-clés, donc plus de risque.
la source
== True
du bon côté de toute façon.L'opérateur d'affectation - également connu de manière informelle sous le nom d'opérateur de morse - a été créé le 28 février 2018 dans PEP572 .
Par souci d'exhaustivité, je posterai les parties pertinentes afin que vous puissiez comparer les différences entre 3.7 et 3.8:
3.7 --- if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT test: or_test ['if' or_test 'else' test] | lambdef test_nocond: or_test | lambdef_nocond lambdef: 'lambda' [varargslist] ':' test lambdef_nocond: 'lambda' [varargslist] ':' test_nocond or_test: and_test ('or' and_test)* and_test: not_test ('and' not_test)* not_test: 'not' not_test | comparison comparison: expr (comp_op expr)* 3.8 --- if_stmt: 'if' namedexpr_test ':' suite ('elif' namedexpr_test ':' suite)* ['else' ':' suite] namedexpr_test: test [':=' test] <---- WALRUS OPERATOR!!! test: or_test ['if' or_test 'else' test] | lambdef or_test: and_test ('or' and_test)* and_test: not_test ('and' not_test)* not_test: 'not' not_test | comparison comparison: expr (comp_op expr)*
la source