为什么一个旧的.pyc文件会导致Django出现故障?

13

我今天使用git拉取了最新的代码,但是出现了以下错误:

ImportError at /
cannot import name Like

这可能与循环导入有关。我检查了回溯信息:

Traceback:
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/core/handlers/base.py" in get_response
  101.                             request.path_info)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/core/urlresolvers.py" in resolve
  298.             for pattern in self.url_patterns:
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/core/urlresolvers.py" in url_patterns
  328.         patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/core/urlresolvers.py" in urlconf_module
  323.             self._urlconf_module = import_module(self.urlconf_name)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/utils/importlib.py" in import_module
  35.     __import__(name)
File "/Users/Desktop/python/mystuff/Project/Project/urls.py" in <module>
  7. admin.autodiscover()
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/contrib/admin/__init__.py" in autodiscover
  29.             import_module('%s.admin' % app)
File "/Library/Python/2.7/site-packages/Django-1.4.1-py2.7.egg/django/utils/importlib.py" in import_module
  35.     __import__(name)

唯一可能导致问题的代码看起来是 urls.py。其中包含以下代码:

from django.contrib import admin
admin.autodiscover()

我注意到在这个时间点,我们之前编写的admin.py文件在最新的合并中被删除了,但是admin.pyc仍然存在。删除.pyc文件后,循环导入错误得到解决,现在一切似乎都正常工作了。

我的问题是:这里究竟发生了什么?Git被配置为忽略所有pyc文件,因此在合并后,即使.py被删除,.pyc文件仍然存在。但是,如果.py本身被删除,Python不应该聪明到不尝试调用任何编译代码在.pyc文件中吗?


它并不知道它已被删除,而且如果没有py,或者py比较旧时,它实际上总是尝试使用pyc - Lev Levitsky
将以下内容添加到您的 root_directory/.gitignore 文件中:*.pyc。这将告诉 git 忽略 Python 字节码。不建议将 pyc 作为仓库的一部分,因为每个本地特性都会编辑它们,如果将其推送给没有您新模块的其他人,则可能会导致运行时错误。 - user1543863
3个回答

11
不,实际上Python会优先使用.pyc文件,只有当它存在且比.pyc文件更新时才会访问.py文件。
这样您可以在不包含源代码的情况下分发编译后的Python应用程序(尽管这并不是很好的代码“混淆”技术)。

1
此功能还允许Linux发行版将已安装软件包的.py文件放置在一个单独的位置,并将.pyc文件放置在每个Python版本的lib目录中(这可能是一个更有用的应用)。 - Sven Marnach

9
不,Python在这方面是故意的(见下文)!你可以运行。
find . -name '*.pyc' -delete

从您的项目目录中删除旧的.pyc文件。

如果您正在使用git,您可以设置钩子以在检出时自动执行此操作。这里是一个类似的解决方案适用于Mercurial。


3
我不会称其为“愚蠢”。这是一项有意的设计决策,旨在支持此功能,并具有多个用例。这是一项特性。 - Sven Marnach
1
@SvenMarnach 我认为“愚蠢”的部分在于当它们被破坏时,它没有提供一个好的清理方式。 - Justin Meiners

2
你能够采取的措施来防止这种情况发生是使用以下命令启动Django:
python -B manage.py runserver

或者使用django-extensions中的clean_pyc来自动删除pyc文件

./manage.py clean_pyc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接