Pourquoi les générateurs et fonctions python partagent-ils le mot-clé "def"?

10

Considérer ce qui suit:

def some_function():
    return 1

def some_generator():
    yield 1

Dans le code ci-dessus, some_functionest une fonction, tandis que some_generatorest un générateur. Ils ont l'air assez similaires.

Le problème que j'ai lorsque je lis du code est que je dois parcourir chaque ligne d'une "fonction" à la recherche du yieldmot - clé avant de pouvoir déterminer s'il s'agit en fait d'une fonction ou d'un générateur!

Il me semble simplement que l'utilisation d'un mot clé différent pour les générateurs aurait plus de sens, par exemple:

gen some_generator():
    yield 1

Quels sont les avantages d'utiliser le defmot - clé pour les générateurs et les fonctions? Pourquoi un nouveau mot-clé n'a-t-il pas été introduit pour séparer les fonctions et les générateurs?

Derek Kwok
la source
Je ne connais pas la vraie réponse, mais je commence souvent par écrire des fonctions qui retournent des listes, puis je les convertis en générateurs quand cela me semble correct. Avoir la correspondance de syntaxe rend cela plus naturel.
Gort the Robot
2
La suggestion de @StevenBurnap Derek d'utiliser quelque chose comme genau lieu de defne rendrait pas cette transformation beaucoup plus onéreuse.
jamesdlin
2
En général, les concepteurs de langage essaient généralement d'éviter d'ajouter des mots clés inutiles. Chaque mot-clé qu'ils ajoutent est un identifiant que les programmes ne sont pas autorisés à utiliser à d'autres fins.
jamesdlin
@jamesdlin: Mais la question fait valoir qu'un nouveau mot-clé serait nécessaire .
Giorgio
1
@jamesdlin: Bien sûr, vous pouvez distinguer les fonctions et les générateurs en regardant leur corps, mais la question fait valoir que l'utilisation de mots clés différents rendrait le code plus lisible.
Giorgio

Réponses:

14

"Quels sont les avantages d'utiliser le mot-clé def pour les générateurs et les fonctions?"

Bien qu'ils soient mécaniquement différents, dans la pratique, lorsque je les utilise, ils sont souvent les mêmes pour moi sur le plan conceptuel (je ne pense pas beaucoup à appeler range()vs xrange()).

En termes de compréhension rapide de la fonction, je suis d'accord pour dire que quelque chose est perdu avec l'utilisation de def, mais les choses ne devraient pas être trop obscurcies au sein de la fonction pour commencer.

Même un implicite return Nonepeut brouiller le comportement prévu d'une fonction après un long peu de conditions (comme dans, était return Noneprévu comme un comportement final ou un oubli dans la logique). Mais ce ne sont que mes croyances à ce sujet.

Je ne pense pas que mon argument soit particulièrement convaincant, je vais donc m'en remettre au PEP 255 :

Problème: introduisez un autre nouveau mot clé (par exemple, "gen" ou "générateur") à la place de "def", ou modifiez autrement la syntaxe, pour distinguer les fonctions génératrices des fonctions non génératrices.

Inconvénient: dans la pratique (comment vous en pensez), les générateurs sont des fonctions, mais avec la torsion qu'ils peuvent être repris. La mécanique de leur configuration est un problème technique relativement mineur, et l'introduction d'un nouveau mot-clé surestimerait inutilement les mécanismes de démarrage des générateurs (une partie vitale mais minuscule de la vie d'un générateur).

Pro: En réalité (comment vous en pensez), les fonctions de générateur sont en fait des fonctions d'usine qui produisent des générateurs-itérateurs comme par magie. À cet égard, ils sont radicalement différents des fonctions non génératrices, agissant plus comme un constructeur que comme une fonction, donc réutiliser "def" est au mieux déroutant. Une déclaration de "rendement" enfouie dans le corps ne suffit pas à avertir que la sémantique est si différente.

BDFL: "def" ça reste. Aucun argument de chaque côté n'est totalement convaincant, j'ai donc consulté l'intuition de mon concepteur de langage. Cela me dit que la syntaxe proposée dans le PEP est exactement la bonne - ni trop chaude, ni trop froide. Mais, comme l'Oracle de Delphi dans la mythologie grecque, il ne me dit pas pourquoi, donc je n'ai pas de réfutation pour les arguments contre la syntaxe PEP. Le mieux que je puisse trouver (à part être d'accord avec les réfutations ... déjà faites) est "FUD". Si cela avait fait partie du langage dès le premier jour, je doute fort que cela aurait fait la page "Python Warts" d'Andrew Kuchling.

quaspas
la source
1
Il convient de noter que les nouvelles constructions de syntaxe await(et async withet async for) ajoutées dans PEP 492 , qui fonctionnent de manière très similaire à yield from, nécessitent que la fonction dans laquelle elles sont utilisées soit déclarée en utilisant async defau lieu d'un juste def.
Feuermurmel
2
  1. L'ajout de nouveaux mots clés risque de casser les programmes existants. Les concepteurs de langage essaient généralement d'éviter d'ajouter de nouveaux mots clés, en particulier pour les fonctionnalités de langue ajoutées après que la langue a déjà gagné en popularité. Chaque mot-clé qu'ils ajoutent est un identifiant que les programmes ne sont pas autorisés à utiliser à d'autres fins, donc l'ajout d'un mot-clé pourrait potentiellement casser les programmes existants. Les concepteurs de langage doivent peser les avantages d'un nouveau mot clé par rapport aux coûts.

  2. Je doute que la définition d' un mot clé distinct pour les générateurs aurait beaucoup d'avantages. Comprendre si un symbole correspond au nom d'une fonction ou au nom d'un générateur est quelque chose qui compte pour les appelants, et les appelants ne devraient pas avoir (et parfois ne peuvent pas) regarder quel mot clé a été utilisé pour l'implémenter. C'est la responsabilité de mieux nommer les conventions et la documentation.

jamesdlin
la source
1

Les générateurs sont des fonctions qui évaluent paresseusement. Étant donné qu'il s'agit de la même chose à la base, il est logique qu'ils utilisent le même mot clé. Une option pourrait être d'utiliser un commentaire pour identifier lequel est lequel pour une instance donnée:

def some_function(): #This is a function.
    return 1

def some_generator(): #This is a generator.
    yield 1
Ingénieur du monde
la source
0

Je suppose que c'est parce qu'il est plus Pythonic mais que sais-je? ;)

Je ne pense pas vraiment que cela compte autant. C'est plus facile à retenir pour moi car pas besoin de les mémoriser tous les deux.

EDIT: Le PEP pourrait dire, vous pouvez enquêter là-bas.

XiKuuKy
la source
Merci! En fait, le PEP le dit! Voir PEP-255 pour les avantages / inconvénients et la décision finale concernant un nouveau mot-clé pour les générateurs.
Derek Kwok
Avec un sens Pythonique: "La façon dont cela se fait en Python"?
Giorgio