Как реализовать "разные" аргументы по умолчанию для Python NamedTuple - PullRequest
1 голос
/ 29 октября 2019

У меня есть NamedTuple, один из атрибутов которого является изменяющейся переменной, которая зависит от контекста, в котором запускается экземпляр. Для минимального примера это должно быть что-то вроде

import pandas as pd
import datetime

class Record(NamedTuple):
    """
    Immutable record objects
    """
    data: dict
    timestamp: pd.Timestamp


# initiation
# I want the timestamp to be the current time
record = Record(data={'x': 1}, timestamp=datetime.datetime.now())

. Приведенный выше код будет работать нормально, но я не хочу показывать атрибут timestamp пользователю. Вместо этого я хочу что-то вроде этого, установив timestamp как значение по умолчанию arg, которое, однако, не теряет своей независимости в контексте инициации:

import pandas as pd
import datetime
import time

class Record(NamedTuple):
    """
    Immutable record objects
    """
    data: dict
    timestamp: pd.Timestamp = datetime.datetime.now()


# initiation, not producing desired output though
record1 = Record(data={'x': 1})
time.sleep(1)
record2 = Record(data={'x': 1})

# expected 1s apart, but actually are the same
print(record1.timestamp, record2.timestamp)

Я ожидаю record.timestamp быть временем инициации, но, по-видимому, это время объявления класса, т. Е. "Фиксированного" с самого начала, что нежелательно.

Что было бы наилучшим способом сделать это?

С прагматической точки зрения, правда, похоже, не больно оставлять аргумент timestamp для внешнего назначения, но я просто хочу избежать его из-за чистоты кода.

1 Ответ

1 голос
/ 29 октября 2019

Я не думаю, что вы можете достичь этого с помощью именованных кортежей.

Если вы хотите, чтобы объект данных был неизменным "своего рода", вы могли бы использовать замороженный класс данных:

import pandas as pd
import datetime
from dataclasses import dataclass, field
import time

@dataclass(frozen=True)
class Record:
    data: dict
    timestamp: pd.Timestamp = field(default_factory=datetime.datetime.now)

record1 = Record(data={'x': 1})
time.sleep(1)
record2 = Record(data={'x': 1})

print(record1.timestamp, record2.timestamp)
...