Чому в Python 3.4+, чому я повинен використовувати nametuple над SimpleNamespace, коли не використовую dict, вони здаються дуже схожими


11

У той чи інший момент ви можете натрапити на функції з великою кількістю аргументів. Іноді є сенс поєднувати деякі аргументи в супер-аргументи. Я часто робив це за допомогою диктів, але зараз я розглядаю кращі способи зробити це.

Я хотів би звернутися ...

def do_something(ax, ay, az, bu, bv, c):
    # Do something

... у ...

def do_something(a, b, c):
    # Do something

... де aі bмістять їх субваріації.

Один із способів зробити це:

A = namedtuple('A', 'x, y, z')
a = A(ax, ay, az)
B = namedtuple('B', 'u, v')
b = B(bu, bv)

Однак це здається більш простим:

a = SimpleNamespace(x=ax, y=ay, z=az)
b = SimpleNamespace(u=bu, v=bv)

У чому недолік? Те, що так aі bне набрано? Вони не A і B об’єкти?

(Btw, не хвилюйтеся про імена змінних. Я зазвичай не використовую як короткі імена змінних.)


1
Немає ніяких недоліків, вони просто різні речі. Для початківців найменування з імпульсами є незмінними, а простори імен - змінні. Є мутантний кращий чи гірший за незмінний? Це залежить від того, що вам потрібно чи хочете, у багатьох випадках це просто не має значення. Ваша функція, ймовірно, буде працювати з будь-яким об'єктом з необхідними атрибутами, як побудувати його, залежить від абонента.
Перестаньте шкодити Моніці

@Goyo Дякую Річ "недолік" була незграбним способом її сказати. Я не мав на увазі, що одне по суті краще, ніж інше. Просто хотіли плюси і мінуси. Знову дякую.
Андре Крістофер Андерсен

1
чи не повинен 4-й рядок виглядати як "b = B (bu, bv)"?
Ален Сіляк

@AlenSiljak Так. Я зараз це виправлю.
Андре Крістофер Андерсен

Відповіді:


21

SimpleNamespaceв основному просто приємний фасад зверху словника. Це дозволяє використовувати властивості замість індексних ключів. Це приємно, оскільки це супер гнучко і легко маніпулювати.

Мінусом цієї гнучкості є те, що вона не забезпечує жодної структури. Ніщо не може завадити комусь телефонувати SimpleNamespace(x=ax, y=ay)del a.zв якийсь момент пізніше). Якщо цей екземпляр передається вашій функції, виняток виникає при спробі доступу до поля.

Навпаки, namedtupleдозволяє створити структурований тип. Тип матиме ім’я, і він буде знати, якими полями він повинен бути. Ви не зможете зробити екземпляр без кожного з цих полів, і їх не можна буде видалити пізніше. Крім того, екземпляр є незмінним, тому ви будете знати, що значення в a.xзавжди буде однаковим.

Ви вирішуєте, чи потрібна вам гнучкість SimpleNamespace, чи надаєте ви структуру та гарантії, які надає компанія namedtuple.


2

Мені дуже подобається відповідь про структуровану порівняно ні, тому я лише надаю конкретний приклад нижче.

SimpleNamespaceприйме ключі, які починаються з _. Якщо ви шукаєте швидкий і простий спосіб перетворити, скажімо, JSON, ви не керуєте об'єктами з іменами полів, це дуже зручно:

d = {"_id": 2342122, "text": "hi there!"} # Elasticsearch gives this id!
e = SimpleNamespace(**d) # works
Name = namedtuple("Name", sorted(d)) # ValueError so we can't do Name(**d)

Зауважте вище, що ви бачите, що це namedtupleдає нам цілий додатковий об'єкт, який SimpleNamespaceніколи не буде. Кожна SimpleNamespaceсправді є "унікальною сніжинкою", тоді як namedtupleіснує без жодного конкретного значення. Де б ви не потребували абстракцій, які узагальнюють конкретні значення, вам, мабуть, слід віддати перевагу.


1

Підсумок SimpleNamespace

Це дозволяє ініціалізувати атрибути під час побудови об'єкта:

sn = SimpleNamespace(a=1, b=2)

Він забезпечує читабельність

repr(): eval(repr(sn)) == sn

Він переосмислює порівняння за замовчуванням. Замість того, щоб порівнювати за id(), він порівнює значення атрибутів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.