使用ctypes进行子类化 - Python

4

这是我在网上找到的一些代码。我不确定它应该如何使用。我只是用枚举键/值填充了members,并且它可以工作,但我很好奇这个元类是什么。我假设它与ctypes有关,但我找不到有关子类化ctypes的信息。我知道EnumerationType在我使用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}

我认为你需要增加一些缩进,这样你的代码就会被格式化为代码。尝试一下文本区域上方的“101/010”按钮。 - Laurence Gonsalves
2个回答

4
一个元类是用于创建类的类。这样想:所有对象都有一个类,而类也是一个对象,因此,一个类可以有一个类是有意义的。

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

为了理解这个程序在做什么,您可以看一下代码中的几个关键点。
 _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

这里会获取你字典中定义的所有键:"T_UNDEF" 和 "T_NUMBER",并将它们放入全局字典中。
def __init__(self, value):
    for k,v in self._members_.items():
        if v == value:
            self.name = k
            break

无论何时您创建枚举实例,它都会检查在初始化类时允许的枚举名称列表中是否存在“value”。当找到该值时,它会将字符串名称设置为self.name。
c_uint.__init__(self, value)

这是实际设置 "ctypes value" 为实际的 C 无符号整数的代码行。

谢谢。那篇文章把一切都解释得很清楚。我猜每天你都会学到新东西。 - Scott

3

这确实是一个奇怪的类。

你使用它的方式是正确的,尽管另一种方法是:

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

(这就是在__new__的前六行中所做的工作)

然后你可以这样使用它:

>>> TOKEN
<Enumeration TOKEN>
>>> TOKEN(T_NAME)
<member T_NAME=1 of <Enumeration TOKEN>>
>>> T_NAME in TOKEN
True
>>> TOKEN(1).name
'T_NAME'
from_param方法似乎是为了方便起见,用于编写接受整数或Enumeration对象的方法。不确定这是否真正是它的目的。
我认为这个类是用来处理使用C风格枚举的外部API的,但看起来要花费很多工作才能获得很少的收益。

好的,这为我的液晶显示屏项目提供了一个快速的表达式计算器和一堆Linux相关的插件。 :)ctypes模块没有明确提供表示枚举类型的方法,因此需要使用代码实现。同样的功能也可以在不使用我发现的元类的情况下实现。元类只是用来提供全局变量的。我已经使用Python超过5年了,我从未听说过元类。当我看到它时,我认为它是特定于ctypes的。 - Scott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接