В некотором роде алгебраические типы данных были бы абсолютно замечательными, но для их правильного использования обычно требуется сопоставление с образцом.
Эдвард З. Ян
51
Что-то не так с этим методом, кроме как утомительно писать?
@levesque труднее переформулировать без опечаток, сложнее читать с MyStruct = namedtuple("MyStruct", "field1 field2 field3")
первого
1
pandas.Series(a=42).aдолжен сделать это, если вы специалист по данным ...
Марк Хорват
Ответы:
341
Используйте именованный кортеж , который был добавлен в модуль коллекций в стандартной библиотеке Python 2.6. Также возможно использовать именованный кортеж Раймонда Хеттингера рецепт если вам нужна поддержка Python 2.4.
Это хорошо для вашего базового примера, но также охватывает множество крайних случаев, с которыми вы можете столкнуться позже. Ваш фрагмент выше будет записан как:
from collections import namedtuple
MyStruct= namedtuple("MyStruct","field1 field2 field3")
Вновь созданный тип может использоваться следующим образом:
m =MyStruct("foo","bar","baz")
Вы также можете использовать именованные аргументы:
m =MyStruct(field1="foo", field2="bar", field3="baz")
... но именованный кортеж неизменен. Пример в ОП изменчив.
Mhowison
28
@mhowison - В моем случае это просто плюс.
ArtOfWarfare
3
Хорошее решение. Как бы вы перебрали массив этих кортежей? Я бы предположил, что поля 1-3 должны иметь одинаковые имена для всех объектов кортежа.
Майкл Смит
2
namedtuple может иметь не более четырех аргументов, поэтому как мы можем отобразить структуру с большим количеством членов данных с соответствующим namedtuple
Kapil
3
@Kapil - Второй аргумент namedtuple должен быть списком имен членов. Этот список может быть любой длины.
ArtOfWarfare,
228
Обновить : классы данных
С введением классов данных в Python 3.7 мы стали очень близки.
Следующий пример похож на пример NamedTuple ниже, но результирующий объект является изменяемым и допускает значения по умолчанию.
from dataclasses import dataclass
@dataclassclassPoint:
x: float
y: float
z: float =0.0
p =Point(1.5,2.5)print(p)# Point(x=1.5, y=2.5, z=0.0)
Это прекрасно работает с новым модулем набора текста, если вы хотите использовать более конкретные аннотации типов.
Я отчаянно ждал этого! Если вы спросите меня, классы данных и новое объявление NamedTuple в сочетании с модулем набора текста - это находка!
Улучшено объявление NamedTuple
Начиная с Python 3.6 он стал довольно простым и красивым (ИМХО), пока можно жить с неизменностью .
from typing importNamedTupleclassUser(NamedTuple):
name: str
classMyStruct(NamedTuple):
foo: str
bar: int
baz: list
qux:User
my_item =MyStruct('foo',0,['baz'],User('peter'))print(my_item)# MyStruct(foo='foo', bar=0, baz=['baz'], qux=User(name='peter'))
Обратите внимание, если вы новичок в Python: кортежи доступны только для чтения, в отличие от структур C
LeBleu
2
@KurtLiu Нет, это, вероятно, сказал быTypeError: this constructor takes no arguments
Евгений Сергеев
84
Возможно, вы ищете структуры без конструкторов:
classSample:
name =''
average =0.0
values =None# list cannot be initialized here!
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:# prints 1,2,3 --> OK.print v
print"***"for v in s2.values:# prints 4 --> OK.print v
То, что вы здесь делаете, технически работает, но многим пользователям, вероятно, не сразу понятно, почему это работает. Ваши декларации class Sample:не сразу делают что-либо; они устанавливают атрибуты класса. К ним всегда можно получить доступ, например Sample.name.
Ченнинг Мур
22
На самом деле вы добавляете свойства экземпляра к объектам s1и s2во время выполнения. Если не запрещено иное, вы можете добавлять или изменять nameатрибут в любом экземпляре любого класса в любое время, независимо от того, имеет ли класс nameатрибут. Вероятно, самая большая функциональная проблема заключается в том, что разные экземпляры одного и того же класса будут вести себя по-разному в зависимости от того, установлен ли вы name. Если вы обновите Sample.name, любые объекты без явно установленного nameсвойства вернут новое name.
Ченнинг Мур
2
Это так же близко, как и к struct - short 'class' без методов, 'fields' (атрибуты класса, я знаю) со значениями по умолчанию. Пока это не изменяемый тип (dict, list), все в порядке. Конечно, вы можете выполнить проверку PEP-8 или «дружественные» проверки IDE, например, у «класса PyCharm нет метода init ».
Томаш Гандор
4
Я экспериментировал с побочным эффектом, описанным Ченнингом Муром. Не стоит экономия нескольких selfключевых слов и строки конструктора, если вы спросите меня. Я был бы признателен, если бы Хосе мог отредактировать свой ответ, добавив предупреждающее сообщение о риске случайного обмена значениями между экземплярами.
Стефан С.
@ChanningMoore: Я пытался воссоздать проблему, которую вы описывали, но не удалось. Не могли бы вы представить минимальный рабочий пример, где проблема всплывает?
Это был и мой подход, но я чувствую, что это опасно именно потому, что словарь может принять что-нибудь за ключ. Не будет ошибки, если я установлю myStruct ["ffield"], когда я собираюсь установить myStruct ["field"]. Проблема может (или не может) стать очевидной, когда я использую или повторно использую myStruct ["field"] позже. Мне нравится подход PabloG.
mobabo
Та же проблема существует с PabloG. Попробуйте добавить к нему следующий код: pt3.w = 1 print pt3.w на языке с dicts лучше использовать их, особенно для сериализуемых объектов, поскольку вы можете автоматически использовать импорт json для их сохранения и других библиотек сериализации, если у вас нет странных вещи внутри вашего диктата. Dicts - это решение, позволяющее хранить данные и логику отдельно, и они лучше, чем структуры для людей, которые не хотят писать собственные функции сериализации и десериализации и не хотят использовать непортативные сериализаторы, такие как pickle.
Пойкилос
27
dF: это круто ... я не знал, что могу получить доступ к полям в классе с помощью dict.
Марк: ситуации, в которых я хотел бы, чтобы это было именно тогда, когда я хочу кортеж, но ничего более «тяжелого», чем словарь.
Вы можете получить доступ к полям класса, используя словарь, потому что поля класса, его методы и все его свойства хранятся внутри с помощью dicts (по крайней мере, в CPython).
... Что приводит нас к вашему второму комментарию. Вера в то, что Python dicts «тяжелые», является крайне непитонистской концепцией. И чтение таких комментариев убивает мой Python Zen. Это не хорошо.
Видите ли, когда вы объявляете класс, вы на самом деле создаете довольно сложную оболочку вокруг словаря - так что, если что-нибудь, вы добавляете больше накладных расходов, чем при использовании простого словаря. Накладные расходы, которые, кстати, бессмысленны в любом случае. Если вы работаете с приложениями, критичными к производительности, используйте C или что-то в этом роде.
# 1, Cython! = CPython. Я думаю, что вы говорили о CPython, реализации Python, написанной на C, а не Cython, проекте по кросс-компиляции кода Python в C-код. Я отредактировал ваш ответ, чтобы исправить это. # 2, я думаю, когда он сказал, что диктат тяжелый, он имел в виду синтаксис. self['member']на 3 символа длиннее self.member, и все эти символы относительно дружелюбны.
ArtOfWarfare
19
Вы можете создать подкласс структуры 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
1020>>> point = POINT(y=5)>>>print point.x, point.y
05>>> 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
05>>>print rc.lowerright.x, rc.lowerright.y
00>>>
Я также хотел бы добавить решение, которое использует слоты :
classPoint:
__slots__ =["x","y"]def __init__(self, x, y):
self.x = x
self.y = y
Обязательно проверьте документацию на наличие слотов, но быстрое объяснение слотов заключается в том, что это способ Python сказать: «Если вы можете заблокировать эти атрибуты и только эти атрибуты в классе так, что вы фиксируете, что вы не добавите никаких новых атрибутов после того, как класс создается экземпляр (да, вы можете добавить новые атрибуты к экземпляру класса, см. пример ниже), тогда я покончу с большим выделением памяти, которое позволяет добавлять новые атрибуты к экземпляру класса, и использую только то, что мне нужно для этих выделенных атрибутов ".
Пример добавления атрибутов к экземпляру класса (таким образом, не используя слоты):
classPoint:def __init__(self, x, y):
self.x = x
self.y = y
p1 =Point(3,5)
p1.z =8print(p1.z)
Выход: 8
Пример попытки добавить атрибуты в экземпляр класса, где использовались слоты:
classPoint:
__slots__ =["x","y"]def __init__(self, x, y):
self.x = x
self.y = y
p1 =Point(3,5)
p1.z =8
Вывод: AttributeError: у объекта 'Point' нет атрибута 'z'
Это может эффективно работать как структура и использовать меньше памяти, чем класс (как это сделала бы структура, хотя я не исследовал, сколько именно). Рекомендуется использовать слоты, если вы будете создавать большое количество экземпляров объекта и вам не нужно добавлять атрибуты. Точечный объект является хорошим примером этого, поскольку вполне вероятно, что можно описать множество точек для описания набора данных.
Обновление по позиции игнорирует порядок объявления атрибутов и использует вместо них их алфавитную сортировку. Так что если вы измените порядок строк в Point3dStructобъявлении, Point3dStruct(5, 6)не будет работать, как ожидалось. Странно, что никто не написал это за все 6 лет.
ляпис
Не могли бы вы добавить версию Python 3 в ваш удивительный код? Отличная работа! Мне нравится, что вы берете что-то абстрактное и делаете это явным со вторым конкретным классом. Это должно быть хорошо для обработки ошибок / отлова. Для Python 3 просто измените print> print()и attrs[n]> next(attrs)(фильтр теперь является собственным итерируемым объектом и требует next).
Джонатан Комар
10
Всякий раз, когда мне нужен «мгновенный объект данных, который также ведет себя как словарь» (я не думаю о структурах C!), Я вспоминаю этот милый хак:
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 valuefor 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)
Примечание: вместо имени 'cstruct', пожалуйста, используйте ваше имя структуры вместо var_i, var_f, var_str, пожалуйста, определите переменную-член вашей структуры.
Это может быть немного поздно, но я принял решение, используя метаклассы Python (версия для декоратора также ниже).
когда __init__ вызывается во время выполнения, он захватывает каждый из аргументов и их значение и назначает их в качестве переменных экземпляра для вашего класса. Таким образом, вы можете создать структурный класс без необходимости присваивать каждое значение вручную.
В моем примере нет проверки ошибок, поэтому легче следовать.
classMyStruct(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
Я разместил его на 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
>>>classTest(object):@init_all_argsdef __init__(self, a, b):pass>>> a =Test(1,2)>>> a.a
1>>>
Черт возьми - сегодня я потратил два часа на написание своего собственного декоратора, а потом нашел это. В любом случае, опубликовать мой, потому что он обрабатывает значения по умолчанию, а ваш нет. stackoverflow.com/a/32448434/901641
ArtOfWarfare
+1 за упоминание func_code. Начал копать в этом направлении и нашел там много интересного.
wombatonfire
5
Я написал декоратор, который вы можете использовать в любом методе, чтобы сделать так, чтобы все передаваемые аргументы или любые значения по умолчанию присваивались экземпляру.
def argumentsToAttributes(method):
argumentNames = method.func_code.co_varnames[1:]# Generate a dictionary of default values:
defaultsDict ={}
defaults = method.func_defaults if method.func_defaults else()for i, default in enumerate(defaults, start = len(argumentNames)- len(defaults)):
defaultsDict[argumentNames[i]]= default
def newMethod(self,*args,**kwargs):# Use the positional arguments.for name, value in zip(argumentNames, args):
setattr(self, name, value)# Add the key word arguments. If anything is missing, use the default.for name in argumentNames[len(args):]:
setattr(self, name, kwargs.get(name, defaultsDict[name]))# Run whatever else the method needs to do.
method(self,*args,**kwargs)return newMethod
Быстрая демонстрация. Обратите внимание, что я использую позиционный аргумент a, значение по умолчанию для bи именованный аргумент c. Затем я печатаю все 3 ссылки self, чтобы показать, что они были правильно назначены до ввода метода.
class A(object):@argumentsToAttributesdef __init__(self, a, b ='Invisible', c ='Hello'):print(self.a)print(self.b)print(self.c)
A('Why', c ='Nothing')
Обратите внимание, что мой декоратор должен работать с любым методом, а не только __init__.
Я не вижу здесь этого ответа, поэтому я полагаю, что добавлю его, так как сейчас я использую Python и только что обнаружил его. В руководстве по Python (в данном случае Python 2) приведен следующий простой и эффективный пример:
classEmployee:pass
john =Employee()# Create an empty employee record# Fill the fields of the record
john.name ='John Doe'
john.dept ='computer lab'
john.salary =1000
То есть создается пустой объект класса, затем создается его экземпляр, и поля добавляются динамически.
Преимущество в том, что это действительно просто. Недостатком является то, что он не особенно самодокументирован (предполагаемые члены нигде не перечислены в классе «определение»), а неустановленные поля могут вызвать проблемы при доступе. Эти две проблемы могут быть решены с помощью:
Вот решение, которое использует класс (никогда не создаваемый) для хранения данных. Мне нравится, что этот способ включает в себя очень мало печатать и не требует каких-либо дополнительных пакетов и т. Д.
class myStruct:
field1 ="one"
field2 ="2"
Вы можете добавить больше полей позже, по мере необходимости:
myStruct.field3 =3
Чтобы получить значения, поля доступны как обычно:
Лично мне этот вариант тоже нравится. Это расширяет ответ @ 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)
Следующее решение для структуры вдохновлено реализацией namedtuple и некоторыми из предыдущих ответов. Однако, в отличие от namedtuple, он является изменяемым по своим значениям, но, как и структура c-style, неизменным в именах / атрибутах, чего нет у обычного класса или dict.
_class_template ="""\
class {typename}:
def __init__(self, *args, **kwargs):
fields = {field_names!r}
for x in fields:
setattr(self, x, None)
for name, value in zip(fields, args):
setattr(self, name, value)
for name, value in kwargs.items():
setattr(self, name, value)
def __repr__(self):
return str(vars(self))
def __setattr__(self, name, value):
if name not in {field_names!r}:
raise KeyError("invalid name: %s" % name)
object.__setattr__(self, name, value)
"""def struct(typename, field_names):
class_definition = _class_template.format(
typename = typename,
field_names = field_names)
namespace = dict(__name__='struct_%s'% typename)exec(class_definition, namespace)
result = namespace[typename]
result._source = class_definition
return result
Применение:
Person= struct('Person',['firstname','lastname'])
generic =Person()
michael =Person('Michael')
jones =Person(lastname ='Jones')In[168]: michael.middlename ='ben'Traceback(most recent call last):File"<ipython-input-168-b31c393c0d67>", line 1,in<module>
michael.middlename ='ben'File"<string>", line 19,in __setattr__
KeyError:'invalid name: middlename'
cstruct2pyявляется чистой библиотекой Python для генерации классов Python из кода C и использования их для упаковки и распаковки данных. Библиотека может анализировать заголовки C (объявления структур, объединений, перечислений и массивов) и эмулировать их в python. Сгенерированные питонные классы могут анализировать и упаковывать данные.
Например:
typedef struct {
int x;
int y;}Point;
after generating pythonic class...
p =Point(x=0x1234, y=0x5678)
p.packed =="\x34\x12\x00\x00\x78\x56\x00\x00"
И я расширяю его, чтобы добавить значения по умолчанию.
class myStruct:def __init__(self,**kwds):
self.x=0
self.__dict__.update(kwds)# Must be last to accept assigned member variable.def __repr__(self):
args =['%s=%s'%(k, repr(v))for(k,v)in vars(self).items()]return'%s(%s)'%( self.__class__.__qualname__,', '.join(args))
a=myStruct()
b=myStruct(x=3,y='test')
c=myStruct(x='str')>>> a
myStruct(x=0)>>> b
myStruct(x=3, y='test')>>> c
myStruct(x='str')
Если у вас нет 3.7 для @dataclass и вам нужна изменчивость, следующий код может работать для вас. Он достаточно самодокументируемый и дружественный к IDE (автозаполнение), предотвращает двойную запись, легко расширяется и очень просто проверить, что все переменные экземпляра полностью инициализированы:
classParams():def __init__(self):
self.var1 : int =None
self.var2 : str =Nonedef are_all_defined(self):for key, value in self.__dict__.items():assert(value isnotNone),"instance variable {} is still None".format(key)returnTrue
params =Params()
params.var1 =2
params.var2 ='hello'assert(params.are_all_defined)
>>> ms =Warning()>>> ms.foo =123>>> ms.bar ='akafrit'
Как это работает? Он просто повторно использует встроенный класс Warning(производный от Exception) и использует его так, как он был определен вами.
Положительным моментом является то, что вам не нужно сначала что-либо импортировать или определять, что «Предупреждение» - это короткое имя, и оно также дает понять, что вы делаете что-то грязное, что не должно использоваться где-либо еще, кроме небольшого сценария.
Кстати, я пытался найти что-то еще проще, ms = object()но не смог (последний пример не работает). Если у вас есть, мне интересно.
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)]# 85718297print(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.16006120000000124print(time_tuple/time_slot)# 1.1694481584580898 # The slot is almost 17% faster than NamedTuple on Windows. (Python 3.7.7)
Если вы __dict__не используете, пожалуйста, выберите между __slots__(более высокая производительность и хранение) и NamedTuple(ясно для чтения и использования)
Вы можете просмотреть эту ссылку ( Использование слотов ), чтобы получить больше __slots__информации.
MyStruct = namedtuple("MyStruct", "field1 field2 field3")
pandas.Series(a=42).a
должен сделать это, если вы специалист по данным ...Ответы:
Используйте именованный кортеж , который был добавлен в модуль коллекций в стандартной библиотеке Python 2.6. Также возможно использовать именованный кортеж Раймонда Хеттингера рецепт если вам нужна поддержка Python 2.4.
Это хорошо для вашего базового примера, но также охватывает множество крайних случаев, с которыми вы можете столкнуться позже. Ваш фрагмент выше будет записан как:
Вновь созданный тип может использоваться следующим образом:
Вы также можете использовать именованные аргументы:
источник
Обновить : классы данных
С введением классов данных в Python 3.7 мы стали очень близки.
Следующий пример похож на пример NamedTuple ниже, но результирующий объект является изменяемым и допускает значения по умолчанию.
Это прекрасно работает с новым модулем набора текста, если вы хотите использовать более конкретные аннотации типов.
Я отчаянно ждал этого! Если вы спросите меня, классы данных и новое объявление NamedTuple в сочетании с модулем набора текста - это находка!
Улучшено объявление NamedTuple
Начиная с Python 3.6 он стал довольно простым и красивым (ИМХО), пока можно жить с неизменностью .
Был представлен новый способ объявления NamedTuples , который также допускает аннотации типов :
источник
dataclass
Модуль нового в Python 3.7 , но вы можетеpip install dataclasses
. Это бэкпорт на Python 3.6. pypi.org/project/dataclasses/#description@dataclass
. Подробности здесь: pypi.org/project/dataclasses/#descriptionВы можете использовать кортеж для многих вещей, где вы будете использовать структуру в C (например, координаты x, y или цвета RGB).
Для всего остального вы можете использовать словарь или вспомогательный класс, подобный этому :
Я думаю, что «окончательное» обсуждение здесь , в опубликованной версии Python Cookbook.
источник
TypeError: this constructor takes no arguments
Возможно, вы ищете структуры без конструкторов:
источник
class Sample:
не сразу делают что-либо; они устанавливают атрибуты класса. К ним всегда можно получить доступ, напримерSample.name
.s1
иs2
во время выполнения. Если не запрещено иное, вы можете добавлять или изменятьname
атрибут в любом экземпляре любого класса в любое время, независимо от того, имеет ли классname
атрибут. Вероятно, самая большая функциональная проблема заключается в том, что разные экземпляры одного и того же класса будут вести себя по-разному в зависимости от того, установлен ли выname
. Если вы обновитеSample.name
, любые объекты без явно установленногоname
свойства вернут новоеname
.self
ключевых слов и строки конструктора, если вы спросите меня. Я был бы признателен, если бы Хосе мог отредактировать свой ответ, добавив предупреждающее сообщение о риске случайного обмена значениями между экземплярами.Как насчет словаря?
Что-то вроде этого:
Затем вы можете использовать это для управления значениями:
И значения не должны быть строками. Они могут быть практически любым другим объектом.
источник
pt3.w = 1 print pt3.w
на языке с dicts лучше использовать их, особенно для сериализуемых объектов, поскольку вы можете автоматически использовать импорт json для их сохранения и других библиотек сериализации, если у вас нет странных вещи внутри вашего диктата. Dicts - это решение, позволяющее хранить данные и логику отдельно, и они лучше, чем структуры для людей, которые не хотят писать собственные функции сериализации и десериализации и не хотят использовать непортативные сериализаторы, такие как pickle.Вы можете получить доступ к полям класса, используя словарь, потому что поля класса, его методы и все его свойства хранятся внутри с помощью dicts (по крайней мере, в CPython).
... Что приводит нас к вашему второму комментарию. Вера в то, что Python dicts «тяжелые», является крайне непитонистской концепцией. И чтение таких комментариев убивает мой Python Zen. Это не хорошо.
Видите ли, когда вы объявляете класс, вы на самом деле создаете довольно сложную оболочку вокруг словаря - так что, если что-нибудь, вы добавляете больше накладных расходов, чем при использовании простого словаря. Накладные расходы, которые, кстати, бессмысленны в любом случае. Если вы работаете с приложениями, критичными к производительности, используйте C или что-то в этом роде.
источник
self['member']
на 3 символа длиннееself.member
, и все эти символы относительно дружелюбны.Вы можете создать подкласс структуры C, которая доступна в стандартной библиотеке. Модуль ctypes предоставляет класс Structure . Пример из документов:
источник
Я также хотел бы добавить решение, которое использует слоты :
Обязательно проверьте документацию на наличие слотов, но быстрое объяснение слотов заключается в том, что это способ Python сказать: «Если вы можете заблокировать эти атрибуты и только эти атрибуты в классе так, что вы фиксируете, что вы не добавите никаких новых атрибутов после того, как класс создается экземпляр (да, вы можете добавить новые атрибуты к экземпляру класса, см. пример ниже), тогда я покончу с большим выделением памяти, которое позволяет добавлять новые атрибуты к экземпляру класса, и использую только то, что мне нужно для этих выделенных атрибутов ".
Пример добавления атрибутов к экземпляру класса (таким образом, не используя слоты):
Выход: 8
Пример попытки добавить атрибуты в экземпляр класса, где использовались слоты:
Вывод: AttributeError: у объекта 'Point' нет атрибута 'z'
Это может эффективно работать как структура и использовать меньше памяти, чем класс (как это сделала бы структура, хотя я не исследовал, сколько именно). Рекомендуется использовать слоты, если вы будете создавать большое количество экземпляров объекта и вам не нужно добавлять атрибуты. Точечный объект является хорошим примером этого, поскольку вполне вероятно, что можно описать множество точек для описания набора данных.
источник
Вы также можете передать параметры init переменным экземпляра по позиции
источник
Point3dStruct
объявлении,Point3dStruct(5, 6)
не будет работать, как ожидалось. Странно, что никто не написал это за все 6 лет.print
>print()
иattrs[n]
>next(attrs)
(фильтр теперь является собственным итерируемым объектом и требуетnext
).Всякий раз, когда мне нужен «мгновенный объект данных, который также ведет себя как словарь» (я не думаю о структурах C!), Я вспоминаю этот милый хак:
Теперь вы можете просто сказать:
Идеально подходит для тех случаев, когда вам нужна «сумка данных, которая НЕ является классом», и когда именованные кортежи непостижимы ...
источник
Вы получаете доступ к структуре C-Style в Python следующим образом.
если вы просто хотите использовать объект cstruct
если вы хотите создать массив объектов cstruct
Примечание: вместо имени 'cstruct', пожалуйста, используйте ваше имя структуры вместо var_i, var_f, var_str, пожалуйста, определите переменную-член вашей структуры.
источник
Некоторые ответы здесь очень тщательно продуманы. Простейший вариант, который я нашел (от: http://norvig.com/python-iaq.html ):
Инициирование:
добавив больше:
редактировать: извините, не видел этот пример уже внизу.
источник
Это может быть немного поздно, но я принял решение, используя метаклассы Python (версия для декоратора также ниже).
когда
__init__
вызывается во время выполнения, он захватывает каждый из аргументов и их значение и назначает их в качестве переменных экземпляра для вашего класса. Таким образом, вы можете создать структурный класс без необходимости присваивать каждое значение вручную.В моем примере нет проверки ошибок, поэтому легче следовать.
Вот оно в действии.
Я разместил его на Reddit и / u / matchu опубликовал версию для декоратора, которая чище. Я рекомендую вам использовать его, если вы не хотите расширять версию метакласса.
источник
Я написал декоратор, который вы можете использовать в любом методе, чтобы сделать так, чтобы все передаваемые аргументы или любые значения по умолчанию присваивались экземпляру.
Быстрая демонстрация. Обратите внимание, что я использую позиционный аргумент
a
, значение по умолчанию дляb
и именованный аргументc
. Затем я печатаю все 3 ссылкиself
, чтобы показать, что они были правильно назначены до ввода метода.Обратите внимание, что мой декоратор должен работать с любым методом, а не только
__init__
.источник
Я не вижу здесь этого ответа, поэтому я полагаю, что добавлю его, так как сейчас я использую Python и только что обнаружил его. В руководстве по Python (в данном случае Python 2) приведен следующий простой и эффективный пример:
То есть создается пустой объект класса, затем создается его экземпляр, и поля добавляются динамически.
Преимущество в том, что это действительно просто. Недостатком является то, что он не особенно самодокументирован (предполагаемые члены нигде не перечислены в классе «определение»), а неустановленные поля могут вызвать проблемы при доступе. Эти две проблемы могут быть решены с помощью:
Теперь вы можете сразу увидеть, какие поля ожидает программа.
Оба склонны к опечаткам,
john.slarly = 1000
все получится. Тем не менее, это работает.источник
Вот решение, которое использует класс (никогда не создаваемый) для хранения данных. Мне нравится, что этот способ включает в себя очень мало печатать и не требует каких-либо дополнительных пакетов и т. Д.
Вы можете добавить больше полей позже, по мере необходимости:
Чтобы получить значения, поля доступны как обычно:
источник
Лично мне этот вариант тоже нравится. Это расширяет ответ @ dF .
Он поддерживает два режима инициализации (которые можно смешивать):
Кроме того, он печатает лучше:
источник
Следующее решение для структуры вдохновлено реализацией namedtuple и некоторыми из предыдущих ответов. Однако, в отличие от namedtuple, он является изменяемым по своим значениям, но, как и структура c-style, неизменным в именах / атрибутах, чего нет у обычного класса или dict.
Применение:
источник
Для этого есть пакет python. смотри cstruct2py
cstruct2py
является чистой библиотекой Python для генерации классов Python из кода C и использования их для упаковки и распаковки данных. Библиотека может анализировать заголовки C (объявления структур, объединений, перечислений и массивов) и эмулировать их в python. Сгенерированные питонные классы могут анализировать и упаковывать данные.Например:
Сначала нам нужно создать питонические структуры:
Теперь мы можем импортировать все имена из кода C:
Мы также можем сделать это напрямую:
Использование типов и определений из кода C
Выход будет:
Для
cstruct2py
запуска клона :источник
Я думаю, что словарь структуры Python подходит для этого требования.
источник
https://stackoverflow.com/a/32448434/159695 не работает в Python3.
https://stackoverflow.com/a/35993/159695 работает в Python3.
И я расширяю его, чтобы добавить значения по умолчанию.
источник
Если у вас нет 3.7 для @dataclass и вам нужна изменчивость, следующий код может работать для вас. Он достаточно самодокументируемый и дружественный к IDE (автозаполнение), предотвращает двойную запись, легко расширяется и очень просто проверить, что все переменные экземпляра полностью инициализированы:
источник
Вот быстрый и подвох:
Как это работает? Он просто повторно использует встроенный класс
Warning
(производный отException
) и использует его так, как он был определен вами.Положительным моментом является то, что вам не нужно сначала что-либо импортировать или определять, что «Предупреждение» - это короткое имя, и оно также дает понять, что вы делаете что-то грязное, что не должно использоваться где-либо еще, кроме небольшого сценария.
Кстати, я пытался найти что-то еще проще,
ms = object()
но не смог (последний пример не работает). Если у вас есть, мне интересно.источник
Лучший способ, который я нашел, - это использовать пользовательский класс словаря, как описано в этом посте: https://stackoverflow.com/a/14620633/8484485
Если требуется поддержка автозаполнения iPython, просто определите функцию dir () следующим образом:
Затем вы определяете свою псевдоструктуру следующим образом: (этот вложенный)
Затем вы можете получить доступ к значениям внутри my_struct следующим образом:
print(my_struct.com1.inst)
=>
[5]
источник
NamedTuple - это удобно. но там никто не разделяет производительность и память.
Если вы
__dict__
не используете, пожалуйста, выберите между__slots__
(более высокая производительность и хранение) иNamedTuple
(ясно для чтения и использования)Вы можете просмотреть эту ссылку ( Использование слотов ), чтобы получить больше
__slots__
информации.источник