11

プラグインが同じ基本クラス(つまりA)のサブクラス(つまりB)である、ある種のプラグインフレームワークを実装することを目的としていました。基本クラスは標準のインポートでロードされますが、サブクラスは既知のパッケージ(つまり、pkg)のパスからimp.load_module()でロードされます。

pkg/
    __init__.py
    mod1.py
        class A
    mod2.py
        class B(pkg.mod1.A)

これは、実際のサブクラス、つまり、

# test_1.py
import pkg
from pkg import mod1
import imp
tup = imp.find_module('mod2', pkg.__path__)
mod2 = imp.load_module('mod2', tup[0], tup[1], tup[2])
print(issubclass(mod2.B, mod1.A)) # True

しかし、基本クラス自体をテストするときに問題が発生しました。

# test_2.py
import pkg
from pkg import mod1
import imp
tup = imp.find_module('mod1', pkg.__path__)
mod0 = imp.load_module('mod1', tup[0], tup[1], tup[2])
print(issubclass(mod0.A, mod1.A)) # False

ただし、mod0.Aとmod1.Aは、実際には同じファイル(pkg / mod1.py)の同じクラスです。

この問題は、Python2.7と3.2の両方で発生します。

ここで、質問は2つあります。a)期待される機能なのか、issubclass()のバグなのか、b)pkgの内容を変更せずにこれを取り除く方法は?

4

3 に答える 3

10

彼らは同じクラスではありません。これらは同じコードで作成されましたが、そのコードを2回(インポートで1回、load_moduleで1回)実行したため、2つの異なるクラスオブジェクトが取得されます。issubclassクラスオブジェクトのIDを比較していますが、それらは異なります。

編集:信頼できないためissubclass、1つの可能な代替手段は、派生クラスによって継承される基本クラスに一意の属性を作成することです。この属性は、クラスのコピーにも存在します。次に、属性をテストできます。

class A:
    isA = True

class B(A):
    pass

class C:
    pass

def isA(aclass):
    try:
        return aclass.isA
    except AttributeError:
        return False

print isA(A)
True
print isA(B)
True
print isA(C)
False
于 2012-07-12T22:20:35.857 に答える
6

私はこれをいじくり回していたので、私は自分の解決策を共有しようと思いました:

import inspect

...

def inherits_from(child, parent_name):
    if inspect.isclass(child):
        if parent_name in [c.__name__ for c in inspect.getmro(child)[1:]]:
            return True
    return False

print inherits_from(possible_child_class, 'parent_class')
#True

もちろん、これは子クラスがCALLED parent_classクラスから継承していることを実際にチェックするだけですが、私の目的(そしてほとんどの場合)では問題ありません。

注:possible_child_classが原因でparent_classのインスタンスである場合、これはfalseを返します[1:]

于 2013-09-12T17:58:33.117 に答える
1
#!/usr/bin/env python

import os
import sys
import pkg
from pkg import mod1
import imp


def smart_load_module(name, path):
    # get full module path
    full_path = os.path.abspath(os.path.join(path[0], name))

    for module_name, module in sys.modules.items():
        # skip empty modules and ones without actual file
        if not module or not hasattr(module, '__file__'):
            continue

        # remove extension and normalize path
        module_path = os.path.abspath(os.path.splitext(module.__file__)[0])
        if full_path == module_path:
            return module

    # if not found, load standard way
    tup = imp.find_module(name, path)
    return imp.load_module(name, tup[0], tup[1], tup[2])


if __name__ == '__main__':
    mod00 = smart_load_module('mod1', pkg.__path__)
    print(issubclass(mod00.A, mod1.A))  # True

    tup = imp.find_module('mod1', pkg.__path__)
    mod0 = imp.load_module('mod1', tup[0], tup[1], tup[2])
    print(issubclass(mod0.A, mod1.A))  # False

これは私のために働きます。sys.modulesでフルパスでクラスを検索し、ロードされたインスタンスが見つかった場合はそれを返します。

于 2013-09-12T11:54:02.820 に答える