Frage
Dies ist ein Code ich im Internet gefunden. Ich bin mir nicht sicher, wie es soll verwendet werden. Ich habe einfach gefüllt Mitglieder mit den Enum-Schlüssel / Werte und es funktioniert, aber ich bin gespannt, was diese metaclass geht. Ich gehe davon aus es etwas mit ctypes zu tun hat, aber ich kann nicht viele Informationen über Subklassifizieren ctypes finden. Ich weiß, EnumerationType ist nichts die Art und Weise tun Enumeration Ich verwende.
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}
Lösung
Eine Metaklasse ist eine Klasse verwendeten Klassen zu erstellen. Denken Sie daran, auf diese Weise:. Alle Objekte haben eine Klasse, eine Klasse ist auch eine Aufgabe, daher macht es Sinn, dass eine Klasse eine Klasse haben kann
http://www.ibm.com/developerworks/linux /library/l-pymeta.html
Um zu verstehen, was dies tut, Sie an einigen Punkten im Code suchen.
_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
Hier nimmt er jeden definierte Schlüssel in Ihrem Wörterbuch: „T_UNDEF“ „T_NUMBER“ und macht sie in Ihrem Globals Wörterbuch verfügbar
.def __init__(self, value):
for k,v in self._members_.items():
if v == value:
self.name = k
break
Wenn Sie eine Instanz Ihrer Enum machen, prüft es, ob der „Wert“ in der Liste der zulässigen Enum-Namen, wenn Sie die Klasse initialisiert. Wenn der Wert gefunden wird, setzt sie den String-Namen self.name.
c_uint.__init__(self, value)
Dies ist die eigentliche Linie, die den „ctypes Wert“ auf einen tatsächlichen c unsigned integer setzt.
Andere Tipps
Das ist in der Tat eine seltsame Klasse.
Die Art und Weise Sie es verwenden ist richtig, obwohl eine andere Art und Weise wäre:
class TOKEN(Enumeration):
T_UNDEF = 0
T_NAME = 1
T_NUMBER = 2
T_STRING = 3
T_OPERATOR = 4
T_VARIABLE = 5
T_FUNCTION = 6
(Das ist, was die ersten 6 Zeilen in __new__
sind)
Dann können Sie es wie so verwenden:
>>> TOKEN
<Enumeration TOKEN>
>>> TOKEN(T_NAME)
<member T_NAME=1 of <Enumeration TOKEN>>
>>> T_NAME in TOKEN
True
>>> TOKEN(1).name
'T_NAME'
Die from_param
Methode scheint für Bequemlichkeit zu sein, Methoden zu schreiben, die entweder ein int oder ein Enumeration
Objekt übernehmen. Nicht wirklich sicher, ob das wirklich sein Zweck erfüllt.
Ich denke, diese Klasse soll verwendet werden, wenn mit externen APIs der Verwendung c-Stil Aufzählungen zu arbeiten, aber es sieht aus wie eine ganze Menge Arbeit für sehr wenig Gewinn.