2016-09-17 11 views
3

У меня есть декоратор функций и классов, который меняет их на одиночные, но докштыры отбрасываются. Функция преобразования возвращает объект класса, который имеет свою собственную docstring, которая должна быть перезаписана. Как я могу обойти это?Программно изменяемый docstring объекта класса

def singleton(cls): 
    return cls() 

def singletonfunction(func): 
    return func() 

@singletonfunction 
def Bit(): 
    """A 1-bit BitField; must be enclosed in a BitStruct""" 
    return BitsInteger(1) 

Осматривая Bit дает BitInteger строку документации, ни одной функции.

ответ

1

Давайте предположим, что оригинальная версия что-то вроде этого:

class BitsInteger: 
    """BitsInteger docstring""" 
    def __init__(self, num): 
     pass 

def singleton(cls): 
    return cls() 

def singletonfunction(func): 
    return func() 

@singletonfunction 
def Bit(): 
    """A 1-bit BitField; must be enclosed in a BitStruct""" 
    return BitsInteger(1) 

b = Bit 
print("b.__doc__ :", b.__doc__) 

Запуск этого с Python3.5 дает выход:

b.__doc_ : BitsInteger docstring 

Это не может быть то, что вы ожидаете. Когда мы бежим с python -i original.py мы можем осмотреться на то, что на самом деле происходит здесь:

>>> vars() 
{'__name__': '__main__', '__builtins__': <module 'builtins' (built-in)>, 'b': <__main__.BitsInteger object at 0x7ff05d2ae3c8>, '__spec__': None, 'singletonfunction': <function singletonfunction at 0x7ff05d2b40d0>, 'singleton': <function singleton at 0x7ff05d30cd08>, '__cached__': None, 'BitsInteger': <class '__main__.BitsInteger'>, '__loader__': <_frozen_importlib.SourceFileLoader object at 0x7ff05d2eb4a8>, '__package__': None, 'Bit': <__main__.BitsInteger object at 0x7ff05d2ae3c8>, '__doc__': None} 
>>> 

Как вы можете видеть b на самом деле типа BitsInteger

Причина в том, что то, что происходит на самом деле в том, что когда вы пишете:

@singleton_function 
def Bit(): 
    """Bit docstring""" 
    ... 
    return BitsInteger(1) 

вы действительно просто получить синтаксический сахар для этого:

def Bit(): 
    """Bit docstring""" 
    ... 
    return BitsInteger(1) 
Bit = singleton_function(Bit) 

В этом случае Bit - это возвращаемое значение singleton_function, которое фактически является BitsInteger. Я нахожу, когда вы отбрасываете синтаксический сахар, гораздо яснее, что здесь происходит.

Если вы хотели бы иметь удобство декоратора, который не изменяет строку документации, я бы рекомендовал использовать wrapt

import wrapt 

class BitsInteger: 
    """BitsInteger docstring""" 
    def __init__(self, num): 
     pass 

def singleton(cls): 
    return cls() 

@wrapt.decorator 
def singletonfunction(func): 
    return func() 

@singletonfunction 
def Bit(): 
    """A 1-bit BitField; must be enclosed in a BitStruct""" 
    return BitsInteger(1) 

b = Bit 
print("b.__doc_ :", b.__doc__) 

Воспроизводит:

b.__doc_ : A 1-bit BitField; must be enclosed in a BitStruct 

Теперь, когда вы смотрите на Vars() вы видите, что 'b': <FunctionWrapper at 0x7f9a9ac42ba8 for function at 0x7f9a9a9e8c80>, который больше не является BitInteger. Лично мне нравится использовать wrapt, потому что я получаю то, что хочу немедленно. Реализация этой функциональности и покрытие всех крайних случаев требует усилий, и я знаю, что wrapt хорошо протестирован и работает по назначению.

+0

По существу «бит = битИнтегер (1)». У вас есть опечатка в определении бит, он не возвращает класс, а экземпляр. Хуже того, он, похоже, не работает на PY3, и он не наследует/>> операторов. – ArekBulski

+0

Я запускал это с помощью cPython 3.5. Если вы можете поместить некоторое определение класса «BitsInteger» вместе с тем, что вам нужно достичь в вопросе, это может помочь мне улучшить ответ здесь. Я не совсем понимаю, какова первоначальная проблема, которую вы пытаетесь решить. Вам нужно, чтобы бит был доступен для вызова и всегда возвращал тот же (singleton) объект? – shuttle87

+0

Бит может быть экземпляром класса, который имеет docstring, взятый из функции, а не класса. Вот и все. Я принимаю ваше решение, даже если оно иногда работает. – ArekBulski