web-dev-qa-db-fra.com

Python: AttributeError: impossible de décaper l'objet local 'writeBuf. <locals> .write'

Je ne suis pas du tout familier avec Python, je fais habituellement Ruby ou JS. Mais je dois écrire un script d'analyse comparative sur un système qui exécute Python. Ce que j'essaie de faire est de créer un petit script qui obtient une taille de fichier et le nombre de threads et écrit un tampon aléatoire. C'est ce que j'ai obtenu après 2 heures de tripotage:

from multiprocessing import Pool
import os, sys

def writeBuf(buf):
    def write(n):
        f = open(os.path.join(directory, 'n' + str(n)), 'w')
        try:
            f.write(buf)
            f.flush()
            os.fsync(f.fileno)
        finally:
            f.close()
    return write

if __name__ == '__main__':
    targetDir = sys.argv[1]
    numThreads = int(sys.argv[2])
    numKiloBytes = int(sys.argv[3])
    numFiles = int(102400 / numKiloBytes)

    buf = os.urandom(numKiloBytes * 1024)

    directory = os.path.join(targetDir, str(numKiloBytes) + 'k')
    if not os.path.exists(directory):
        os.makedirs(directory)

    with Pool(processes=numThreads) as pool:
        pool.map(writeBuf(buf), range(numFiles))

Mais il jette l'erreur: AttributeError: Can't pickle local object 'writeBuf.<locals>.write'

J'ai déjà essayé d'utiliser write sans la fermeture, mais j'ai eu une erreur lorsque j'ai essayé de définir la fonction à l'intérieur de __name__ == '__main__' partie. L'omission de if entraîne également une erreur et j'ai lu qu'il était nécessaire que Pool fonctionne.

Qu'est-ce qui est censé être juste un petit script transformé en une énorme épreuve, quelqu'un peut-il me montrer le bon chemin?

7
Lanbo

En théorie, python ne peut pas pickler les fonctions. (Pour plus de détails, voir Can't pickle Function )

En pratique, python pickles le nom et le module d'une fonction pour que le passage d'une fonction fonctionne. Dans votre cas cependant, la fonction que vous essayez de passer est une variable locale renvoyée par writeBuf.

Au lieu:

  1. Supprimez le wrapper writeBuf.
  2. N'utilisez pas la fermeture de la fonction write (buf et directory), mais donnez à write tout ce dont elle a besoin comme paramètre.

Résultat:

def write(args):
    directory, buf, n = args

    with open(os.path.join(directory, 'n' + str(n)), 'w') as f:
        # might as well use with-statements ;)
        f.write(buf)
        f.flush()
        os.fsync(f.fileno)

if __name__ == '__main__':
    ...

    with Pool(processes=numThreads) as pool:
        nargs = [(directory, buf, n) for n in range(numFiles)]
        pool.map(write, nargs)
11
Hetzroni