У меня есть класс, содержащий только поля и никаких методов, например:
class Request(object):
def __init__(self, environ):
self.environ = environ
self.request_method = environ.get('REQUEST_METHOD', None)
self.url_scheme = environ.get('wsgi.url_scheme', None)
self.request_uri = wsgiref.util.request_uri(environ)
self.path = environ.get('PATH_INFO', None)
# ...
Это можно легко перевести на диктант. Класс более гибкий для будущих дополнений и может работать быстрее __slots__
. Так будет ли вместо этого использование dict? Будет ли диктатор быстрее класса? И быстрее класса со слотами?
python
oop
class
dictionary
Deamon
источник
источник
dict
может иметь смысл наследование класса от до. Отличное преимущество: при отладке просто скажите,print(request)
и вы сразу увидите всю информацию о состоянии. при более классическом подходе вам придется писать свои собственные__str__
методы, что отстой, если вам приходится делать это все время.Ответы:
Зачем вам делать из этого словарь? В чем преимущество? Что произойдет, если позже вы захотите добавить код? Куда пойдет ваш
__init__
код?Классы предназначены для объединения связанных данных (и обычно кода).
Словари предназначены для хранения отношений «ключ-значение», где обычно все ключи одного типа, и все значения также одного типа. Иногда они могут быть полезны для объединения данных, когда не все имена ключей / атрибутов известны заранее, но часто это признак того, что с вашим дизайном что-то не так.
Держите это в классе.
источник
__init__
. Но ты прав: я бы разделил вещи, которые принадлежат друг другу.where would your __init__ code go?
по поводу. Это могло бы убедить менее опытного разработчика в том, что следует использовать только классы, поскольку метод инициализации не используется в словаре. Абсурд.Используйте словарь, если вам не нужен дополнительный механизм класса. Вы также можете использовать
namedtuple
гибридный подход:>>> from collections import namedtuple >>> request = namedtuple("Request", "environ request_method url_scheme") >>> request <class '__main__.Request'> >>> request.environ = "foo" >>> request.environ 'foo'
Различия в производительности здесь будут минимальными, хотя я был бы удивлен, если бы словарь не был быстрее.
источник
Класс в Python - это слово внизу. Вы действительно получаете некоторые накладные расходы на поведение класса, но вы не сможете это заметить без профилировщика. В этом случае, я считаю, что занятия вам принесут пользу, потому что:
источник
Я думаю, что использование каждого из них слишком субъективно для меня, чтобы заниматься этим, поэтому я просто буду придерживаться цифр.
Я сравнил время, необходимое для создания и изменения переменной в dict, классе new_style и классе new_style со слотами.
Вот код, который я использовал для его тестирования (он немного беспорядочный, но выполняет свою работу).
import timeit class Foo(object): def __init__(self): self.foo1 = 'test' self.foo2 = 'test' self.foo3 = 'test' def create_dict(): foo_dict = {} foo_dict['foo1'] = 'test' foo_dict['foo2'] = 'test' foo_dict['foo3'] = 'test' return foo_dict class Bar(object): __slots__ = ['foo1', 'foo2', 'foo3'] def __init__(self): self.foo1 = 'test' self.foo2 = 'test' self.foo3 = 'test' tmit = timeit.timeit print 'Creating...\n' print 'Dict: ' + str(tmit('create_dict()', 'from __main__ import create_dict')) print 'Class: ' + str(tmit('Foo()', 'from __main__ import Foo')) print 'Class with slots: ' + str(tmit('Bar()', 'from __main__ import Bar')) print '\nChanging a variable...\n' print 'Dict: ' + str((tmit('create_dict()[\'foo3\'] = "Changed"', 'from __main__ import create_dict') - tmit('create_dict()', 'from __main__ import create_dict'))) print 'Class: ' + str((tmit('Foo().foo3 = "Changed"', 'from __main__ import Foo') - tmit('Foo()', 'from __main__ import Foo'))) print 'Class with slots: ' + str((tmit('Bar().foo3 = "Changed"', 'from __main__ import Bar') - tmit('Bar()', 'from __main__ import Bar')))
И вот результат ...
Создание ...
Dict: 0.817466186345 Class: 1.60829183597 Class_with_slots: 1.28776730003
Изменение переменной ...
Dict: 0.0735140918748 Class: 0.111714198313 Class_with_slots: 0.10618612142
Итак, если вы просто храните переменные, вам нужна скорость, и вам не потребуется выполнять много вычислений, я рекомендую использовать dict (вы всегда можете просто создать функцию, которая выглядит как метод). Но, если вам действительно нужны классы, помните - всегда используйте __ slots __ .
Заметка:
Я тестировал «класс» с обеими new_style и old_style классов. Оказывается, классы old_style быстрее создавать, но медленнее изменять (не сильно, но существенно, если вы создаете много классов в тесном цикле (совет: вы делаете это неправильно)).
Также время для создания и изменения переменных на вашем компьютере может отличаться, так как мой старый и медленный. Убедитесь, что вы проверили его сами, чтобы увидеть «реальные» результаты.
Редактировать:
Позже я протестировал namedtuple: я не могу его изменить, но для создания 10000 образцов (или чего-то подобного) потребовалось 1,4 секунды, поэтому словарь действительно самый быстрый.
Если я изменю функцию dict, чтобы включить ключи и значения и вернуть dict вместо переменной, содержащей dict, когда я ее создаю, это даст мне 0,65 вместо 0,8 секунды.
class Foo(dict): pass
Создание похоже на класс со слотами, а изменение переменной - самое медленное (0,17 секунды), поэтому не используйте эти классы . перейти к dict (скорость) или к классу, производному от объекта ('синтаксическая конфета')
источник
dict
(я полагаю, без переопределенных методов?). Работает ли он так же, как класс нового стиля, написанный с нуля?Я согласен с @adw. Я бы никогда не изобразил «объект» (в объектно-ориентированном смысле) со словарем. Словари объединяют пары имя / значение. Классы представляют объекты. Я видел код, в котором объекты представлены словарями, и неясно, какова фактическая форма этого объекта. Что происходит, когда определенных имен / ценностей нет? Что мешает клиенту вообще что-либо вставлять. Или пытаться вообще что-нибудь вытащить. Форма вещи всегда должна быть четко обозначена.
При использовании Python важно строить дисциплинированно, поскольку язык дает автору множество способов выстрелить себе в ногу.
источник
Я бы порекомендовал класс, так как это всевозможная информация, связанная с запросом. Если бы кто-то использовал словарь, я бы ожидал, что хранимые данные будут гораздо более похожими по своей природе. Рекомендация, которой я стараюсь следовать, заключается в том, что если я хочу перебрать весь набор пар ключ-> значение и что-то сделать, я использую словарь. В противном случае данные, по-видимому, имеют гораздо больше структуры, чем базовое сопоставление ключ-> значение, а это означает, что класс, вероятно, будет лучшей альтернативой.
Следовательно, придерживайтесь класса.
источник
Если все, что вы хотите достичь, - это синтаксическая конфетка, например,
obj.bla = 5
вместоobj['bla'] = 5
, особенно если вам нужно много повторять это, возможно, вы захотите использовать какой-то простой класс контейнера, как в предложении martineaus. Тем не менее, код там довольно раздутый и излишне медленный. Вы можете сделать это просто так:class AttrDict(dict): """ Syntax candy """ __getattr__ = dict.__getitem__ __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__
Другой причиной для перехода на
namedtuple
s или класс__slots__
может быть использование памяти. Dicts требуют значительно больше памяти, чем типы списков, так что об этом стоит подумать.В любом случае, в вашем конкретном случае, похоже, нет никакой мотивации отказаться от вашей текущей реализации. Кажется, что вы не поддерживаете миллионы этих объектов, поэтому типы, производные от списков, не требуются. И он на самом деле содержит некоторую функциональную логику внутри
__init__
, так что вам также не стоит связываться сAttrDict
.источник
types.SimpleNamespace
(доступно с Python 3.3) является альтернативой пользовательскому AttrDict.Возможно, получится съесть свой торт и съесть его. Другими словами, вы можете создать что-то, что обеспечивает функциональность как класса, так и экземпляра словаря. См. Рецепт Dɪᴄᴛɪᴏɴᴀʀʏ ᴡɪᴛʜ ᴀᴛᴛʀɪʙᴜᴛᴇ-sᴛʏʟᴇ ss от ActiveState и комментарии о том, как это сделать.
Если вы решите использовать обычный класс, а не подкласс, я обнаружил, что рецепт Tʜᴇ sɪᴍᴘʟᴇ ʙᴜᴛ ʜᴀɴᴅʏ "ᴄᴏʟʟᴇᴄᴛᴏʀ ᴏғ ᴀ ʙᴜɴᴄʜ ᴏғ ɴᴀᴍᴇᴅ sᴛᴜғғ" ᴄʟᴀss (от Алекса Мартелли) очень гибкий и полезный для такого рода вещей. похоже, что вы делаете (т.е. создаете относительно простой агрегатор информации). Поскольку это класс, вы можете легко расширить его функциональность, добавив методы.
Наконец, следует отметить, что имена членов класса должны быть допустимыми идентификаторами Python, а ключи словаря - нет, поэтому словарь предоставит большую свободу в этом отношении, потому что ключи могут быть чем угодно хэшируемыми (даже тем, что не является строкой).
Обновить
Класс
object
(у которого нет__dict__
) названный подклассSimpleNamespace
(у которого он есть) был добавлен вtypes
модуль Python 3.3 и является еще одной альтернативой.источник
class ClassWithSlotBase: __slots__ = ('a', 'b',) def __init__(self): self.a: str = "test" self.b: float = 0.0 def test_type_hint(_b: float) -> None: print(_b) class_tmp = ClassWithSlotBase() test_type_hint(class_tmp.a)
Я рекомендую класс. Если вы используете класс, вы можете получить подсказку типа, как показано. И класс поддерживает автоматическое завершение, когда класс является аргументом функции.
источник