Subclassification of ctypes - Python

This is the code I found on the Internet. I am not sure how it is intended to be used. I just populated the elements with enumeration keys / values, and it works, but I'm curious what the metaclass is. I assume this has something to do with ctypes, but I cannot find much information about the subclassification of ctypes. I know that EnumerationType does nothing, as I use Enumeration.

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} 
+4
source share
2 answers

A metaclass is a class used to create classes. Think of it this way: all objects have a class, the class is also an object, so it makes sense that the class can have a class.

http://www.ibm.com/developerworks/linux/library/l-pymeta.html

To understand what this does, you can look at a few points in the code.

  _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 

It requires each specific key in your dictionary: "T_UNDEF" "T_NUMBER" and makes them available in your global dictionary.

 def __init__(self, value): for k,v in self._members_.items(): if v == value: self.name = k break 

Whenever you make an instance of your enum, it checks to see if the "value" is in the list of valid enum names when initializing the class. When a value is found, it sets the string name to self.name.

 c_uint.__init__(self, value) 

This is the actual string that sets the value of "ctypes" to a real unsigned integer.

+4
source

This is a really weird class.

How you use it is correct, although another way would be:

 class TOKEN(Enumeration): T_UNDEF = 0 T_NAME = 1 T_NUMBER = 2 T_STRING = 3 T_OPERATOR = 4 T_VARIABLE = 5 T_FUNCTION = 6 

(This is what for the first 6 lines in __new__ )

Then you can use it like this:

 >>> TOKEN <Enumeration TOKEN> >>> TOKEN(T_NAME) <member T_NAME=1 of <Enumeration TOKEN>> >>> T_NAME in TOKEN True >>> TOKEN(1).name 'T_NAME' 

The from_param method is apparently convenient for writing methods that accept an int or Enumeration object. Not quite sure that this is really his goal.

I think this class is intended to be used when working with external APIs using c-style lists, but it looks like a lot of work for very little gain.

+3
source

All Articles