对于Python结构,使用具有有意义的字段名值的数组是否不是pythonic?
我看到了一些关于如何在Python中实现C对于Python结构,使用具有有意义的字段名值的数组是否不是pythonic?,python,struct,Python,Struct,我看到了一些关于如何在Python中实现Cstruct之类的东西的问题。通常人们建议使用namedtuple,但问题是,它的字段是不可变的,我认为不可变的结构没有多大意义,因此如果需要,建议使用dictionary,在我看来,这太冗长了-必须用引号将字段名括起来,它必须非常慢-您必须搜索字段值 我从来没有看到过对我来说似乎是自然的解决方案: i = -1 i += 1 FIELD_A = i i += 1 FIELD_B = i i += 1 FIELD_C = i structure
struct
之类的东西的问题。通常人们建议使用namedtuple
,但问题是,它的字段是不可变的,我认为不可变的结构没有多大意义,因此如果需要,建议使用dictionary
,在我看来,这太冗长了-必须用引号将字段名括起来,它必须非常慢-您必须搜索字段值
我从来没有看到过对我来说似乎是自然的解决方案:
i = -1
i += 1
FIELD_A = i
i += 1
FIELD_B = i
i += 1
FIELD_C = i
structure = [ 0, "foo", "bar" ]
structure[FIELD_A] = 1
执行i
操作的原因是,它允许复制和粘贴,而不可能两次指定相同的值或浪费空间。使用大写字母的原因是为了使这些值成为“常量”
我是不是太天真了,上面的代码有什么问题,或者不是Pythonic?使用dict替代您的代码:
structure = {}
structure["FIELD1"] = 0
structure["FIELD2"] = "foo"
structure["FIELD3"] = "bar
在我看来,代码行更少,可读性更高,因为您不必怀疑i
到底在做什么。在MATLAB中工作时,我实际上使用了上述方法,因为没有方便的dict替代方法
此外,如果您发现大写字母更具可读性,那么没有什么可以阻止您使用大写字母。使用dict的代码的替代方案:
structure = {}
structure["FIELD1"] = 0
structure["FIELD2"] = "foo"
structure["FIELD3"] = "bar
在我看来,代码行更少,可读性更高,因为您不必怀疑i
到底在做什么。在MATLAB中工作时,我实际上使用了上述方法,因为没有方便的dict替代方法
此外,如果您觉得大写字母更具可读性,那么没有什么可以阻止您使用大写字母。我认为最接近C-struct的类比,以Python的方式,应该是具有命名属性的Python对象 繁琐的方式:
class mystruct:
def __init__(self):
self.FIELD1 = None
self.FIELD2 = None
self.FIELD3 = None
x = mystruct()
x.FIELD1 = 42
x.FIELD3 = "aap"
可以使用type
功能创建具有多个属性的匿名对象:
y = type('', (), {'FIELD1': None, 'FIELD2':None})()
y.FIELD1 = 42
但这仍然很麻烦。但这可以通过编写一个函数来实现,该函数返回一个将创建对象实例的函数
# 'objmaker' takes a list of field names and returns a function
# which will create an instance of an object with those fields, their
# values initially set to None
objmaker = lambda *fields: type('', (), {field: None for field in fields})
# Now it's trivial to define new 'structs' - here we 'define' two
# types of 'structs'
mystruct_maker = objmaker('FIELD1', 'FIELD2', 'FIELD3')
yourstruct_maker = objmaker('x', 'y')
# And creating instances goes like this:
my_str1 = mystruct_maker()
my_str2 = mystruct_maker()
yr_str = yourstruct_maker()
yr_str.x = 42
my_str1.FIELD1 = yr_str.x
class MyStruct(object):
FIELD1 = 0
FIELD2 = 'foo'
FIELD3 = 'bar'
print(MyStruct.FIELD2)
s = MyStruct()
s.FIELD2 = 'baz'
print(s.FIELD2)
class MySlots(object):
__slots__ = ['FIELD1', 'FIELD2', 'FIELD3']
def __init__(self, FIELD1=0, FIELD2='foo', FIELD3='bar'):
self.FIELD1 = FIELD1
self.FIELD2 = FIELD2
self.FIELD3 = FIELD3
s = MySlots()
print(s.FIELD2)
我认为,以Python的方式,与C-struct最接近的类比应该是具有命名属性的Python对象 繁琐的方式:
class mystruct:
def __init__(self):
self.FIELD1 = None
self.FIELD2 = None
self.FIELD3 = None
x = mystruct()
x.FIELD1 = 42
x.FIELD3 = "aap"
可以使用type
功能创建具有多个属性的匿名对象:
y = type('', (), {'FIELD1': None, 'FIELD2':None})()
y.FIELD1 = 42
但这仍然很麻烦。但这可以通过编写一个函数来实现,该函数返回一个将创建对象实例的函数
# 'objmaker' takes a list of field names and returns a function
# which will create an instance of an object with those fields, their
# values initially set to None
objmaker = lambda *fields: type('', (), {field: None for field in fields})
# Now it's trivial to define new 'structs' - here we 'define' two
# types of 'structs'
mystruct_maker = objmaker('FIELD1', 'FIELD2', 'FIELD3')
yourstruct_maker = objmaker('x', 'y')
# And creating instances goes like this:
my_str1 = mystruct_maker()
my_str2 = mystruct_maker()
yr_str = yourstruct_maker()
yr_str.x = 42
my_str1.FIELD1 = yr_str.x
class MyStruct(object):
FIELD1 = 0
FIELD2 = 'foo'
FIELD3 = 'bar'
print(MyStruct.FIELD2)
s = MyStruct()
s.FIELD2 = 'baz'
print(s.FIELD2)
class MySlots(object):
__slots__ = ['FIELD1', 'FIELD2', 'FIELD3']
def __init__(self, FIELD1=0, FIELD2='foo', FIELD3='bar'):
self.FIELD1 = FIELD1
self.FIELD2 = FIELD2
self.FIELD3 = FIELD3
s = MySlots()
print(s.FIELD2)
“它一定很慢-你必须搜索字段值。”如果你认为字典查找很慢,那么python会给你一系列心脏病发作。考虑
foo = 'somestring'
bar = bar
baz = someobj.variable
Python计算了'somestring'
的哈希值,因为它在创建所有字符串时都会这样做。每次我们提到它们时,它都会在模块的名称空间中向上看foo
和bar
。访问对象变量需要在对象的dict
中查找它们
获得类似结构的行为的两种方法是定义类级别的变量或使用\uuuuu slots\uuuu
为对象定义一组固定的变量
# 'objmaker' takes a list of field names and returns a function
# which will create an instance of an object with those fields, their
# values initially set to None
objmaker = lambda *fields: type('', (), {field: None for field in fields})
# Now it's trivial to define new 'structs' - here we 'define' two
# types of 'structs'
mystruct_maker = objmaker('FIELD1', 'FIELD2', 'FIELD3')
yourstruct_maker = objmaker('x', 'y')
# And creating instances goes like this:
my_str1 = mystruct_maker()
my_str2 = mystruct_maker()
yr_str = yourstruct_maker()
yr_str.x = 42
my_str1.FIELD1 = yr_str.x
class MyStruct(object):
FIELD1 = 0
FIELD2 = 'foo'
FIELD3 = 'bar'
print(MyStruct.FIELD2)
s = MyStruct()
s.FIELD2 = 'baz'
print(s.FIELD2)
class MySlots(object):
__slots__ = ['FIELD1', 'FIELD2', 'FIELD3']
def __init__(self, FIELD1=0, FIELD2='foo', FIELD3='bar'):
self.FIELD1 = FIELD1
self.FIELD2 = FIELD2
self.FIELD3 = FIELD3
s = MySlots()
print(s.FIELD2)
这些可能是令人愉快的,但它们并不比使用dict快多少。“它一定很慢-您必须搜索字段值。”如果您认为字典查找很慢,那么python将给您带来一连串的心脏病发作。考虑
foo = 'somestring'
bar = bar
baz = someobj.variable
Python计算了'somestring'
的哈希值,因为它在创建所有字符串时都会这样做。每次我们提到它们时,它都会在模块的名称空间中向上看foo
和bar
。访问对象变量需要在对象的dict
中查找它们
获得类似结构的行为的两种方法是定义类级别的变量或使用\uuuuu slots\uuuu
为对象定义一组固定的变量
# 'objmaker' takes a list of field names and returns a function
# which will create an instance of an object with those fields, their
# values initially set to None
objmaker = lambda *fields: type('', (), {field: None for field in fields})
# Now it's trivial to define new 'structs' - here we 'define' two
# types of 'structs'
mystruct_maker = objmaker('FIELD1', 'FIELD2', 'FIELD3')
yourstruct_maker = objmaker('x', 'y')
# And creating instances goes like this:
my_str1 = mystruct_maker()
my_str2 = mystruct_maker()
yr_str = yourstruct_maker()
yr_str.x = 42
my_str1.FIELD1 = yr_str.x
class MyStruct(object):
FIELD1 = 0
FIELD2 = 'foo'
FIELD3 = 'bar'
print(MyStruct.FIELD2)
s = MyStruct()
s.FIELD2 = 'baz'
print(s.FIELD2)
class MySlots(object):
__slots__ = ['FIELD1', 'FIELD2', 'FIELD3']
def __init__(self, FIELD1=0, FIELD2='foo', FIELD3='bar'):
self.FIELD1 = FIELD1
self.FIELD2 = FIELD2
self.FIELD3 = FIELD3
s = MySlots()
print(s.FIELD2)
这些可能令人愉快,但它们并不比使用
口述快
我感谢所有其他答案,但它们并不能真正回答问题。问题是“我的代码出了什么问题”,而不是“编码xyz的最佳方式是什么”
我发现错的是,我引入了一组“全局”常数。如果我有另一个带有
字段A
的结构,我就有麻烦了<代码>字段_A应具有结构范围,而不是全局范围。这是我所做的不符合标准的一个重要原因。我很欣赏所有其他答案,但它们并不能真正回答问题。问题是“我的代码出了什么问题”,而不是“编码xyz的最佳方式是什么”
我发现错的是,我引入了一组“全局”常数。如果我有另一个带有
字段A
的结构,我就有麻烦了<代码>字段_A应具有结构范围,而不是全局范围。这是我所做的不符合标准的一个重要原因。字典并不慢……它们通常实现为非常快的哈希表查找。此外,您不必将键名放在引号中,您可以使用任何不可变类型作为键…实际上,您已经将键映射到了这里的整数。最后,我不会考虑把引号作为“VBOSE”和“不是”之间的区别。@ GAREPPY当然要查找一个字符串的哈希值,你必须对整个字符串进行评估并计算哈希值,也许这是快的,但是肯定比查找数组中的值慢。这取决于你在做什么。你所拥有的实际上是一个列表,一旦列表变大,添加到列表中的速度就会变慢。无论大小,添加到dict几乎都是一个常量时间操作。为什么不使用类呢?它们将是可变的,并且比DICT快得多