سؤال

تعديل: لاحظ أن هذه فكرة سيئة حقا للقيام بها في رمز الإنتاج. كان هذا مجرد شيء مثير للاهتمام بالنسبة لي. لا تفعل هذا في المنزل!

هل من الممكن تعديل متغير __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

أنا أفهم أن Global __metaclass__ لم تعد تعمل في Python 3.x، ولكن هذا ليس قلقي (رمز إذا كان دليلا على المفهوم). فهل هناك أي طريقة لإنجاز هذا في Python-2.x؟

هل كانت مفيدة؟

المحلول

تمام؛ IMO هذا هو الإجمالي، شعر، سحر الظلام. يجب أن لا تستخدمه، ربما من أي وقت مضى، ولكن لا سيما في قانون الإنتاج. إنه نوع من الاهتمام فقط من أجل الفضول، ولكن.

يمكنك كتابة مستورد مخصص باستخدام الآليات الموضحة في بيب 302., ، وناقشت كذلك في دوغ هيلمان Pymotw: وحدات وواردات. وبعد هذا يمنحك الأدوات اللازمة لإنجاز المهمة التي تفصيت بها.

لقد قمت بتنفيذ مثل هذا المستورد، لمجرد أنني كنت فضوليا. أساسا، بالنسبة للوحدات التي تحددها عن طريق متغير الطبقة __chatty_for__, ، سوف يدخل نوع مخصص ك __metaclass__ متغير في الوحدة النمطية المستوردة __dict__, قبل يتم تقييم التعليمات البرمجية. إذا كان الرمز المعني يحدد نفسه __metaclass__, ، من شأنها أن تحل محل واحد مدرج مسبقا من قبل المستورد. سيكون من غير المستحقين لتطبيق هذا المستورد على أي وحدات قبل النظر بعناية في ما ستفعله لهم.

لم أكتب العديد من المستوردين، لذلك ربما فعلت أشياء أو أكثر من الأشياء السخيفة أثناء كتابة هذا واحد. إذا لاحظ أي شخص حالات العيوب / الزاوية التي فاتنيها في التنفيذ، فالرجاء ترك تعليق.

ملف المصدر 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

نصائح أخرى

العالمية __metaclass__"ميزة Python 2 مصممة للعمل لكل وحدة واحدة، فقط (فقط اعتقد ما هو الفساد الذي سيعززه، وإلا من خلال إجبار metaclass الخاص بك على جميع وحدات المكتبة والطرف الثالث الذي قمت باستيراده من تلك النقطة فصاعدا - ارتجف!) . إذا كان من المهم للغاية أن يغيرك "سرا" سلوك جميع الوحدات النمطية التي تقوم باستيرادها من نقطة معينة فصاعدا، لأي سبب من الأسباب عباءة وخنجر، يمكنك أن تلعب حيل قذرة للغاية مع هوك استيراد (في أسوأ الأحوال من خلال نسخ المصادر أولا إلى موقع مؤقت أثناء تغييرها ...) ولكن الجهد سيكون متناسبا مع ضخامة الفعل، والتي تبدو مناسبة ؛-)

لا. (هذه ميزة!)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top