是否有一种方法可以方便地在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
当前回答
这里的一些答案非常详尽。我找到的最简单的选项是(from: http://norvig.com/python-iaq.html):)
class Struct:
"A structure that can have any fields defined."
def __init__(self, **entries): self.__dict__.update(entries)
初始化:
>>> options = Struct(answer=42, linelen=80, font='courier')
>>> options.answer
42
添加更多的:
>>> options.cat = "dog"
>>> options.cat
dog
编辑:对不起,没有看到这个例子已经进一步。
其他回答
我认为Python结构字典适合这个需求。
d = dict{}
d[field1] = field1
d[field2] = field2
d[field2] = field3
您可以子类化标准库中可用的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
>>>
NamedTuple很舒服。但是没有人共享性能和存储。
from typing import NamedTuple
import guppy # pip install guppy
import timeit
class User:
def __init__(self, name: str, uid: int):
self.name = name
self.uid = uid
class UserSlot:
__slots__ = ('name', 'uid')
def __init__(self, name: str, uid: int):
self.name = name
self.uid = uid
class UserTuple(NamedTuple):
# __slots__ = () # AttributeError: Cannot overwrite NamedTuple attribute __slots__
name: str
uid: int
def get_fn(obj, attr_name: str):
def get():
getattr(obj, attr_name)
return get
if 'memory test':
obj = [User('Carson', 1) for _ in range(1000000)] # Cumulative: 189138883
obj_slot = [UserSlot('Carson', 1) for _ in range(1000000)] # 77718299 <-- winner
obj_namedtuple = [UserTuple('Carson', 1) for _ in range(1000000)] # 85718297
print(guppy.hpy().heap()) # Run this function individually.
"""
Index Count % Size % Cumulative % Kind (class / dict of class)
0 1000000 24 112000000 34 112000000 34 dict of __main__.User
1 1000000 24 64000000 19 176000000 53 __main__.UserTuple
2 1000000 24 56000000 17 232000000 70 __main__.User
3 1000000 24 56000000 17 288000000 87 __main__.UserSlot
...
"""
if 'performance test':
obj = User('Carson', 1)
obj_slot = UserSlot('Carson', 1)
obj_tuple = UserTuple('Carson', 1)
time_normal = min(timeit.repeat(get_fn(obj, 'name'), repeat=20))
print(time_normal) # 0.12550550000000005
time_slot = min(timeit.repeat(get_fn(obj_slot, 'name'), repeat=20))
print(time_slot) # 0.1368690000000008
time_tuple = min(timeit.repeat(get_fn(obj_tuple, 'name'), repeat=20))
print(time_tuple) # 0.16006120000000124
print(time_tuple/time_slot) # 1.1694481584580898 # The slot is almost 17% faster than NamedTuple on Windows. (Python 3.7.7)
如果你的__dict__没有被使用,请在__slots__(更高的性能和存储)和NamedTuple(清晰的阅读和使用)之间选择。
您可以查看此链接(插槽的使用 )来获取更多的__slots__信息。
还可以按位置将初始化参数传递给实例变量
# Abstract struct class
class Struct:
def __init__ (self, *argv, **argd):
if len(argd):
# Update by dictionary
self.__dict__.update (argd)
else:
# Update by position
attrs = filter (lambda x: x[0:2] != "__", dir(self))
for n in range(len(argv)):
setattr(self, attrs[n], argv[n])
# Specific class
class Point3dStruct (Struct):
x = 0
y = 0
z = 0
pt1 = Point3dStruct()
pt1.x = 10
print pt1.x
print "-"*10
pt2 = Point3dStruct(5, 6)
print pt2.x, pt2.y
print "-"*10
pt3 = Point3dStruct (x=1, y=2, z=3)
print pt3.x, pt3.y, pt3.z
print "-"*10
就我个人而言,我也喜欢这种变体。它扩展了@dF的答案。
class struct:
def __init__(self, *sequential, **named):
fields = dict(zip(sequential, [None]*len(sequential)), **named)
self.__dict__.update(fields)
def __repr__(self):
return str(self.__dict__)
它支持两种初始化模式(可以混合使用):
# Struct with field1, field2, field3 that are initialized to None.
mystruct1 = struct("field1", "field2", "field3")
# Struct with field1, field2, field3 that are initialized according to arguments.
mystruct2 = struct(field1=1, field2=2, field3=3)
而且,它打印得更好:
print(mystruct2)
# Prints: {'field3': 3, 'field1': 1, 'field2': 2}