سؤال

لنفترض أن لدينا فئة metaclass CallableWrappingMeta الذي يمشي في جسد فئة جديدة، ويغلف أساليبها بطبقة، InstanceMethodWrapper:

import types

class CallableWrappingMeta(type):
    def __new__(mcls, name, bases, cls_dict):
        for k, v in cls_dict.iteritems():
            if isinstance(v, types.FunctionType):
                cls_dict[k] = InstanceMethodWrapper(v)
        return type.__new__(mcls, name, bases, cls_dict)

class InstanceMethodWrapper(object):
    def __init__(self, method):
        self.method = method
    def __call__(self, *args, **kw):
        print "InstanceMethodWrapper.__call__( %s, *%r, **%r )" % (self, args, kw)
        return self.method(*args, **kw)

class Bar(object):
    __metaclass__ = CallableWrappingMeta
    def __init__(self):
        print 'bar!'

يقوم غلافنا الوهمي بطباعة الحجج بمجرد وصولها.لكن ستلاحظ شيئا واضحا:لا يتم تمرير الطريقة إلى مستقبل كائن المثيل، لأنه على الرغم من ذلك InstanceMethodWrapper قابلة للاستدعاء، ولا يتم التعامل معها كدالة لغرض تحويلها إلى طريقة مثيل أثناء إنشاء الفئة (بعد الانتهاء من فئة التعريف الخاصة بنا).

الحل المحتمل هو استخدام ديكور بدلاً من فئة لتغليف الأساليب - ستصبح هذه الوظيفة طريقة مثيل.ولكن في العالم الحقيقي، InstanceMethodWrapper هو أكثر تعقيدا بكثير:فهو يوفر واجهة برمجة التطبيقات (API) وينشر أحداث استدعاء الطريقة.الفصل الدراسي أكثر ملاءمة (وأكثر أداءً، وهذا ليس مهمًا كثيرًا).

لقد حاولت أيضًا بعض الطرق المسدودة.تصنيف فرعي types.MethodType و types.UnboundMethodType لم يذهب إلى أي مكان.قليل من الاستبطان، ويبدو أنهم ينزلون عن ذلك type.لذا حاولت استخدام كليهما كطبقة تعريفية، لكن لم يحالفني الحظ هناك أيضًا.قد يكون الأمر أن لديهم متطلبات خاصة باعتبارها فئة تعريفية، ولكن يبدو أننا في منطقة غير موثقة في هذه المرحلة.

أيه أفكار؟

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

المحلول

فقط إثرائك InstanceMethodWrapper فئة مع أ __get__ (والتي يمكن أن تكون جيدة تمامًا return self) - أي تحويل هذه الفئة إلى ملف واصف اكتب، بحيث تكون مثيلاته كائنات واصفة.يرى http://users.rcn.com/python/download/Descriptor.htm للحصول على الخلفية والتفاصيل.

راجع للشغل، إذا كنت تستخدم Python 2.6 أو أفضل، ففكر في استخدام أداة تزيين الفئات بدلاً من تلك الفئة التعريفية - لقد أضفنا أدوات تزيين الفئات على وجه التحديد لأن العديد من فئات التعريف كانت تُستخدم فقط لأغراض الزخرفة هذه، كما أن استخدام أدوات الديكور أسهل كثيرًا حقًا .

نصائح أخرى

تعديل : لأكذب مرة أخرى. سمات __?attr__ على وظائف هي للقراءة فقط، ولكن على ما يبدو لا يلقي دائما استثناء AttributeException عند تعيين؟ لا أدري. العودة إلى المربع رقم واحد!

تعديل : في هذا الواقع لا يحل المشكلة، لأن وظيفة التفاف سوف لن طلبات سمة بالوكالة إلى InstanceMethodWrapper. أنا يمكن، بطبيعة الحال، البط، لكمة سمات __?attr__ في الديكور - وهذا ما أفعله الآن - ولكن هذا قبيح. أفضل الأفكار هي موضع ترحيب كبير.


وبطبيعة الحال، أدركت على الفور أن يجمع بين الديكور بسيط مع صفوفنا سوف تفعل خدعة:

def methodize(method, callable):
    "Circumvents the fact that callables are not converted to instance methods."
    @wraps(method)
    def wrapper(*args, **kw):
        return wrapper._callable(*args, **kw)
    wrapper._callable = callable
    return wrapper

وبعد ذلك قمت بإضافة الديكور للدعوة إلى InstanceMethodWrapper في metaclass:

cls_dict[k] = methodize(v, InstanceMethodWrapper(v))

والشاذ جنسيا. ومنحرف قليلا، ولكنه يعمل.

وانا التخمين تحاول جعل metaclass التي يلتف كل أسلوب في فئة مع وظيفة مخصصة.

وهنا هو الإصدار الخاص بي الذي أعتقد أن أقل قليلا منحرف.

import types

class CallableWrappingMeta(type):
    def __new__(mcls, name, bases, cls_dict):
        instance = type.__new__(mcls, name, bases, cls_dict)
        for k in dir(instance):
            v = getattr(instance, k)
            if isinstance(v, types.MethodType):
                setattr(instance, k, instanceMethodWrapper(v))

        return instance

def instanceMethodWrapper(function):
    def customfunc(*args, **kw):
        print "instanceMethodWrapper(*%r, **%r )" % (args, kw)
        return function(*args, **kw)
    return customfunc

class Bar(object):
    __metaclass__ = CallableWrappingMeta

    def method(self, a, b):
        print a,b

a = Bar()
a.method("foo","bar")

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

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