Python导入模块导致NameError
我遇到了一个模块导入的问题。
我在ubuntu 10.10上使用python 2.6。
我有一个类,它是一个守护进程的子类,具体可以参考这个链接:http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/。我创建了一个python包,里面有一个模块,包含了一些从django项目中导入的模型代码。当我从一个类中使用这些代码时,它能正常工作,但当我不继承守护进程时就不行了。我的文件结构大概是这样的:
my_module
__init__.py
- bin
- cfg
- core
__init__.py
collection.py
daemon.py
这是ItemRepository的代码:
class ItemRepository(object):
"""This class provides an implementation to retrieve configuration data
from the monocle database
"""
def __init__(self, project_path):
if project_path is not None:
sys.path.append(project_path)
try:
from django.core.management import setup_environ
from someproj import settings
setup_environ(settings)
from someproj.someapp.models import ItemConfiguration
except ImportError:
print "Could not import models from web app. Please ensure the\
PYTHONPATH is configured properly"
def get_scheduled_collectors(self):
"""This method finds and returns all ItemConfiguration objects
that are scheduled to run
"""
logging.info('At the error path: %s' % sys.path)
# query ItemConfigs from database
items = ItemConfiguration.objects.filter(disabled=False) #ERROR OCCURS AT THIS LINE
return [item for item in items if item.scheduled]
这是守护进程的代码(在/usr/local/bin/testdaemon.py):
import sys
from my_module.core.daemon import Daemon
from my_module.core.collection import ItemRepository
import logging
import time
class TestDaemon(Daemon):
default_conf = '/etc/echodaemon.conf'
section = 'echo'
def run(self):
while True:
logging.info('The echo daemon says hello')
ir = ItemRepository(project_path=self.project_path)
items = ir.get_scheduled_collectors() #TRIGGERS ERROR
logging.info('there are %d scheduled items' % len(items))
time.sleep(1)
if __name__ == '__main__':
TestDaemon().main()
我遇到的错误是“NameError: global name 'my_module' is not defined”。它在导入时没有问题,但在尝试调用对象的方法时就失败了。我猜这可能和sys.path / PYTHONPATH有关,但我知道我的django项目在路径上,因为我已经打印出来看过了。到目前为止,python文档和《Learning Python》都没有帮助我。有没有人能给点建议,或者知道关于模块导入的好参考资料?
更新:
现在我尝试简化问题,以便更容易理解。现在我的目录结构看起来像这样:
/home
/username
/django
/someproj
/web
models.py
/my_module
daemon.py
我在/etc/bash.bashrc中设置了$PYTHONPATH变量为'/home/username/django'。
在testdaemon.py文件中,导入的代码看起来像:
import logging
from django.core.management import setup_environ
from someproj import settings
setup_environ(settings)
from someproj.web.models import ItemConfiguration
但现在我得到一个ImportError:没有名为'someproj'的模块。所以我又添加了路径。
import sys
sys.path.append('/home/username/django')
import logging
from django.core.management import setup_environ
from someproj import settings
setup_environ(settings)
from someproj.web.models import ItemConfiguration
现在ImportError显示:没有名为'web'的模块。这里是错误追踪信息:
Traceback (most recent call last):
File "testdaemon.py", line 77, in <module>
TestDaemon('/tmp/testdaemon.pid').run()
File "testdaemon.py", line 47, in run
scheduled_items = [item for item in ItemConfiguration.objects.filter(disabled=False) if collector.scheduled]
File "/usr/local/lib/python2.6/dist-packages/django/db/models/manager.py", line 141, in filter
return self.get_query_set().filter(*args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py", line 550, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py", line 568, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py", line 1128, in add_q
can_reuse=used_aliases)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py", line 1026, in add_filter
negate=negate, process_extras=process_extras)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py", line 1179, in setup_joins
field, model, direct, m2m = opts.get_field_by_name(name)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/options.py", line 291, in get_field_by_name
cache = self.init_name_map()
File "/usr/local/lib/python2.6/dist-packages/django/db/models/options.py", line 321, in init_name_map
for f, model in self.get_all_related_m2m_objects_with_model():
File "/usr/local/lib/python2.6/dist-packages/django/db/models/options.py", line 396, in get_all_related_m2m_objects_with_model
cache = self._fill_related_many_to_many_cache()
File "/usr/local/lib/python2.6/dist-packages/django/db/models/options.py", line 410, in _fill_related_many_to_many_cache
for klass in get_models():
File "/usr/local/lib/python2.6/dist-packages/django/db/models/loading.py", line 167, in get_models
self._populate()
File "/usr/local/lib/python2.6/dist-packages/django/db/models/loading.py", line 61, in _populate
self.load_app(app_name, True)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/loading.py", line 76, in load_app
app_module = import_module(app_name)
File "/usr/local/lib/python2.6/dist-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
ImportError: No module named web
根据之前的评论,我尝试添加:
import sys
sys.path.append('/home/username/django')
import logging
from django.core.management import setup_environ
from someproj import settings
setup_environ(settings)
from someproj import web
from someproj.web import models
from someproj.web.models import ItemConfiguration
但这没有帮助。所以我创建了一个非常简单的文件:
#!/usr/bin/python
import logging
import time
import sys
sys.path.append('/home/username/django')
from django.core.management import setup_environ
from someproj import settings
setup_environ(settings)
from someproj.web.models import ItemConfiguration
if __name__ == '__main__':
print sys.path
items = ItemConfiguration.objects.all()
for item in items:
print item
这个可以正常工作!这让我更加困惑。所以我在想,可能是和守护进程有关。它使用了os.fork(),我不确定路径是否仍然设置好。这就是我在/etc/bash.bashrc文件中设置$PYTHONPATH变量的原因。
还有其他的见解吗?我真的需要这个守护进程,我没有太多选择,因为我需要一个长时间运行的进程。
3 个回答
使用 from my_module.core.daemon import Daemon
这行代码时,其实并没有把加载的模块 my_module
绑定到一个变量上。如果你想要这样做,可以在其他导入语句之前或之后,使用 import my_module
这行代码。
下面用代码来解释一下:
>>> from xml import dom
>>> xml
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'xml' is not defined
>>> import xml
>>> xml
<module 'xml' from '/usr/lib/python2.6/xml/__init__.pyc'>
你让我有点困惑,你说的“你的Django项目”是指你的模块“my_module”是更高级包的一部分吗?像这样吗
django_project
|
|my_module
__init__.py
- bin
- cfg
- core
__init__.py
collection.py
daemon.py
如果是这样,而且就像你说的,django_project在PYTHONPATH里面,那么你应该这样导入my_module:
from django_project.my_module.core.daemon import Daemon
顺便说一下,最好不要像这样导入模块、类或函数:
from django_project.my_module.core import daemon
而是像这样使用它:
daemon.Daemon()
最后我发现,我需要在Django项目的settings.py文件中,在INSTALLED_APPS设置里使用我应用的完整名称。也就是说,要写成“someproj.web”,而不是简单的“web”。在Django项目内部使用简短的名称没问题,但从外部访问时就不太好用了。