Sto provando a generare alcune definizioni di classe dinamicamente (per il wrapping di un'estensione C++). Il seguente descrittore funziona bene tranne quando provo ad accedere alla docstring per un campo usando help(), fornisce la documentazione predefinita per il descrittore piuttosto che il campo stesso. Tuttavia quando lo faccio aiuto (nome classe), recupera il docstring passato al descrittore:Creazione di docstring dinamici nel descrittore Python
class FieldDescriptor(object):
def __init__(self, name, doc='No documentation available.'):
self.name = name
self.__doc__ = doc
def __get__(self, obj, dtype=None):
if obj is None and dtype is not None:
print 'Doc is:', self.__doc__
return self
return obj.get_field(self.name)
def __set__(self, obj, value):
obj.set_field(self.name, value)
class TestClass(object):
def __init__(self):
self.fdict = {'a': None, 'b': None}
def get_field(self, name):
return self.fdict[name]
def set_field(self, name, value):
self.fdict[name] = value
fields = ['a', 'b']
def define_class(class_name, baseclass):
class_obj = type(class_name, (baseclass,), {})
for field in fields:
setattr(class_obj, field, FieldDescriptor(field, doc='field %s in class %s' % (field, class_name)))
globals()[class_name] = class_obj
if __name__ == '__main__':
define_class('DerivedClass', TestClass)
help(DerivedClass.a)
help(DerivedClass)
v = DerivedClass()
help(v.a)
stampe "pitone" test.py:
Doc is: field a in class DerivedClass Help on FieldDescriptor in module __main__ object: class FieldDescriptor(__builtin__.object) | Methods defined here: | | __get__(self, obj, dtype=None) | | __init__(self, name, doc='No documentation available.') | | __set__(self, obj, value) | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) Doc is: field a in class DerivedClass Doc is: field b in class DerivedClass Help on class DerivedClass in module __main__: class DerivedClass(TestClass) | Method resolution order: | DerivedClass | TestClass | __builtin__.object | | Data descriptors defined here: | | a | field a in class DerivedClass | | b | field b in class DerivedClass | | ---------------------------------------------------------------------- | Methods inherited from TestClass: | | __init__(self) | | get_field(self, name) | | set_field(self, name, value) | | ---------------------------------------------------------------------- | Data descriptors inherited from TestClass: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) Help on NoneType object: class NoneType(object) | Methods defined here: | | __hash__(...) | x.__hash__() hash(x) | | __repr__(...) | x.__repr__() repr(x)
Qualsiasi idea di come si può ottenere il descriptor.__doc__
per help(class.field)
? E c'è un modo per aggirare questo e avere qualcosa come una funzione getter per doc invece di dover memorizzare la doc string nel descrittore?
piace:
class FieldDescriptor(object):
def __init__(self, name, doc='No documentation available.'):
self.name = name
self.__doc__ = doc
def __get__(self, obj, dtype=None):
if obj is None and dtype is not None:
print 'Doc is:', self.__doc__
return self
return obj.get_field(self.name)
def __set__(self, obj, value):
obj.set_field(self.name, value)
# This is what I'd like to have
def __doc__(self, obj, dtype):
return dtype.generate_docstring(self.name)
UPDATE: In realtà ho iniziato con questa definizione di __get__
:
def __get__(self, obj, dtype=None):
return obj.get_field(self.name)
Il problema di questo è che quando ho detto:
help(DerivedClass.a)
Python ha gettato un'eccezione che indica che stavo cercando di chiamare None.get_field
. Pertanto, help()
chiama il metodo __get__
con obj=None
e dtype=DerivedClass
. Ecco perché ho deciso di restituire l'istanza FieldDescriptor quando obj = None e dtype! = None. La mia impressione è stata help(xyz)
tenta di visualizzare xyz.__doc__
. Con questa logica, se __get__
restituisce descriptor_instance
, quindi descriptor_instance.__doc__
deve essere stampato da help(), che è il caso per l'intera classe [help(DerivedClass)
], ma non per il campo singolo [help(DerivedClass.a)
].
Sono sicuro che è tutto lì, ma potresti chiarire quali chiamate ti danno l'output dell'aiuto sbagliato? È troppo sforzo per indovinare cosa ti aspettavi leggendo il codice. – alexis
Come sottolineato da jsbueno, è la guida (DerivedClass.a) che visualizza la documentazione per il descrittore invece della documentazione per il campo (salvata nel descrittore .__ doc__). – subhacom