C-подобные структуры в Python
Как можно удобно определить структуру, подобную C, в Python? Я устал постоянно писать подобное:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
Есть ли более простой и эффективный способ создания такой структуры данных в Python?
5 ответ(ов)
Вы, вероятно, ищете структуры без конструкторов. Вот пример, иллюстрирующий это:
class Sample:
name = ''
average = 0.0
values = None # список нельзя инициализировать здесь!
s1 = Sample()
s1.name = "sample 1"
s1.values = [] # инициализация списка для первого экземпляра
s1.values.append(1)
s1.values.append(2)
s1.values.append(3)
s2 = Sample()
s2.name = "sample 2"
s2.values = [] # инициализация списка для второго экземпляра
s2.values.append(4)
for v in s1.values: # выводит 1, 2, 3 --> ОК.
print(v)
print("***")
for v in s2.values: # выводит 4 --> ОК.
print(v)
Обратите внимание, что в этом примере каждый экземпляр класса Sample
имеет свой собственный список values
, который инициализируется после создания экземпляра. Это важно, поскольку если бы мы инициализировали его на уровне класса, все экземпляры ссылались бы на один и тот же объект списка, что может привести к неожиданным результатам.
Вы можете использовать словарь для хранения данных. Например, вы можете определить словарь следующим образом:
myStruct = {'field1': 'некое значение', 'field2': 'другое значение'}
После этого вы сможете работать с его значениями:
print(myStruct['field1'])
myStruct['field2'] = 'какие-то другие значения'
Обратите внимание, что значения в словаре не обязательно должны быть строками. Они могут быть любыми другими объектами.
Вы можете обращаться к полям класса, используя словарь, потому что поля класса, его методы и все свойства хранятся внутренне с помощью словарей (по крайней мере, в CPython).
Что касается вашего второго комментария. Вера в то, что словари в Python "тяжеловесные", — это крайне непайтоновское представление. Чтение подобных комментариев убивает мой Python Zen, а это нехорошо.
Когда вы объявляете класс, на самом деле вы создаете довольно сложную обертку вокруг словаря. Таким образом, в этом смысле вы добавляете больше накладных расходов, чем при использовании простого словаря. Накладные расходы, которые, кстати, не имеют значения в любом случае. Если вы работаете над производительными приложениями, используйте C или что-то подобное.
Вы также можете передавать параметры инициализации в переменные экземпляра по позициям.
# Абстрактный класс структуры
class Struct:
def __init__ (self, *argv, **argd):
if len(argd):
# Обновление по словарю
self.__dict__.update(argd)
else:
# Обновление по позициям
attrs = filter(lambda x: x[0:2] != "__", dir(self))
for n in range(len(argv)):
setattr(self, attrs[n], argv[n])
# Конкретный класс
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)
В этом примере класс Struct
предоставляет базовую функциональность для инициализации атрибутов как по позиционным аргументам, так и по ключевым. Класс Point3dStruct
наследуется от Struct
и имеет три атрибута: x
, y
и z
. Вы можете создать экземпляры этого класса и инициализировать атрибуты как по позициям (в pt2
), так и по именам (в pt3
).
Когда мне нужен "мгновенный объект данных, который также ведет себя как словарь" (Я не думаю о структурах C!), я вспоминаю этот классный хак:
class Map(dict):
def __init__(self, **kwargs):
super(Map, self).__init__(**kwargs)
self.__dict__ = self
Теперь вы можете просто сказать:
struct = Map(field1='foo', field2='bar', field3=42)
self.assertEquals('bar', struct.field2)
self.assertEquals(42, struct['field3'])
Это идеально подходит для случаев, когда вам нужен "мешок данных, который НЕ является классом", и когда именованные кортежи непонятны...
Как клонировать список, чтобы он не изменялся неожиданно после присваивания?
Преобразование списка словарей в DataFrame pandas
Как отсортировать список/кортеж списков/кортежей по элементу на заданном индексе
Как отменить последнюю миграцию?
Как явно освободить память в Python?