2010-09-10 4 views
5

j'ai écrit une ligne de code en utilisant lambda pour fermer une liste d'objets de fichiers dans python2.6:Impossible de fermer le fichier de manière fonctionnelle dans python3.1?

map(lambda f: f.close(), files) 

Il fonctionne, mais ne pas python3.1. Pourquoi?

Voici mon code de test:

import sys 

files = [sys.stdin, sys.stderr] 

for f in files: print(f.closed) # False in 2.6 & 3.1 

map(lambda o : o.close(), files) 

for f in files: print(f.closed) # True in 2.6 but False in 3.1 

for f in files: f.close()   

for f in files: print(f.closed) # True in 2.6 & 3.1 

Répondre

6

map retourne une liste en Python 2, mais un itérateur en Python 3. Ainsi, les fichiers seront fermés uniquement si vous itérer sur le résultat.

Ne jamais appliquer map ou des fonctions "fonctionnelles" similaires à des fonctions avec effets secondaires. Python n'est pas un langage fonctionnel, et ne le sera jamais. Utilisez une boucle for:

for o in files: 
    o.close() 
+0

Notez également que 2to3 attrape ceci, et listera automatiquement (...) l'appel de carte pour vous, en forçant une évaluation immédiate. –

+3

'N'appliquez jamais de fonction de carte ou de fonction "fonctionnelle" similaire à des fonctions ayant des effets secondaires. Python n'est pas un langage fonctionnel, et ne le sera jamais. Je ne vois pas pourquoi ce ne serait pas un bon conseil même si Python était un langage fonctionnel. Il ne sert à rien d'utiliser la carte si vous n'utilisez pas le résultat - dans n'importe quelle langue. – sepp2k

+0

Dans les langues purement fonctionnelles, les fonctions n'ont pas d'effets secondaires, donc une fonction 'close()' ne peut pas exister. – Philipp

4

Parce que la carte en Python 3 est un iterator paresseux. Citation the docs:

Retourne un itérateur qui applique la fonction à chaque élément de itérable, donnant les résultats.

E.g. en Python 2, map(f, seq) équivalent à [f(i) for i in seq], mais en Python 3, c'est (f(i) for i in seq) - syntaxe subtilement différente, mais sémantique très différente. Pour que la variante de carte fonctionne, vous devez consommer l'itérateur. Ergo, c'est plus simple (et plus idiomatique: la carte, la compréhension et les générateurs ne devraient pas avoir d'effets secondaires!) Pour utiliser une boucle for-explicite.

+1

À mon avis, ils auraient dû laisser map() 'seul et faire de la méthode du module itertools' imap() 'un built-in. Au lieu de cela, tout ce qu'ils ont fait était d'introduire une incompatibilité plus importante en changeant ce que fait un built-in existant. – martineau

+0

De même, laisser 'map()' seul et faire 'imap()' un built-in aurait mieux suivi la philosophie "Explicit is better than implicit". – martineau

Questions connexes