2010-08-02 15 views
5

(estoy usando Python 2.7) La documentación de Python indica que se puede pasar una asignación al dict orden interna y va a copiar que la cartografía en el nuevo dict:ABC Python: registrar vs subclases

http://docs.python.org/library/stdtypes.html#mapping-types-dict

tengo una clase que implementa el mapeo de ABC, pero fracasa:

import collections 
class Mapping(object): 
    def __init__(self, dict={}): self.dict=dict 
    def __iter__(self): return iter(self.dict) 
    def __iter__(self): return iter(self.dict) 
    def __len__(self): return len(self.dict) 
    def __contains__(self, value): return value in self.dict 
    def __getitem__(self, name): return self.dict[name] 

m=Mapping({5:5}) 
dict(m) 
# Traceback (most recent call last): 
# File "<stdin>", line 1, in <module> 
# TypeError: cannot convert dictionary update sequence element #0 to a sequence 
collections.Mapping.register(Mapping) 
dict(m) 
# Traceback (most recent call last): 
# File "<stdin>", line 1, in <module> 
# TypeError: cannot convert dictionary update sequence element #0 to a sequence 

sin embargo, si mis subclases de la clase collections.Mapping entonces funciona bien:

import collections 
class Mapping(collections.Mapping): 
    def __init__(self, dict={}): self.dict=dict 
    def __iter__(self): return iter(self.dict) 
    def __iter__(self): return iter(self.dict) 
    def __len__(self): return len(self.dict) 
    def __contains__(self, value): return value in self.dict 
    def __getitem__(self, name): return self.dict[name] 

m=Mapping({5:5}) 
dict(m) 
# {5: 5} 

Pensé que el objetivo del ABC era permitir que el registro funcionara de la misma manera que la creación de subclases (para isinstance y issubclass de todos modos). Entonces, ¿qué hay aquí?

Respuesta

7

registro no le da los "perdidos" métodos implementados en la parte superior de los que se definen: de hecho, el registro es no invasiva con respecto al tipo que está registrando - nada se añade a ella, nada se elimina, nada se altera. Es solo afecta a isinstance y issubclass controles: nada más, nada menos.

Subclasificar un ABC puede y le da muchos métodos implementados "gratis" por el ABC además de aquellos que tiene que definir usted mismo.

La semántica de una operación que es totalmente no invasiva, como el registro, en comparación con una operación prevista para enriquecer una clase, como la creación de subclases, obviamente no puede ser idéntica; por lo tanto, su comprensión de "todo el punto del ABC" es imperfecta: el ABC tiene dos puntos, uno obtenido por subclases ("invasivo") y otro por registro (no invasivo).

Tenga en cuenta que siempre se puede multiplicar-heredar si ya tiene una clase como el original Mapping: class GoogMapping(Mapping, collections.Mapping): ... le dará los mismos resultados que hereda directamente de Mappingcollections.Mapping - un nuevo tipo con todos los métodos auxiliares añadidas por collections.Mapping.

+0

Gracias! Eso fue informativo. No quería hacer una subclase porque no quiero los métodos particulares "gratis" que obtienes cuando haces una subclase. Pensé que había cubierto mi clase lo suficiente como para poder lanzarla a un dict, pero estaba equivocado. Gracias de nuevo. –

+0

@Eric, ¡de nada! El método específico que omitió con el propósito de ingresar (o actualizar) un dict con una instancia de su clase es 'keys' - línea 1411 de http://svn.python.org/view/python/trunk/Objects /dictobject.c?annotate=81029 - 'if (PyObject_HasAttrString (arg," keys "))' - así es como 'dict' descubre si se está pasando un mapeo o un iterable de pares (en el primer caso, línea 1567 , usará 'PyMapping_Keys' & c). Por cierto, inocuo pero superfluo, definiste '__iter__' dos veces. –

+0

En lo que respecta a la clase Mapeo, ¿significa eso que un Mapeo adecuado debe tener todos los métodos de Mapeo, incluso los libres? Yo pensaría que sí, ya que se esperaban llaves para Dict. ¿O es que ese dict podría haber usado iter para obtener las llaves? –

0

Ah, parece que dict() está buscando el método de claves ... No usa el ABC.

+0

Lo hace ('PyMapping_Keys' específicamente) pero si y solo si el método' keys' está presente, vea mi comentario anterior (en el hilo de comentarios de A) sobre más detalles. –