gpt4 book ai didi

python - 为什么元类会改变 issubclass() 的工作方式?

转载 作者:行者123 更新时间:2023-11-28 17:54:11 24 4
gpt4 key购买 nike

好的,所以我正在编写一个框架,它在名为 task.py 的子目录中查找 python 文件,然后查找从基类 Task< 派生的类 并收集它们。我决定我需要向 Task 添加一个元类,但随后 issubclass() 开始以一种奇怪的方式运行。这是目录布局的样子:

start.py                
tasks/__init__.py
tasks/base.py
tasks/sub/__init__.py # empty
tasks/sub/task.py

开始.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'>}

但是当我注释掉 Base 类(Task1 的基类)中的 __metaclass__ 行时,我得到了预期的输出( ALL_TASK1 字典不为空):

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'>}

当通过 imp 函数导入模块时,我不明白元类如何影响 issubclass(),但当模块使用正常导入

谁能给我解释一下(我使用的是 python 2.6.1)?

最佳答案

您的代码也无法通过正常导入工作。

>>> 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):

这会产生与您注释掉元类行时相同的输出,并且与原始代码相比具有优势,因为它允许您的用户定义他们自己的元类并将它们作为任务运行。如果您想明确禁止这一点(请不要,我可能有一天会想使用您的框架)您可以只检查您的元类或 TypeType 具体。

关于python - 为什么元类会改变 issubclass() 的工作方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3555283/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com