que es try en python
¿Cuál es la forma correcta de anular el método__dir__? (3)
y 3: si tu solución es correcta.
recarray
no define__dir__
simplemente porque la implementación por defecto estaba bien, por lo que no se molestaron en implementarla, y losnumpy
de numpy no diseñaron la clase para ser subclase, por lo que no veo por qué deberían haber molestado.A menudo es una mala idea crear subclases de tipos incorporados que no están diseñados específicamente para la herencia, por lo que le sugiero que utilice la delegación / composición en lugar de la herencia, excepto si hay una razón particular (por ejemplo, desea pasarla). a una función
numpy
que comprueba de formaisinstance
conisinstance
).No. Como señalaste en python3, cambiaron la implementación para que haya un
object.__dir__
, pero en otras versiones de python no puedo ver nada de lo que puedes hacer. Además, de nuevo, usar larecarray
con herencia múltiple es simplemente una locura, las cosas se romperán. La herencia múltiple debe diseñarse con cuidado y, por lo general, las clases se diseñan específicamente para ser utilizadas con ella (por ejemplo, mezclas). Así que no me molestaría en tratar este caso, ya que quien lo intente será mordido por otros problemas.No veo por qué debería cuidar las clases que no tienen
__dict__
... ya que su subclase lo tiene, ¿cómo debería romperse? Cuando cambie la implementación de la subclase, por ejemplo, si usa__slots__
también podría cambiar fácilmente__dir__
. Si desea evitar la redefinición de__dir__
, simplemente puede definir una función que compruebe__dict__
luego__slots__
etc. Sin embargo,__slots__
cuenta que los atributos se pueden generar de forma sutil con__getattr__
y__getattribute__
y, por lo tanto, no puede capturarlos de forma confiable.
Esta pregunta pretende ser más sobre __dir__
que sobre numpy
.
Tengo una subclase de numpy.recarray
(en python 2.7, numpy 1.6.2), y noté que los nombres de los campos de recarray
no aparecen en la lista al dirigir el objeto (y, por lo tanto, el autocompletado de ipython no funciona).
Tratando de arreglarlo, traté de reemplazar __dir__
en mi subclase, como esto:
def __dir__(self):
return sorted(set(
super(MyRecArray, self).__dir__() + /
self.__dict__.keys() + self.dtype.fields.keys()))
que resultó con: AttributeError: ''super'' object has no attribute ''__dir__''
. (Encontré que esto debería funcionar en Python 3.3 ...)
Como solución, intenté:
def __dir__(self):
return sorted(set(
dir(type(self)) + /
self.__dict__.keys() + self.dtype.fields.keys()))
Por lo que puedo decir, este funciona, pero por supuesto, no tan elegante.
Preguntas:
- ¿Es correcta la última solución en mi caso, es decir, para una subclase de
recarray
? - ¿Hay alguna manera de hacerlo funcionar en el caso general? Me parece que no funcionaría con herencia múltiple (rompiendo la cadena de
super
llamada) y, por supuesto, para objetos sin__dict__
... - ¿Sabe por qué
recarray
no admite enumerar sus nombres de campo para empezar? mero descuido?
Has probado:
def __dir__(self):
return sorted(set(
dir(super(MyRecArray, self)) + /
self.__dict__.keys() + self.dtype.fields.keys()))
Python 2.7+, 3.3+ clase mezcla que simplifica la implementación del método __dir__ en las subclases. Espero que ayude. Gist
import six
class DirMixIn:
""" Mix-in to make implementing __dir__ method in subclasses simpler
"""
def __dir__(self):
if six.PY3:
return super(DirMixIn, self).__dir__()
else:
# code is based on
# http://www.quora.com/How-dir-is-implemented-Is-there-any-PEP-related-to-that
def get_attrs(obj):
import types
if not hasattr(obj, ''__dict__''):
return [] # slots only
if not isinstance(obj.__dict__, (dict, types.DictProxyType)):
raise TypeError("%s.__dict__ is not a dictionary"
"" % obj.__name__)
return obj.__dict__.keys()
def dir2(obj):
attrs = set()
if not hasattr(obj, ''__bases__''):
# obj is an instance
if not hasattr(obj, ''__class__''):
# slots
return sorted(get_attrs(obj))
klass = obj.__class__
attrs.update(get_attrs(klass))
else:
# obj is a class
klass = obj
for cls in klass.__bases__:
attrs.update(get_attrs(cls))
attrs.update(dir2(cls))
attrs.update(get_attrs(obj))
return list(attrs)
return dir2(self)