33

Is it possible to have Python save the .pyc files to a separate folder location that is in sys.path?

/code
    foo.py
    foo.pyc
    bar.py
    bar.pyc

To:

/code
   foo.py
   bar.py
/code_compiled
   foo.pyc
   bar.pyc

I would like this because I feel it'd be more organized. Thanks for any help you can give me.

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
Evan Fosmark
  • 98,895
  • 36
  • 105
  • 117
  • How you tried Python 3.2? It implements PEP 3147: PYC Repository Directories (http://www.python.org/dev/peps/pep-3147/). – Noctis Skytower Aug 07 '12 at 16:27
  • If you don't care for the .pyc files, you could use `os.system('del *.pyc')` (windows, e.g.) at the end of your script. – Charles Jul 26 '16 at 15:51

10 Answers10

21

Update:

In Python 3.8 -X pycache_prefix=PATH command-line option enables writing .pyc files to a parallel tree rooted at the given directory instead of to the code tree. See $PYTHONPYCACHEPREFIX envvarcredits: @RobertT' answer

The location of the cache is reported in sys.pycache_prefix (None indicates the default location in __pycache__ [since Python 3.2] subdirectories).

To turn off caching the compiled Python bytecode, -B may be set, then Python won’t try to write .pyc files on the import of source modules. See $PYTHONDONTWRITEBYTECODE envvarcredits: @Maleev's answer


Old [Python 2] answer:

There is PEP 304: Controlling Generation of Bytecode Files. Its status is Withdrawn and corresponding patch rejected. Therefore there might be no direct way to do it.

If you don't need source code then you may just delete *.py files. *.pyc files can be used as is or packed in an egg.

jfs
  • 399,953
  • 195
  • 994
  • 1,670
18

In the dark and ancient days of 2003, PEP 304 came forth to challenge this problem. Its patch was found wanting. Environment variable platform dependencies and version skews ripped it to shreds and left its bits scattered across the wastelands.

After years of suffering, a new challenger rose in the last days of 2009. Barry Warsaw summoned PEP 3147 and sent it to do battle, wielding a simple weapon with skill. The PEP crushed the cluttering PYC files, silenced the waring Unladen Swallow and CPython interpreter each trying to argue its PYC file should be triumphant, and allowed Python to rest easy with its dead ghosts occasionally running in the dead of night. PEP 3147 was found worthy by the dictator and was knighted into the official roles in the days of 3.2.

As of 3.2, Python stores a module's PYC files in __pycache__ under the module's directory. Each PYC file contains the name and version of the interpreter, e.g., __pycache__/foo.cpython-33.pyc. You might also have a __pycache__/foo.cpython-32.pyc compiled by an earlier version of Python. The right magic happens: the correct one is used and recompiled if out of sync with the source code. At runtime, look at the module's mymodule.__cached__ for the pyc filename and parse it with imp.get_tag(). See the What's New section for more information.

TL;DR - Just works in Python 3.2 and above. Poor hacks substitute for versions before that.

Charles Merriam
  • 19,908
  • 6
  • 73
  • 83
  • 3
    PEP 3147 is only partial solution. `__pycache__` directories still clutter source code. Main annoyance for me with pycs is directories left undeleted after `svn switch` or such. – Suor Jul 25 '13 at 03:30
  • Seems like an aesthetic problem: the cached .pyc will only be used for exact timestamp matches; probably from filecmp.filecmp(shallow=True). While not beautiful, extra caches should not be used. – Charles Merriam Oct 03 '13 at 01:11
  • Pray tell that, like most things in 3.2, this was also included in 2.7? – ArtOfWarfare Apr 08 '15 at 20:07
  • Damnit - just ran the suggested test in PEP 3147 and got back the answer `False`. The test is: `import imp; hasattr(imp, 'get_tag')`. – ArtOfWarfare Apr 08 '15 at 20:24
  • Specifically, it seems that the PEP was finalized after the first beta of 2.7 had already been released. Still... maybe there is hope? They backported the `pip` module in 2.7.9... maybe they can backport this in 2.7.11? – ArtOfWarfare Apr 09 '15 at 13:30
  • @ArtOfWarfare Or may be we can just abandon python2 already! :-D – binki Feb 17 '16 at 16:59
  • @binki - No Fabric in Python 3. Also, almost every OS still comes with Python 2. These are the two main reasons I'm still stuck on 2.7. – ArtOfWarfare Feb 17 '16 at 17:01
  • 2
    *As the new kingdom arose, those of the old kingdom coveted the treasures of the new land. Many raids for class decorators, integer division, and print functions returned victorious. It was only when farmers started bringing back carts of topsoil that the old ones decided to migrate.* – Charles Merriam Jan 17 '17 at 18:07
  • @CharlesMerriam Out of curiousity, what does the topsoil allegory refer to? – syockit Dec 23 '20 at 11:43
  • Topsoil is a moderately valuable good but bulky and not worth transporting. Not all features were back-ported; but is long enough ago I do not remember. – Charles Merriam Dec 29 '20 at 22:06
7

And only almost ten years later, Python 3.8 finally provides support for keeping bytecode in separate parallel filesystem tree by setting environment variable PYTHONPYCACHEPREFIX or using -X pycache_prefix=PATH argument (official doc here).

RobertT
  • 4,300
  • 3
  • 29
  • 36
5

If you're willing to sacrifice bytecode generation altogether for it, there's a command line flag:

python -B file_that_imports_others.py

Can be put into IDE's build/run preferences

Maleev
  • 843
  • 3
  • 12
  • 21
3

I disagree. The reasons are wrong or at least not well formulated; but the direction is valid. There are good reasons for being able to segregate source code from compiled objects. Here are a few of them (all of them I have run into at one point or another):

  • embedded device reading off a ROM, but able to use an in memory filesystem on RAM.
  • multi-os dev environment means sharing (with samba/nfs/whatever) my working directory and building on multiple platforms.
  • commercial company wishes to only distribute pyc to protect the IP
  • easily run test suite for multiple versions of python using the same working directory
  • more easily clean up transitional files (rm -rf $OBJECT_DIR as opposed to find . -name '*.pyc' -exec rm -f {} \;)

There are workarounds for all these problems, BUT they are mostly workarounds NOT solutions. The proper solution in most of these cases would be for the software to accept an alternative location for storing and lookup of these transitional files.

dietbuddha
  • 8,556
  • 1
  • 30
  • 34
3

I agree, distributing your code as an egg is a great way to keep it organized. What could be more organized than a single-file containing all of the code and meta-data you would ever need. Changing the way the bytecode compiler works is only going to cause confusion.

If you really do not like the location of those pyc files, an alternative is to run from a read-only folder. Since python will not be able to write, no pyc files ever get made. The hit you take is that every python file will have to be re-compiled as soon as it is loaded, regardless of whether you have changed it or not. That means your start-up time will be a lot worse.

Salim Fadhley
  • 22,020
  • 23
  • 75
  • 102
2

Since Python 3.2 has been implemented PEP 3147: this means that all .pyc files are generated inside a __pycache__ directory (there will be a __pycache__ directory for each directory where you have Python files, and it will hold .pyc files for each version of Python used on the sources)

Riccardo Galli
  • 12,419
  • 6
  • 64
  • 62
1

There is ongoing pep that will enable building bytecode to magic directory.

Basically all python files will be compiled to directory __pythoncache__.

Community
  • 1
  • 1
jb.
  • 23,300
  • 18
  • 98
  • 136
1

For Python 3.8 or higher:

The PYTHONPYCACHEPREFIX setting (also available as -X pycache_prefix) configures the implicit bytecode cache to use a separate filesystem tree, rather than the default __pycache__ subdirectories within each source directory.

The location of the cache is reported in sys.pycache_prefix (None indicates the default location in __pycache__ subdirectories).

Cesar Canassa
  • 18,659
  • 11
  • 66
  • 69
-2

"I feel it'd be more organized" Why? How? What are you trying to accomplish?

The point of saving the compiler output is to save a tiny bit of load time when the module gets imported. Why make this more complex? If you don't like the .pyc's, then run a "delete all the .pyc's" script periodically.

They aren't essential; they're helpful. Why turn off that help?

This isn't C, C++ or Java where the resulting objects are essential. This is just a cache that Python happens to use. We mark them as "ignored" in Subversion so they don't accidentally wind up getting checked in.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 8
    > Why? Apparently because they make ls output or Windows Explorer file listing more viusally cluttered. Subjective but fairly legitimate concern, isn't it? – Maleev Jun 05 '10 at 11:37
  • @Maleev: "visually cluttered"? Explorer can be sorted by file type to put the .pyc files elsewhere. Linux `ls` can be used with a wild-card (i.e., `ls *.py`). Trying to rearrange the files is a large waste of time when you have to trivial ways to reduce visual clutter. – S.Lott Jun 06 '10 at 13:16
  • 1
    Moving the .pyc file location is not the same as turning the feature off. Nor does doing so make the Python interpreter more complex. The argument made is predicated on a misunderstanding of what a cache actually is (a temporary storage facility designed to enhance locality of reference). Caches are, by definition, both lossy and localized. Strewing .pyc files throughout a Python project's hierarchy defeats the purpose of a cache. At best you can say it's an optimization at the cost of file hierarchy hygiene. – Samuel A. Falvo II Jan 27 '15 at 23:54
  • 1
    Guido disagrees. See the discussion thread on PEP 3147 where this exact problem was fixed - he says that the biggest selling point on the feature is to fix the clutter. A good way down on this mailing thread you'll find Guido's comment "this is a major selling point of this PEP!" with regard to how files will be less cluttered/better organized. https://mail.python.org/pipermail/python-dev/2010-April/099414.html – ArtOfWarfare Apr 09 '15 at 13:28