باستخدام docstring من طريقة الكتابة تلقائيا من طريقة أخرى

StackOverflow https://stackoverflow.com/questions/71817

  •  09-06-2019
  •  | 
  •  

سؤال

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

لذلك سيكون من الجميل أن تعديل قاعدة الطبقة في مثل هذه الطريقة التي في فئة فرعية من docstring execute يتم استبدالها تلقائيا مع _execute.أي أفكار كيف يمكن أن يتم ذلك ؟

كنت أفكر في metaclasses للقيام بذلك ، لجعل هذا شفافة تماما للمستخدم.

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

المحلول

حسنا, إذا كنت لا تمانع في النسخ الأصلية الأسلوب في فرعية, يمكنك استخدام الأسلوب التالي.

import new

def copyfunc(func):
    return new.function(func.func_code, func.func_globals, func.func_name,
                        func.func_defaults, func.func_closure)

class Metaclass(type):
    def __new__(meta, name, bases, attrs):
        for key in attrs.keys():
            if key[0] == '_':
                skey = key[1:]
                for base in bases:
                    original = getattr(base, skey, None)
                    if original is not None:
                        copy = copyfunc(original)
                        copy.__doc__ = attrs[key].__doc__
                        attrs[skey] = copy
                        break
        return type.__new__(meta, name, bases, attrs)

class Class(object):
    __metaclass__ = Metaclass
    def execute(self):
        '''original doc-string'''
        return self._execute()

class Subclass(Class):
    def _execute(self):
        '''sub-class doc-string'''
        pass

نصائح أخرى

هل هناك سبب لا يمكنك تجاوز قاعدة الفئة execute وظيفة مباشرة ؟

class Base(object):
    def execute(self):
        ...

class Derived(Base):
    def execute(self):
        """Docstring for derived class"""
        Base.execute(self)
        ...stuff specific to Derived...

إذا كنت لا تريد أن تفعل أعلاه:

طريقة كائنات لا تدعم الكتابة إلى __doc__ السمة ، لذا يجب عليك تغيير __doc__ في وظيفة فعلية الكائن.منذ كنت لا تريد تجاوز واحد في الفئة الأساسية, يجب أن تعطي كل فئة فرعية نسخته من execute:

class Derived(Base):
    def execute(self):
        return Base.execute(self)

    class _execute(self):
        """Docstring for subclass"""
        ...

    execute.__doc__= _execute.__doc__

ولكن هذا يشبه طريقة ملتوية إعادة تعريف execute...

نظرة على functools.يلتف() الديكور;لا يفعل كل هذا, ولكن أنا لا أعرف مرتجلا إذا كنت قادر على تشغيلها في السياق الصحيح

حسنا الطبيب-سلسلة المخزنة في __doc__ لذلك لن يكون من الصعب إعادة تعيين على أساس doc-سلسلة من _execute بعد وقوعها.

في الأساس:

class MyClass(object):
    def execute(self):
        '''original doc-string'''
        self._execute()

class SubClass(MyClass):
    def _execute(self):
        '''sub-class doc-string'''
        pass

    # re-assign doc-string of execute
    def execute(self,*args,**kw):
        return MyClass.execute(*args,**kw)
    execute.__doc__=_execute.__doc__

تنفيذ لابد من إعادة أعلن ذلك الدكتور سلسلة يحصل تعلق نسخة من تنفيذ عن SubClass وليس MyClass (وإلا تتداخل مع غيرها من الفئات الفرعية).

هذا ليس أنيق جدا طريقة للقيام بذلك ، ولكن من بوف المستخدم من المكتبة يجب أن تعطي النتيجة المرجوة.ثم يمكن أن ننتهي من هذا في الطبقة الفوقية لجعله أسهل بالنسبة للأشخاص الذين فرعية تصنف.

أنا أتفق أن أبسط Pythonic طريقة لتناول هذا هو ببساطة إعادة تنفيذ في فرعية ويكون ذلك استدعاء أسلوب التنفيذ الفئة الأساسية:

class Sub(Base):
    def execute(self):
        """New docstring goes here"""
        return Base.execute(self)

هذا هو القليل جدا من رمز لإنجاز ما تريد ؛ الجانب السلبي الوحيد هو أنه يجب تكرار هذا الرمز في كل فئة فرعية تمتد القاعدة.ولكن هذا هو ثمن قليل لدفع ثمن السلوك تريد.

إذا كنت تريد قذرة مطول طريقة التأكد من أن docstring لتنفيذ هي ديناميكيا ، يمكنك استخدام واصف البروتوكول الذي سيكون أقل بكثير رمز من المقترحات الأخرى هنا.هذا أمر مزعج لأنه لا يمكنك فقط تعيين واصف على وظيفة القائمة ، مما يعني أن التنفيذ يجب أن تكون مكتوبة كفئة منفصلة مع __call__ الأسلوب.

هنا هو رمز للقيام بذلك ، ولكن نأخذ في الاعتبار أن بلدي المثال أعلاه هو أبسط من ذلك بكثير وأكثر Pythonic:

class Executor(object):
    __doc__ = property(lambda self: self.inst._execute.__doc__)

    def __call__(self):
        return self.inst._execute()

class Base(object):
    execute = Executor()

class Sub(Base):
    def __init__(self):
        self.execute.inst = self

    def _execute(self):
        """Actually does something!"""
        return "Hello World!"

spam = Sub()
print spam.execute.__doc__  # prints "Actually does something!"
help(spam)                  # the execute method says "Actually does something!"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top