好的,所以我正在编写一个框架,在名为task.py
的子目录中查找python文件,然后查找从基类Task
派生的类并收集它们。
我决定我需要向Task
添加一个元类,但是issubclass()
开始表现得很奇怪。
以下是目录布局的外观:
start.py
tasks/__init__.py
tasks/base.py
tasks/sub/__init__.py # empty
tasks/sub/task.py
start.py:
#!/usr/bin/env python
from tasks.base import Task1, Task2
from tasks.sub.task import SubTask1, SubTask2
print "Normal import:"
print "is SubTask1 sub class of Task1? %s" % issubclass(SubTask1, Task1)
print "is SubTask2 sub class of Task2? %s" % issubclass(SubTask2, Task2)
from tasks import setup
print "Imp import:"
setup()
任务/的初始化的.py
import os.path, imp, types
from tasks.base import Task1, Task2
# Find all task definitions
ALL_TASK1 = { }
ALL_TASK2 = { }
def _append_class(d, task, base):
if (type(task) == types.TypeType) and issubclass(task, base):
if task == base:
return
if not task.name in d:
d[task.name] = task
this_dir = os.path.dirname(os.path.abspath(__file__))
for root, dirs, files in os.walk(this_dir):
if not "task.py" in files:
continue
mod_name = "task"
f, pathname, description = imp.find_module(mod_name, [ root ])
m = imp.load_module(mod_name, f, pathname, description)
f.close()
for task in m.__dict__.itervalues():
_append_class(ALL_TASK1, task, Task1)
_append_class(ALL_TASK2, task, Task2)
def setup():
print "All Task1: %s" % ALL_TASK1
print "All Task2: %s" % ALL_TASK2
任务/ base.py
class MetaClass (type):
def __init__(cls, name, bases, attrs):
pass
class Base (object):
__metaclass__ = MetaClass
def method_using_metaclass_stuff(self):
pass
class Task1 (Base):
pass
class Task2 (object):
pass
任务/子/ task.py
from tasks.base import Task1, Task2
class SubTask1 (Task1): # Derived from the __metaclass__ class
name = "subtask1"
class SubTask2 (Task2):
name = "subtask2"
当我运行setup.py
时,我得到以下输出(ALL_TASK1 dict为空!):
Normal import:
is SubTask1 sub class of Task1? True
is SubTask2 sub class of Task2? True
Imp import:
All Task1: {}
All Task2: {'subtask2': <class 'task.SubTask2'>}
但是当我在类__metaclass__
(Base
的基类)中注释掉Task1
行时,我得到了我期望的输出(ALL_TASK1 dict不为空):< / p>
Normal import:
is SubTask1 sub class of Task1? True
is SubTask2 sub class of Task2? True
Imp import:
All Task1: {'subtask1': <class 'task.SubTask1'>}
All Task2: {'subtask2': <class 'task.SubTask2'>}
我不理解元类在通过issubclass()
函数导入模块时如何影响imp
,而不是在使用普通import
导入模块时。
有人可以向我解释一下(我使用的是python 2.6.1)吗?
答案 0 :(得分:2)
您的代码也无法通过正常导入工作。
>>> from tasks.base import Task1
>>> type(Task1)
<class 'tasks.base.MetaClass'>
>>> from types import TypeType
>>> type(Task1) == TypeType
False
>>> issubclass(type(Task1), TypeType)
True
>>>
当您实例化元类(作为类)时,实例没有类型TypeType
,它具有类型tasks.base.MetaClass
。如果您在TypeType
之外测试它,那么您的代码将按预期工作。
def _append_class(d, task, base):
if (issubclass(type(task), types.TypeType) and issubclass(task, base):
这会产生与注释元类线时相同的输出,并且优于您的origninal代码,因为它允许用户定义自己的元类并使它们作为任务运行。如果你想明确地拒绝这个(请不要,我可能希望有一天使用你的框架),你可以只检查你的元类或TypeType
。
答案 1 :(得分:0)
在__metaclass__
中定义Base
时,type(Base)
变为tasks.base.MetaClass
,而不是types.TypeType
。
似乎在_append_class
中你真正关心的是抓住那些作为基类的子类的任务。而不是
if (type(task) == types.TypeType) and issubclass(task, base):
你可以只测试issubclass(task,base)
并捕捉异常:
try: isbase=issubclass(task, base)
except TypeError: isbase=False
if isbase: