Структуры в C++ | OTUS
Один из способов определения пользовательских типов в языке программирования C++ заключается в использовании структур. Способ этот был унаследован еще от языка Си.
Структура — это производный тип данных, представляющий собой какую-либо конкретную определенную сущность, впрочем, как и класс. В связи с вышесказанным, применительно к языку C++ структуры нередко также называют классами. Говоря по правде, в реальной жизни различия между ними не так уж и велики.
Чтобы определить структуру, применяют ключевое слово struct. Что касается формата определения, то он выглядит так:
При этом Имя_структуры — это произвольный идентификатор, к которому применимы такие же правила, как и к наименованию переменных.
Далее после имени структуры в фигурных скобках помещают Компоненты_структуры — набор описаний объектов и функций, составляющих эту структуру.
Определение и инициализация
Рассмотрим, как это выглядит на примере. Определим простейшую структуру:
Итак, определена структура person, имеющая 2 элемента: age (тип int) и name (тип string).
После того, как структура определена, ее можно использовать. В начале можно определить объект структуры — речь идет, по сути, об обычной переменной, которая станет представлять созданный выше тип. Кроме того, после создания переменной структуры мы можем обращаться к ее элементам, получая их значения либо присваивая им новые значения. Чтобы обращаться к элементам структуры, используют операцию «точка»:
Опять же, повторимся, что по своей сути структура похожа на класс, что означает, что посредством структур мы тоже можем определять сущности в целях применения их в нашей программе. Одновременно с этим, все члены структуры, для которых не применяется спецификатор доступа (private, public), по дефолту являются открытыми (public). А в классе, как известно, все его члены, для которых спецификатор доступа не указан, являются закрытыми (private).
Идем дальше. У разработчика есть возможность инициализировать структуру путем присвоения ее переменным значений посредством синтаксиса инициализации:
Инициализация структур схожа с инициализацией массивов, для чего в фигурных скобках передают значения для элементов структуры по порядку. При этом, раз в структуре person первым определено свойство, представляющее тип int, то есть число, то и в скобках сначала идет число. Ну и так далее по порядку для всех элементов структуры.
Класс в виде структуры
Следующий момент — любой класс можно представить в качестве структуры и наоборот. Рассмотрим следующий класс:
Этот класс определяет сущность человека, а также содержит приватные и публичные переменные и функции. Однако для определения этой же сущности мы можем использовать вместо класса структуру:
При этом с точки зрения итогового результата работы программы большой разницы мы увидим.
Когда использовать структуры?
Обычно их используют при описании данных, имеющих лишь набор публичных атрибутов (речь идет об открытых переменных). К примеру, как структура person, определенная в начале статьи. В некоторых случаях такие сущности также называют aggregate classes.
По материалам сайта https://metanit.com/cpp.
Структуры в C
В C структура — это определяемая пользователем переменная, используемая для хранения коллекции переменных в рамках одной сущности. Давайте воспользуемся простой аналогией, чтобы объяснить реализацию и полезность структур в C.
Предположим, мы хотим хранить информацию о пользователях, использующих определенный сервис. Такая информация может включать имя пользователя, электронную почту, адрес, режим обслуживания и т.д. Чтобы сохранить такую информацию, мы можем создать каждый атрибут как отдельную переменную. Однако, когда у нас больше десяти пользователей, код может выйти из-под контроля и стать очень трудным и утомительным для чтения.
Чтобы решить эту проблему, мы можем создать структуру. Внутри структуры мы можем хранить все атрибуты, общие для всех пользователей, а затем добавлять уникальные переменные для каждого пользователя.
Давайте посмотрим на различные примеры, чтобы увидеть, как это реализовать.
Содержание
- Как определить структуру на C
- Как создать структурные переменные
- Член структуры Init
- Члены структуры доступа
- Ключевое слово Typedef
- Указатели структуры
- Заключение
Как определить структуру на C
Чтобы определить структуру в C, мы используем ключевое слово struct, за которым следует имя структуры. После имени у нас есть пара фигурных скобок, куда мы добавляем элементы.
Рассмотрим синтаксис ниже:
struct struct_name
{
/* data */
type member_name;
type member_name2;
type member_name3;…
type member_nameN;
};
Имя структуры может быть любым, если оно соответствует соглашению об именах языка программирования C.
Мы можем реализовать пример структуры пользовательской аналогии как:
struct users
{
char username[20];
char email[225];
char address[50];
int age;
bool registered;
};
Как создать структурные переменные
Есть два основных способа создания структурных переменных. Первый — объявить их как обычные переменные, а второй — установить их с помощью фигурных скобок.
В приведенном ниже примере показано, как объявить структурные переменные как стандартные переменные C.
struct users
{
char username[20];
char email[225];
char address[50];
int age;
bool registered;
};int main(int argc, char const *argv[])
{
struct users user1, user2, user3
return ;
}
Другой метод создания структурных переменных показан ниже:
struct users
{
char username[20];
char email[225];
char address[50];
int age;
bool registered;
} user1, user2, user3;
В этом примере мы создаем их во время объявления структуры.
Член структуры Init
Вы не можете инициализировать элементы структуры во время создания, поскольку для этого типа нет выделенной памяти.
Чтобы инициализировать элементы структуры, используйте фигурные скобки, как показано ниже:
struct users
{
char username[20];
char email[225];
char address[50];
int age;
bool registered;
};
int main(int argc, char const *argv[])
{
struct users user1 = {«myusername», «zero@user. name», 35, true}
return ;
}
Члены структуры доступа
Чтобы получить доступ к членам структуры, мы используем оператор точки, начиная с имени структуры, точки и имени члена.
struct users
{
char username[20];
char email[225];
char address[50];
int age;
bool registered;
};
int main(int argc, char const *argv[])
{
struct users user1 = {«myusername», «[email protected]», 35, true}
user1.email = «[email protected]»
return ;
}
В этом примере мы получаем доступ к членам user1.
Ключевое слово Typedef
Мы используем ключевое слово typedef для создания псевдонима для типов данных, что делает код более читабельным.
Например:
typedef struct users
{
char username[20];
char email[225];
char address[50];
int age;
bool registered;
} u;
int main(int argc, char const *argv[])
{
u user1 = {«myusername», «[email protected]», 35, true}
user1. registered = false
return ;
}
В приведенном выше примере мы создали псевдоним „u“ для структуры „users“. Следовательно, нам не нужно каждый раз вызывать struct users. Мы можем использовать „u“, как определено выше.
Указатели структуры
У вас также может быть указатель на структуру. Это позволяет получить доступ к членам с помощью оператора ->.
Например:
typedef struct users
{
char username[20];
char email[225];
char address[50];
int age;
bool registered;
} u;
int main(int argc, char const *argv[])
{
u user1 = {«myusername», «[email protected]», 35, true}// pointer to another structure
u *user_ptr = &user1
user_ptr -> username = «ptrusername»
return ;
}
Заключение
В этом руководстве рассматриваются основы работы со структурами на языке программирования C.
Простое руководство по использованию структур в C
Автор Джером Дэвидсон
Структуры — важная концепция C, которую необходимо понять. Как упрощенная версия класса, они могут предлагать такие преимущества, как удобочитаемость и повторное использование кода.
Структура (или структура) — это смешанный тип данных в C. Вы можете использовать его для хранения переменных разных типов.
Тип структуры сопоставим с классами в объектно-ориентированном программировании. Иногда вам может понадобиться присвоить значения объектам с одинаковыми свойствами. Вместо того, чтобы создавать несколько переменных для этих объектов в вашей программе на C, вы можете определить их в структура .
Создание структуры
Чтобы определить структуру, используйте ключевое слово
struct Car{
имя символа[45];
внутренние колеса;
двойная стоимость;
} ;
Вы можете определить несколько экземпляров Car , добавив объявления этих экземпляров после правой фигурной скобки в объявлении struct :
struct Car{
/* переменные */
} Car1, Car2, Car3;
Вы также можете вложить структуру в структуру. См. пример ниже:
адрес структуры {
int area_code;
символа street_name[45];
};
struct Person {
char name[60];
высота поплавка;
адрес структуры Persons_location;
};
Связанный: Советы по программированию на C, которые вы должны изучить, чтобы начать работу
Операции над типами структур
Инициализация
Существует три способа инициализации элементов структуры.Вы можете вставить значения, разделенные запятыми, в скобки {} , а затем присвоить их структуре. Обратите внимание, что значения должны быть в том же порядке, в котором вы объявили переменные.
struct Car Car1 = {"Грузовик", 10, 65000};
Связано: Руководство для начинающих по стандартной библиотеке шаблонов в C++
Вы также можете назначать значения, не обращая внимания на порядок их объявления. См. пример ниже.
struct Car Car2 = {
.cost = 45000,
. name = "Грузовик",
.wheels = 8
};
Третий способ инициализировать вашу структуру — назначить ей существующую структуру того же типа.
структура Автомобиль Автомобиль3 = Автомобиль1;
Доступ к элементам структуры
Чтобы получить доступ к значению, хранящемуся в элементе структуры, используйте оператор точки.
/* синтаксис:
structName.elementName */
int y = Car1.wheels;
Взгляд на объектно-ориентированное программирование
Как упоминалось в начале, struct сравнима с использованием классов в объектно-ориентированном программировании (ООП). Классы проще в использовании и позволяют повторно использовать код.
По этой и многим другим причинам был введен C++. C++ — это объектно-ориентированная версия C. Следующим в вашем списке для чтения должно быть понимание концепций ООП.
struct — C-подобные структуры в Python
Задавать вопрос
спросил
Изменено 2 года, 5 месяцев назад
Просмотрено 779 тысяч раз
Есть ли способ удобно определить C-подобную структуру в Python? Я устал писать такие вещи, как:
class MyStruct(): def __init__(я, поле1, поле2, поле3): само. поле1 = поле1 само.поле2 = поле2 self.field3 = поле3
- питон
- структура
10
Обновление : классы данныхС введением классов данных в Python 3.7 мы очень близки.
Следующий пример подобен приведенному ниже примеру NamedTuple , но результирующий объект mutable и допускает значения по умолчанию.
из классов данных импортировать класс данных @dataclass Класс Точка: х: плавающий у: плавать г: число с плавающей запятой = 0,0 р = точка (1,5, 2,5) print(p) # Точка(x=1.5, y=2.5, z=0.0)
Это прекрасно сочетается с новым модулем набора текста, если вы хотите использовать более конкретные аннотации типов.
Я так ждал этого! Если вы спросите меня, Data Classes и новое объявление NamedTuple в сочетании с модулем typing — это находка!
Улучшенное объявление NamedTuple
Начиная с Python 3. 6 стало довольно просто и красиво (ИМХО), пока можно жить с неизменностью .
Был представлен новый способ объявления NamedTuples, который также позволяет использовать аннотации типов:
из ввода import NamedTuple Пользователь класса (NamedTuple): название: ул. класс MyStruct (NamedTuple): фу: ул бар: инт баз: список qux: пользователь my_item = MyStruct('foo', 0, ['baz'], пользователь('питер')) print(my_item) # MyStruct(foo='foo', bar=0, baz=['baz'], qux=User(name='peter'))9
Используйте именованный кортеж, который был добавлен в модуль коллекций стандартной библиотеки в Python 2.6. Также можно использовать рецепт именованного кортежа Раймонда Хеттингера, если вам нужна поддержка Python 2.4.
Это хорошо для вашего базового примера, но также охватывает множество пограничных случаев, с которыми вы можете столкнуться позже. Ваш фрагмент выше будет записан как:
из коллекций import namedtuple МояСтруктура = namedtuple("МояСтруктура", "поле1 поле2 поле3")
Вновь созданный тип можно использовать следующим образом:
m = MyStruct("foo", "bar", "baz")
Вы также можете использовать именованные аргументы:
m = MyStruct(field1="foo", field2="bar", field3="baz")
8
Вы можете использовать кортеж для многих вещей, где вы использовали бы структуру в C (что-то вроде координат x, y или цветов RGB).
Для всего остального вы можете использовать словарь или служебный класс, подобный этому:
>>> class Bunch: ... def __init__(self, **kwds): ... self.__dict__.update(kwds) ... >>> mystruct = Bunch (поле1=значение1, поле2=значение2)
Я думаю, что «окончательное» обсуждение находится здесь, в опубликованной версии Поваренной книги Python.
5
Возможно, вы ищете структуры без конструкторов:
class Sample: имя = '' среднее = 0,0 values = None # Здесь нельзя инициализировать список! s1 = Образец () s1.name = "образец 1" s1.значения = [] s1.values.append(1) s1.values.append(2) s1.values.append(3) s2 = Образец () s2.name = "образец 2" s2.значения = [] s2.values.append(4) для v в s1.values: # печатает 1,2,3 --> ОК. напечатать v Распечатать "***" для v в s2.values: # печатает 4 --> OK. напечатать v
8
Как насчет словаря?
Примерно так:
myStruct = {'field1': 'some val', 'field2': 'some val'}
Затем вы можете использовать это для управления значениями:
print myStruct['field1'] myStruct['field2'] = 'некоторые другие значения'
И значения не обязательно должны быть строками. Они могут быть практически любым другим объектом.
2
dF: это довольно круто… я не знаю, что я мог получить доступ к полям в класс, использующий dict.
Марк: ситуации, которые я хотел бы иметь это именно тогда, когда я хочу кортеж но ничего такого «тяжелого», как толковый словарь.
Вы можете получить доступ к полям класса с помощью словаря, потому что поля класса, его методы и все его свойства хранятся внутри с помощью словарей (по крайней мере, в CPython).
…Что приводит нас к вашему второму комментарию. Вера в то, что словари Python «тяжелые», является крайне непитоновской концепцией. И чтение таких комментариев убивает мой Python Zen. Это не хорошо.
Видите ли, когда вы объявляете класс, вы на самом деле создаете довольно сложную оболочку для словаря, так что, во всяком случае, вы добавляете больше накладных расходов, чем при использовании простого словаря. Накладные расходы, которые, кстати, бессмысленны в любом случае. Если вы работаете над приложениями, критически важными для производительности, используйте C или что-то в этом роде.
1
Я также хотел бы добавить решение, использующее слоты:
class Point: __slots__ = ["х", "у"] def __init__(я, х, у): я.х = х селф.у = у
Определенно проверьте документацию по слотам, но краткое объяснение слотов заключается в том, что это способ python сказать: «Если вы можете заблокировать эти атрибуты и только эти атрибуты в классе таким образом, что вы фиксируете, что вы не будете добавлять новые атрибуты один раз создается экземпляр класса (да, вы можете добавить новые атрибуты в экземпляр класса, см. пример ниже), тогда я избавлюсь от выделения большого объема памяти, позволяющего добавлять новые атрибуты в экземпляр класса, и использовать только то, что мне нужно для этих слотированные атрибуты «.
Пример добавления атрибутов к экземпляру класса (без использования слотов):
class Point: def __init__(я, х, у): я.х = х селф.у = у p1 = точка (3,5) p1.z = 8 печать (p1.z)
Вывод: 8
Пример попытки добавить атрибуты в экземпляр класса, где использовались слоты:
class Point: __slots__ = ["х", "у"] def __init__(я, х, у): я.х = х селф.у = у p1 = точка (3,5) p1.z = 8
Вывод: AttributeError: объект «Point» не имеет атрибута «z»
Это может эффективно работать как структура и использовать меньше памяти, чем класс (как и структура, хотя я не исследовал точно, сколько). Рекомендуется использовать слоты, если вы будете создавать большое количество экземпляров объекта и вам не нужно добавлять атрибуты. Точечный объект является хорошим примером этого, поскольку вполне вероятно, что можно создать множество точек для описания набора данных.
1
Вы можете создать подкласс структуры C, доступной в стандартной библиотеке. Модуль ctypes предоставляет класс Structure. Пример из документации:
>>> from ctypes import * >>> класс POINT(Структура): ... _fields_ = [("x", c_int), ... ("у", c_int)] ... >>> точка = ПУНКТ(10, 20) >>> вывести точку.x, точку.y 10 20 >>> точка = ПУНКТ(y=5) >>> вывести точку.x, точку.y 0 5 >>> ТОЧКА(1, 2, 3) Traceback (последний последний вызов): Файл "", строка 1, в ? ValueError: слишком много инициализаторов >>> >>> класс RECT(Структура): ... _fields_ = [("верхний левый", POINT), ... ("внизу справа", POINT)] ... >>> rc = RECT(точка) >>> напечатать rc.upperleft.x, rc.upperleft.y 0 5 >>> напечатать rc.lowerright.x, rc.lowerright.y 0 0 >>>
0
Вы также можете передать параметры инициализации в переменные экземпляра по позиции
# Класс абстрактной структуры Структура класса: def __init__ (я, *argv, **argd): если длина (аргумент): # Обновление по словарю self. __dict__.update (argd) еще: # Обновление по позиции attrs = фильтр (лямбда x: x[0:2] != "__", dir(self)) для n в диапазоне (len (argv)): setattr(self, attrs[n], argv[n]) # Конкретный класс класс Point3dStruct (Структура): х = 0 у = 0 г = 0 pt1 = Point3dStruct() pt1.x = 10 распечатать pt1.x напечатать "-"*10 pt2 = Point3dStruct(5, 6) распечатать pt2.x, pt2.y напечатать "-"*10 pt3 = Point3dStruct (x=1, y=2, z=3) напечатать pt3.x, pt3.y, pt3.z напечатать "-"*10
2
Всякий раз, когда мне нужен «мгновенный объект данных, который также ведет себя как словарь» (я не думаю о структурах C!), я думаю об этом милом хаке:
class Map(dict): def __init__(я, **kwargs): super(Map, self).__init__(**kwargs) self.__dict__ = я
Теперь вы можете просто сказать:
struct = Map(field1='foo', field2='bar', field3=42) self. assertEquals('bar', struct.field2) self.assertEquals (42, структура ['field3'])
Идеально подходит для тех случаев, когда вам нужен «пакет данных, который НЕ является классом», и когда именованные кортежи непонятны…
1
Некоторые ответы здесь очень сложные. Самый простой вариант, который я нашел, это (от: http://norvig.com/python-iaq.html):
class Struct: «Структура, в которой могут быть определены любые поля». def __init__(self, **entries): self.__dict__.update(entries)
Инициализация:
>>> options = Struct(answer=42, linelen=80, font='courier') >>> варианты.ответ 42
добавляем еще:
>>> options.cat = "собака" >>> варианты.cat собака
изменить: Извините, что не видел этот пример ниже.
2
Вы получаете доступ к структуре C-Style в python следующим образом.
класс cstruct: переменная_i = 0 переменная_f = 0,0 var_str = ""
объект = cstruct () obj.var_i = 50 obj.var_f = 50,00 obj.var_str = "пятьдесят" print "cstruct: obj i=%d f=%f s=%s" %(obj.var_i, obj.var_f, obj.var_str)
obj_array = [cstruct() для i в диапазоне (10)] obj_array[0].var_i = 10 obj_array[0].var_f = 10,00 obj_array[0].var_str = "десять" # идем дальше и заполняем оставшиеся экземпляры массива структурой #распечатать все значение для я в диапазоне (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)
Примечание: вместо имени «cstruct» используйте имя своей структуры вместо var_i, var_f, var_str определите переменную-член вашей структуры.
1
Это может быть немного поздно, но я сделал решение, используя метаклассы Python (версия декоратора также ниже).
Когда __init__
вызывается во время выполнения, он захватывает каждый из аргументов и их значение и назначает их как переменные экземпляра для вашего класса. Таким образом, вы можете создать структуроподобный класс без необходимости вручную назначать каждое значение.
В моем примере нет проверки ошибок, поэтому его легче понять.
класс MyStruct (тип): def __call__(cls, *args, **kwargs): имена = cls.__init__.func_code.co_varnames[1:] self = type.__call__(cls, *args, **kwargs) для имени, значение в zip (имена, аргументы): setattr(я, имя, значение) для имени значение в kwargs.iteritems(): setattr(я, имя, значение) вернуть себя
Вот он в действии.
>>> класс MyClass(объект): __metaclass__ = МояСтруктура def __init__(я, а, б, в): проходить >>> мой_экземпляр = МойКласс(1, 2, 3) >>> my_instance.a 1 >>>
Я разместил его на Reddit, а /u/matchu опубликовал более чистую версию декоратора. Я бы посоветовал вам использовать его, если вы не хотите расширять версию метакласса.
>>> по умолчанию init_all_args(fn): @обертки(fn) def wrapper_init(self, *args, **kwargs): имена = fn. func_code.co_varnames[1:] для имени, значение в zip (имена, аргументы): setattr(я, имя, значение) для имени значение в kwargs.iteritems(): setattr(я, имя, значение) вернуть завернутый_инит >>> Тест класса (объект): @init_all_args def __init__(я, а, б): проходить >>> а = тест (1, 2) >>> а.а. 1 >>>
2
Я написал декоратор, который можно использовать для любого метода, чтобы все переданные аргументы или любые значения по умолчанию присваивались экземпляру.
def argumentsToAttributes (метод): имя_аргумента = method.func_code.co_varnames[1:] # Создать словарь значений по умолчанию: defaultsDict = {} defaults = method.func_defaults if method.func_defaults else () для i значение по умолчанию в перечислении (значения по умолчанию, начало = len (имена аргументов) - len (значения по умолчанию)): defaultsDict[имя_аргумента[i]] = по умолчанию def newMethod(self, *args, **kwargs): # Используйте позиционные аргументы. для имени, значение в zip(argumentNames, args): setattr(я, имя, значение) # Добавьте аргументы ключевого слова. Если чего-то не хватает, используйте значение по умолчанию. для имени в argumentsNames[len(args):]: setattr (я, имя, kwargs.get (имя, defaultsDict [имя])) # Запустить все, что еще нужно сделать методу. метод(я, *args, **kwargs) вернуть новый метод
Быстрая демонстрация. Обратите внимание, что я использую позиционный аргумент a
, использую значение по умолчанию для b
и именованный аргумент c
. Затем я печатаю все 3 ссылки на self
, чтобы показать, что они были правильно назначены до ввода метода.
класс А (объект): @argumentsToAttributes def __init__(self, a, b = 'Невидимый', c = 'Привет'): распечатать (я) распечатать (я.б) печать (я.с) А('Почему', с = 'Ничего')
Обратите внимание, что мой декоратор должен работать с любым методом, а не только с __init__
.
Я не вижу здесь этого ответа, поэтому думаю, что добавлю его, так как сейчас я склоняюсь к Python и только что обнаружил его. Учебное пособие по Python (в данном случае Python 2) дает следующий простой и эффективный пример:
class Employee: проходить john = Employee() # Создать пустую запись сотрудника # Заполняем поля записи john.name = 'Джон Доу' john.dept = 'компьютерная лаборатория' джон.зарплата = 1000
То есть создается пустой объект класса, затем создается экземпляр, и поля добавляются динамически.
Преимущество этого в том, что он действительно прост. Недостатком является то, что он не особенно самодокументирован (предполагаемые члены нигде не перечислены в «определении» класса), а неустановленные поля могут вызвать проблемы при доступе. Эти две проблемы могут быть решены с помощью:
class Сотрудник: защита __init__ (сам): self.name = None # или что-то подобное self.dept = Нет self.salary = Нет
Теперь с первого взгляда можно хотя бы увидеть, какие поля будут ожидаться программой.
Оба склонны к опечаткам, john.slarly = 1000
получится. Тем не менее, это работает.
Вот решение, в котором для хранения данных используется класс (никогда не созданный). Мне нравится, что этот способ почти не требует набора текста и не требует дополнительных пакетов и т. д.
class myStruct: поле1 = "один" поле2 = "2"
При необходимости вы можете добавить дополнительные поля позже:
myStruct.field3 = 3
Для получения значений поля доступны как обычно:
>>> myStruct.field1 'один'
4
Лично мне этот вариант тоже нравится. Он расширяет ответ @dF.
структура класса: def __init__(self, *sequential, **named): fields = dict(zip(sequential, [None]*len(sequential)), **named) self.__dict__.update(поля) защита __repr__(сам): вернуть строку (я.__dict__)
Поддерживает два режима инициализации (которые можно комбинировать):
# Структура с полем1, полем2, полем3, которые инициализируются значением Нет. mystruct1 = struct("поле1", "поле2", "поле3") # Структура с field1, field2, field3, которые инициализируются в соответствии с аргументами. mystruct2 = структура (поле1 = 1, поле2 = 2, поле3 = 3)
Кроме того, он печатает лучше:
print(mystruct2) # Выводит: {'field3': 3, 'field1': 1, 'field2': 2}
Именно для этой цели существует пакет python. см. cstruct2py
cstruct2py
— это чистая библиотека Python для создания классов Python из кода C и использования их для упаковки и распаковки данных. Библиотека может анализировать заголовки C (объявления структур, объединений, перечислений и массивов) и эмулировать их в python. Сгенерированные классы Python могут анализировать и упаковывать данные.
Например:
typedef struct { интервал х; инт у; } Точка; после создания класса pythonic... р = точка (х = 0x1234, у = 0x5678) p.packed == "\x34\x12\x00\x00\x78\x56\x00\x00"
Как пользоваться
Сначала нам нужно сгенерировать pythonic структуры:
import cstruct2py парсер = cstruct2py. c2py.Parser() parser.parse_file('примеры/example.h')
Теперь мы можем импортировать все имена из кода C:
parser.update_globals(globals())
Мы также можем сделать это напрямую:
A = parser.parse_string('struct A { int x; int y;};')
Использование типов и определений из кода C
a = A() ах = 45 распечатать buf = a.packed б = А (баф) печатать б с = А('аааа11112222', 2) печатать с печать репр(с)
Вывод будет:
{'x':0x2d, 'y':0x0} {'х': 0x2d, 'у': 0x0} {'х': 0x31316161, 'у': 0x32323131} А('аа111122', х=0x31316161, у=0x32323131)
Клон
Для клона cstruct2py
запустите:
git clone https://github.com/st0ky/cstruct2py.git --recursive
0
Вот быстрый и грязный трюк:
>>> ms = Warning() >>> мс.foo = 123 >>> ms.bar = 'акафрит'
Как это работает? Он просто повторно использует встроенный класс Warning
(производный от Exception
) и использует его так, как это был ваш собственный определенный класс.
Положительные моменты в том, что вам не нужно ничего сначала импортировать или определять, что «Предупреждение» — это короткое имя, и это также дает понять, что вы делаете что-то грязное, что не должно использоваться где-либо еще, кроме вашего небольшого скрипта. .
Кстати, я пытался найти что-то еще проще, например, ms = object()
, но не смог (последний пример не работает). Если у вас есть, мне интересно.
0
NamedTuple удобен. но там производительность и память никто не разделяет.
от ввода импорта NamedTuple import guppy # pip install guppy импортировать время Пользователь класса: def __init__(self, name: str, uid: int): self.name = имя self.uid = идентификатор пользователя класс UserSlot: __slots__ = ('имя', 'идентификатор пользователя') def __init__(self, name: str, uid: int): self.name = имя self.uid = идентификатор пользователя класс UserTuple (NamedTuple): # __slots__ = () # AttributeError: невозможно перезаписать атрибут NamedTuple __slots__ название: ул. идентификатор: интервал def get_fn(obj, attr_name: str): деф получить(): getattr(obj, attr_name) вернуть получить
, если «проверка памяти»: obj = [User('Carson', 1) for _ in range(1000000)] # Всего: 189138883 obj_slot = [UserSlot('Carson', 1) for _ in range(1000000)] # 77718299 <-- победитель obj_namedtuple = [UserTuple('Carson', 1) for _ in range(1000000)] # 85718297 print(guppy.hpy().heap()) # Запускаем эту функцию отдельно. """ Количество индексов % Размер % Совокупный % Вид (класс / определение класса) 0 1000000 24 112000000 34 112000000 34 dict of __main__.User 1 1000000 24 64000000 19176000000 53 __main__.UserTuple 2 1000000 24 56000000 17 232000000 70 __main__.Пользователь 3 1000000 24 56000000 17 288000000 87 __main__.UserSlot ... """ если «тест производительности»: obj = Пользователь('Карсон', 1) obj_slot = UserSlot('Карсон', 1) obj_tuple = UserTuple('Карсон', 1) time_normal = мин (timeit. repeat (get_fn (объект, 'имя'), повтор = 20)) print(time_normal) # 0.12550550000000005 time_slot = min (timeit.repeat (get_fn (obj_slot, 'имя'), повтор = 20)) печать (временной_слот) # 0.13686000008 time_tuple = мин (timeit.repeat (get_fn (obj_tuple, 'имя'), повтор = 20)) print(time_tuple) # 0.16006120000000124 print(time_tuple/time_slot) # 1.1694481584580898 # Слот почти на 17% быстрее, чем NamedTuple в Windows. (Питон 3.7.7)
Если ваш __dict__
не используется, выберите между __slots__
(более высокая производительность и хранилище) и NamedTuple
(очистить для чтения и использования)
Вы можете просмотреть эту ссылку (использование слотов ), чтобы получить больше __slots__
информации.
https://stackoverflow.com/a/32448434/159695 не работает в Python3.
https://stackoverflow.com/a/35993/159695 работает в Python3.
И я расширяю его, добавляя значения по умолчанию.
класс myStruct: def __init__(я, **kwds): селф.х=0 self.__dict__.update(kwds) # Должен быть последним, чтобы принять назначенную переменную-член. защита __repr__(сам): args = ['%s=%s' % (k, repr(v)) для (k,v) в vars(self).items()] вернуть '%s(%s)' % ( self.__class__.__qualname__, ', '.join(args)) а=мояСтруктура() б = моя структура (х = 3, у = 'тест') c=myStruct(x='str') >>> а моя структура (х = 0) >>> б myStruct(x=3, y='тест') >>> с мояСтруктура(х='строка')
1
Следующее решение структуры основано на реализации namedtuple и некоторых предыдущих ответах. Однако, в отличие от namedtuple, он является изменчивым в своих значениях, но, как и структура c-стиля, неизменяемой в именах/атрибутах, чего нет в обычном классе или словаре.
_class_template = """\ класс {имя_типа}: def __init__(я, *args, **kwargs): поля = {имена_полей!r} для х в полях: setattr(я, х, нет) для имени, значение в zip (поля, аргументы): setattr(я, имя, значение) для имени значение в kwargs. items(): setattr(я, имя, значение) защита __repr__(сам): вернуть ул (вары (сам)) def __setattr__(я, имя, значение): если имя отсутствует в {field_names!r}: поднять KeyError("недопустимое имя: %s" % имя) object.__setattr__(я, имя, значение) """ структура def (имя_типа, имена_полей): class_definition = _class_template.format( имя_типа = имя_типа, имена_полей = имена_полей) namespace = dict(__name__='struct_%s' % typename) exec (определение_класса, пространство имен) результат = пространство имен [имя типа] результат._источник = определение_класса вернуть результат
Использование:
Person = struct('Person', ['firstname','lastname']) универсальный = человек () Майкл = Человек('Майкл') Джонс = Человек (фамилия = 'Джонс') В [168]: michael.middlename = 'бен' Traceback (последний последний вызов): Файл "", строка 1, в michael.middlename = 'бен' Файл " ", строка 19, в __setattr__ KeyError: 'недопустимое имя: отчество'
Если у вас нет 3. 7 для @dataclass и вам нужна изменяемость, вам может подойти следующий код. Он достаточно самодокументирован и удобен для IDE (автозаполнение), предотвращает повторную запись, легко расширяется, и очень просто проверить, что все переменные экземпляра полностью инициализированы:
класс Params(): защита __init__(сам): self.var1 : int = Нет self.var2 : ул = Нет защита are_all_defined (я): для ключа, значение в self.__dict__.items(): assert (значение не None), "переменная экземпляра {} по-прежнему None".format(key) вернуть Истина параметры = параметры () параметры.var1 = 2 params.var2 = 'привет' утверждать (params.are_all_defined)
Лучший способ сделать это — использовать собственный класс словаря, как описано в этом сообщении: https://stackoverflow.com/a/14620633/8484485
Если требуется поддержка автодополнения iPython, просто определите функцию dir () следующим образом:
class AttrDict(dict): def __init__(я, *args, **kwargs): super(AttrDict, self).