Pregunta
Esto es código que encontré en internet. No estoy seguro de cómo está destinado a ser utilizado. Simplemente llena miembros con las llaves / valores de enumeración y funciona, pero tengo curiosidad lo que este metaclase se trata. Estoy suponiendo que tiene algo que ver con ctypes, pero no puedo encontrar mucha información sobre ctypes de subclases. Sé EnumerationType no está haciendo nada la forma en que estoy usando Enumeración.
from ctypes import *
class EnumerationType(type(c_uint)):
def __new__(metacls, name, bases, dict):
if not "_members_" in dict:
_members_ = {}
for key,value in dict.items():
if not key.startswith("_"):
_members_[key] = value
dict["_members_"] = _members_
cls = type(c_uint).__new__(metacls, name, bases, dict)
for key,value in cls._members_.items():
globals()[key] = value
return cls
def __contains__(self, value):
return value in self._members_.values()
def __repr__(self):
return "<Enumeration %s>" % self.__name__
class Enumeration(c_uint):
__metaclass__ = EnumerationType
_members_ = {}
def __init__(self, value):
for k,v in self._members_.items():
if v == value:
self.name = k
break
else:
raise ValueError("No enumeration member with value %r" % value)
c_uint.__init__(self, value)
@classmethod
def from_param(cls, param):
if isinstance(param, Enumeration):
if param.__class__ != cls:
raise ValueError("Cannot mix enumeration members")
else:
return param
else:
return cls(param)
def __repr__(self):
return "<member %s=%d of %r>" % (self.name, self.value, self.__class__)
And an enumeration probably done the wrong way.
class TOKEN(Enumeration):
_members_ = {'T_UNDEF':0, 'T_NAME':1, 'T_NUMBER':2, 'T_STRING':3, 'T_OPERATOR':4, 'T_VARIABLE':5, 'T_FUNCTION':6}
Solución
Una metaclase es una clase usada para crear clases. Piénsalo de esta manera:. Todos los objetos tienen una clase, una clase es también un objeto, por lo tanto, tiene sentido que una clase puede tener una clase
http://www.ibm.com/developerworks/linux /library/l-pymeta.html
Para entender lo que está haciendo esto, se puede ver en algunos puntos en el código.
_members_ = {'T_UNDEF':0, 'T_NAME':1, 'T_NUMBER':2, 'T_STRING':3, 'T_OPERATOR':4, 'T_VARIABLE':5, 'T_FUNCTION':6}
globals()[key] = value
A continuación se tarda cada llave se define en el diccionario: "T_UNDEF" "T_NUMBER" y los pone a disposición en su diccionario globales
.def __init__(self, value):
for k,v in self._members_.items():
if v == value:
self.name = k
break
Siempre que se realice una instancia de su enumeración, se comprobará para ver si el "valor" está en la lista de nombres de enumeración permisibles al inicializar la clase. Cuando se encuentra el valor, se establece el nombre de la cadena de self.name.
c_uint.__init__(self, value)
Esta es la línea real que establece el "valor ctypes" a un c entero sin signo real.
Otros consejos
Esto es de hecho una clase rara.
La forma en que lo está utilizando es correcta, aunque de otra manera sería:
class TOKEN(Enumeration):
T_UNDEF = 0
T_NAME = 1
T_NUMBER = 2
T_STRING = 3
T_OPERATOR = 4
T_VARIABLE = 5
T_FUNCTION = 6
(Eso es lo que los primeros 6 líneas en __new__
son para)
A continuación, se puede usar de esta manera:
>>> TOKEN
<Enumeration TOKEN>
>>> TOKEN(T_NAME)
<member T_NAME=1 of <Enumeration TOKEN>>
>>> T_NAME in TOKEN
True
>>> TOKEN(1).name
'T_NAME'
El método from_param
parece ser por conveniencia, para los métodos de escritura que aceptan ya sea un entero o un objeto Enumeration
. En realidad, no estoy seguro si eso es realmente su propósito.
Creo que esta clase está destinado a ser utilizado cuando se trabaja con las API externas las enumeraciones uso de estilo C, pero parece que una gran cantidad de trabajo para muy poca ganancia.