简体   繁体   English

动态导入的模块不认为它有类

[英]Dynamically imported module doesn't think it has class

Setup: Python 3.3 设置:Python 3.3

I'm making an application that looks through a folder called 'sources' for .py files, and look in them to find classes that extend a class called 'SourceBase' that I defined. 我正在创建一个应用程序,通过一个名为'sources'的文件夹查找.py文件,并查看它们以查找扩展我定义的名为'SourceBase'的类的类。 If they extend SourceBase, I want to make a new instance of the class to work on. 如果他们扩展SourceBase,我想创建一个新的类实例来处理。

I've done some fair amount of research through the following posts, which I understand for the most part: 我通过以下帖子做了一些相当多的研究,我在很大程度上理解这些:

My folder setup is like this, which I beleive is relevant: 我的文件夹设置是这样的,我相信是相关的:

EPDownloader [package]
\
 epdownloader.py [main]
 SourceBase.py [contains SourceBase class]
 imageutils.py [this class will find and dynamically load the classes in the sources package]
 sources [package]
 \
  source1.py [has class that extends SourceBase]
  source2.py
  ...other plugins here...

My issue is that I'm using the following code (from the other stack overflow questions I listed above) and it's searching through my module for classes, but it doesn't find my classes. 我的问题是我正在使用以下代码(来自我上面列出的其他堆栈溢出问题)并且它正在我的模块中搜索类,但它找不到我的类。 It just skips them. 它只是跳过它们。 I'm not sure what's wrong. 我不确定是什么问题。 Here is my code that is performing the search (its based off the first link I posted): 这是我执行搜索的代码(基于我发布的第一个链接):

<!--language: python-->
def getSources(self):
    pluginbase=SourceBase.SourceBase
    searchpath='sources'
    #We want to iterate over all modules in  the sources/ directory, allowing the user to make their own.
    for root, dirs, files in os.walk('./'+searchpath):
        print('files: ',files)
        candidates = [fname for fname in files if fname.endswith('.py') 
                      and not fname.startswith('__')]
        classList=[]
        if candidates:
            for c in candidates:
                modname = os.path.splitext(c)[0]
                print('importing: ',modname)
                module=__import__(searchpath+'.'+modname)   #<-- You can get the module this way
                print('Parsing module '+modname)
                for cls in dir(module):          #<-- Loop over all objects in the module's namespace
                    print('Inspecting item from module: '+str(cls))
                    cls=getattr(module,cls) #this seems to still be a module when it hits source1
                    print('Get attribute: '+str(cls))
                    if (inspect.isclass(cls)):                # Make sure it is a class
                        print('...is a class') 
                        if inspect.getmodule(cls)==module:  # Make sure it was defined in module, not just imported
                            print('...is in a module')
                            if issubclass(cls,pluginbase):          # Make sure it is a subclass of base
                                print('...subclasses '+pluginbase.__name__)
                                classList.append(cls)
        print(classList)

Here is the relevant output it gives me (I trimmed a lot of other stuff this code outputs): 这是它给我的相关输出(我修剪了这个代码输出的很多其他东西):

Inspecting item from module: source1
Get attribute: <module 'sources.source1' from    '/Users/Mgamerz/Documents/workspace/code/EPDownloader/sources/source1.py'>
[] <--- signifies it failed to find the source class

I'm pretty sure my subclassing works, here's a snippet of the class: 我很确定我的子类化工作,这里是该类的片段:

from EPDownloader import SourceBase
class source1(SourceBase.SourceBase):
    def __init__(self):
        pass

I'm stumped by this problem. 我被这个问题困扰了。 I've spent the last few hours on it and I don't know what to do. 我花了最后几个小时,我不知道该怎么做。 I have a feeling its a simple fix I'm not seeing. 我有一种感觉,它是一个我没有看到的简单修复。 Can someone help me find the bug here? 有人可以帮我找到这里的错误吗?

[Note: I looked through the StackOverflow formatting help, and don't see any way to format a 'highlight', the ones where it puts a grey background on text, but inline. [注意:我查看了StackOverflow格式化帮助,并没有看到任何格式化'突出显示'的方法,即在文本上放置灰色背景但内联的方式。 It would help highlight parts of this question I'm trying to convey.] 这将有助于突出我试图传达的这个问题的部分内容。

Look at the documentation: http://docs.python.org/3.1/library/functions.html# import 请查看文档: http://docs.python.org/3.1/library/functions.html# 进口

When the name variable is of the form package.module, normally, the top-level package (the name up till the first dot) is returned, not the module named by name . 当name变量的形式为package.module时,通常会返回顶级包(直到第一个点的名称),而不是按名称命名的模块 However, when a non-empty fromlist argument is given, the module named by name is returned. 但是,当给出非空的fromlist参数时,将返回按名称命名的模块。

Simply replace 只需更换

module=__import__(searchpath+'.'+modname)

with

module=__import__(searchpath+'.'+modname, None, None, "*")

It's the same as "from sources.source1 import *" which tells __import__ to fetch everything inside the given module. 这是同为“从sources.source1进口*”告诉__import__获取给定的模块的一切。

There is something wrong with your __import__ : instead of importing a module, you're importing the whole package (the whole 'sources' directory as a package). 你的__import__ :你不是导入一个模块,而是导入整个包(整个'sources'目录作为一个包)。

I could fix your code doing this: 我可以修复你的代码:

for c in candidates:
        modname = os.path.splitext(c)[0]
        print('importing: ',modname)
        # NEW CODE
        sys.path.insert(0, searchpath)
        module=__import__(modname)   #<-- You can get the module this way
        # END OF NEW CODE
        print('Parsing module '+modname)
        ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM