是否有一种方法可以方便地在Python中定义类c结构?我厌倦了写这样的东西:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
是否有一种方法可以方便地在Python中定义类c结构?我厌倦了写这样的东西:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
当前回答
这可能有点晚了,但我使用Python元类(下面也有装饰器版本)做了一个解决方案。
当__init__在运行时被调用时,它会获取每个参数及其值,并将它们作为实例变量分配给你的类。通过这种方式,您可以创建一个类结构的类,而不必手动分配每个值。
我的例子没有错误检查,所以更容易遵循。
class MyStruct(type):
def __call__(cls, *args, **kwargs):
names = cls.__init__.func_code.co_varnames[1:]
self = type.__call__(cls, *args, **kwargs)
for name, value in zip(names, args):
setattr(self , name, value)
for name, value in kwargs.iteritems():
setattr(self , name, value)
return self
这是它的行动。
>>> class MyClass(object):
__metaclass__ = MyStruct
def __init__(self, a, b, c):
pass
>>> my_instance = MyClass(1, 2, 3)
>>> my_instance.a
1
>>>
我把它发布在reddit上,/u/matchu发布了一个更干净的装饰版本。我鼓励您使用它,除非您想扩展元类版本。
>>> def init_all_args(fn):
@wraps(fn)
def wrapped_init(self, *args, **kwargs):
names = fn.func_code.co_varnames[1:]
for name, value in zip(names, args):
setattr(self, name, value)
for name, value in kwargs.iteritems():
setattr(self, name, value)
return wrapped_init
>>> class Test(object):
@init_all_args
def __init__(self, a, b):
pass
>>> a = Test(1, 2)
>>> a.a
1
>>>
其他回答
您可以子类化标准库中可用的C结构。ctypes模块提供了一个Structure类。文档中的例子:
>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = [("x", c_int),
... ("y", c_int)]
...
>>> point = POINT(10, 20)
>>> print point.x, point.y
10 20
>>> point = POINT(y=5)
>>> print point.x, point.y
0 5
>>> POINT(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: too many initializers
>>>
>>> class RECT(Structure):
... _fields_ = [("upperleft", POINT),
... ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print rc.upperleft.x, rc.upperleft.y
0 5
>>> print rc.lowerright.x, rc.lowerright.y
0 0
>>>
你可以通过以下方式在python中访问C-Style struct。
class cstruct:
var_i = 0
var_f = 0.0
var_str = ""
如果你只想使用cstruct的对象
obj = cstruct()
obj.var_i = 50
obj.var_f = 50.00
obj.var_str = "fifty"
print "cstruct: obj i=%d f=%f s=%s" %(obj.var_i, obj.var_f, obj.var_str)
如果你想创建一个cstruct对象的数组
obj_array = [cstruct() for i in range(10)]
obj_array[0].var_i = 10
obj_array[0].var_f = 10.00
obj_array[0].var_str = "ten"
#go ahead and fill rest of array instaces of struct
#print all the value
for i in range(10):
print "cstruct: obj_array i=%d f=%f s=%s" %(obj_array[i].var_i, obj_array[i].var_f, obj_array[i].var_str)
注意: 请使用你的struct名称,而不是'cstruct'名称 请定义结构的成员变量,而不是var_i, var_f, var_str。
dF:太酷了……我没有 我知道我可以访问的领域 一个使用字典的类。 马克:我希望我遇到的情况 这正是我需要一个元组的时候 但没有什么比 字典。
你可以使用字典访问类的字段,因为类的字段、它的方法和它的所有属性都是用字典存储在内部的(至少在CPython中是这样)。
...这就引出了你的第二个评论。相信Python字典是“沉重的”是一个非常非Python主义的概念。读这样的评论简直要了我的Python禅。这可不太好。
您可以看到,当您声明一个类时,实际上是在为一个字典创建一个相当复杂的包装器——因此,如果有的话,您比使用一个简单的字典增加了更多的开销。顺便说一下,这种开销在任何情况下都是没有意义的。如果您正在处理性能关键的应用程序,请使用C或其他语言。
使用命名元组,该元组被添加到Python 2.6标准库中的collections模块中。如果你需要支持Python 2.4,也可以使用Raymond Hettinger的命名元组配方。
它适用于基本示例,但也适用于稍后可能遇到的一些边缘情况。你上面的片段可以写成:
from collections import namedtuple
MyStruct = namedtuple("MyStruct", "field1 field2 field3")
新创建的类型可以这样使用:
m = MyStruct("foo", "bar", "baz")
你也可以使用命名参数:
m = MyStruct(field1="foo", field2="bar", field3="baz")
这可能有点晚了,但我使用Python元类(下面也有装饰器版本)做了一个解决方案。
当__init__在运行时被调用时,它会获取每个参数及其值,并将它们作为实例变量分配给你的类。通过这种方式,您可以创建一个类结构的类,而不必手动分配每个值。
我的例子没有错误检查,所以更容易遵循。
class MyStruct(type):
def __call__(cls, *args, **kwargs):
names = cls.__init__.func_code.co_varnames[1:]
self = type.__call__(cls, *args, **kwargs)
for name, value in zip(names, args):
setattr(self , name, value)
for name, value in kwargs.iteritems():
setattr(self , name, value)
return self
这是它的行动。
>>> class MyClass(object):
__metaclass__ = MyStruct
def __init__(self, a, b, c):
pass
>>> my_instance = MyClass(1, 2, 3)
>>> my_instance.a
1
>>>
我把它发布在reddit上,/u/matchu发布了一个更干净的装饰版本。我鼓励您使用它,除非您想扩展元类版本。
>>> def init_all_args(fn):
@wraps(fn)
def wrapped_init(self, *args, **kwargs):
names = fn.func_code.co_varnames[1:]
for name, value in zip(names, args):
setattr(self, name, value)
for name, value in kwargs.iteritems():
setattr(self, name, value)
return wrapped_init
>>> class Test(object):
@init_all_args
def __init__(self, a, b):
pass
>>> a = Test(1, 2)
>>> a.a
1
>>>