2

編集:これは本番コードで行うのは本当に悪い考えであることに注意してください。これは私にとって興味深いことでした。家でこれをしないでください!

Pythonでプログラム全体(インタープリター)の__metaclass__変数を変更することは可能ですか?

この簡単な例は機能しています。

class ChattyType(type):
    def __init__(cls, name, bases, dct):
        print "Class init", name
        super(ChattyType, cls).__init__(name, bases, dct)

__metaclass__= ChattyType


class Data:
    pass

data = Data() # prints "Class init Data"
print data

しかし、サブモジュールでも機能するように__metaclass__を変更できるようにしたいと思います。したがって、たとえば(ファイルm1.py):

 class A:
       pass

 a=A()
 print a

ファイルmain.py:

class ChattyType(type):
    def __init__(cls, name, bases, dct):
        print "Class init", name
        super(ChattyType, cls).__init__(name, bases, dct)

__metaclass__= ChattyType

import m1 # and now print "Class init A"

class Data:
    pass

data = Data() # print "Class init Data"
print data

グローバル__metaclass__がPython3.Xで機能しなくなったことは理解していますが、それは私の懸念事項ではありません(概念実証の場合は私のコード)。では、Python-2.xでこれを実現する方法はありますか?

4

3 に答える 3

7

Python 2の「グローバル__metaclass__」機能は、モジュールごとにのみ機能するように設計されています (それがどのような大混乱を引き起こすかを考えてみてください。そうしないと、その時点以降にインポートしたすべてのライブラリとサードパーティ モジュールに独自のメタクラスを強制することになります --身震い!)。特定の時点以降にインポートするすべてのモジュールの動作を「秘密裏に」変更することが非常に重要である場合、なんらかのクロークアンドダガーの理由で、インポートフックを使用して非常に汚いトリックを実行できます(最悪の場合最初にソースを変更しながら一時的な場所にコピーします...)しかし、その労力は行為の巨大さに比例するため、適切と思われます;-)

于 2009-12-02T01:10:02.687 に答える
4

わかった; IMO これはグロスで毛むくじゃらのダーク マジックです。おそらく絶対に使用すべきではありませんが、特に本番コードでは使用しないでください。ただし、好奇心のためだけに興味深いものです。

PEP 302で説明されているメカニズムを使用してカスタム インポーターを作成でき、さらに Doug Hellmann のPyMOTW: Modules and Importsで説明されています。これにより、考えていたタスクを達成するためのツールが得られます。

好奇心が強いという理由だけで、そのようなインポーターを実装しました。基本的に、クラス変数を使用して指定したモジュールの場合、コードが評価される前に、インポートされたモジュールの にカスタム__chatty_for__型が変数として挿入されます。問題のコードが独自の を定義している場合、それはインポーターによって事前に挿入されたものを置き換えます。このインポーターがモジュールに何をするかを慎重に検討する前に、このインポーターをモジュールに適用することはお勧めできません。__metaclass____dict____metaclass__

私は多くのインポーターを書いていないので、これを書いている間に 1 つ以上のばかげたことをしたかもしれません。誰かが実装で見逃した欠陥/コーナーケースに気付いた場合は、コメントを残してください.

ソースファイル 1:

# foo.py
class Foo: pass

ソースファイル 2:

# bar.py
class Bar: pass

ソースファイル 3:

# baaz.py
class Baaz: pass

そしてメインイベント:

# chattyimport.py
import imp
import sys
import types

class ChattyType(type):
    def __init__(cls, name, bases, dct):
        print "Class init", name
        super(ChattyType, cls).__init__(name, bases, dct)

class ChattyImporter(object):

    __chatty_for__ = []

    def __init__(self, path_entry):
        pass

    def find_module(self, fullname, path=None):
        if fullname not in self.__chatty_for__:
            return None
        try:
            if path is None:
                self.find_results = imp.find_module(fullname)
            else:
                self.find_results = imp.find_module(fullname, path)
        except ImportError:
            return None
        (f,fn,(suf,mode,typ)) = self.find_results
        if typ == imp.PY_SOURCE:
            return self
        return None

    def load_module(self, fullname):
        #print '%s loading module %s' % (type(self).__name__, fullname)
        (f,fn,(suf,mode,typ)) = self.find_results
        data = f.read()
        if fullname in sys.modules:
            module = sys.modules[fullname]
        else:
            sys.modules[fullname] = module = types.ModuleType(fullname)

        module.__metaclass__ = ChattyType
        module.__file__ = fn
        module.__name__ = fullname
        codeobj = compile(data, fn, 'exec')
        exec codeobj in module.__dict__
        return module

class ChattyImportSomeModules(ChattyImporter):
    __chatty_for__ = 'foo bar'.split()

sys.meta_path.append(ChattyImportSomeModules(''))

import foo # prints 'Class init Foo'
import bar # prints 'Class init Bar'
import baaz
于 2009-12-02T01:57:00.160 に答える
1

いいえ。(これが特徴です!)

于 2009-12-01T22:51:42.787 に答える