Могу ли я распечатать имя экземпляра класса?

Я пытаюсь распечатать имя экземпляра класса. В этом примере это таймер, который выводит, как долго выполняются различные перекрывающиеся участки моего кода:

class timerstart:
    def __init__(self):
        # Sets some variables with system time

    def stop(self):
        # Calculates current total time
        print(*instance name*, 'total time is ...')

Поэтому, когда я вызываю это в своем коде, это будет выглядеть примерно так:

allcode=timerstart()
  # some code
    subcode=timerstart()
      # some code
    subcode.stop()
  # some code
allcode.stop()

Что выведет:

subcode total time...
allcode total time...

Я знаю, что могу инициализировать функцию с ее именем: allcode=timerstart(name='allcode'), что раздражает.

Я также сталкиваюсь с проблемами с трассировкой, используя: inspect.currentframe().f_back.f_locals.items()

Есть ли способ напечатать имя экземпляра, например print(self.selfname) или что-то в этом роде?


person Audelia    schedule 04.12.2019    source источник


Ответы (3)


Сделайте timerstart менеджером контекста. Тогда вам вообще не нужна ссылка на объект timer.

import time


class timer:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        self.start = time.time()

    def __exit__(self, *args):
        print(f'{self.name} total time {time.time() - self.start}')

Затем вы напишете свой код, используя операторы with:

with timer("allcode"):
    # some code
    with timer("subcode"):
        # some sub-block
    # some more code

Возможно, вы сможете определить менеджера, используя contextlib.contextmanager, а не явно определяя методы __enter__ и __exit__ в классе.

import contextlib


@contextlib.contextmanager
def timer(name):
    start = time.time()
    yield
    print(f'{name} total time {time.time() - start}')
person chepner    schedule 04.12.2019

Короткий ответ: Не всегда работает. Имена переменных Python являются односторонними сопоставлениями с этим объектом. Один и тот же экземпляр может иметь несколько имен, что означает, что несколько переменных ссылаются на один и тот же экземпляр. Простой пример:

obj1 = [1,2,3]
obj2 = obj1
# Demonstration that the object is now obj2 and obj1 at the same time
obj2[0] = 0
obj1 = [0,2,3]

Здесь объект, созданный obj1, также имеет имя obj2. Печать или получение имени экземпляра этого класса теперь неоднозначны.

Лучший способ получить имя объекта allcode и subcode — это назначить поле имени и создать его экземпляр, как вы делали раньше, или изменить конструктор, чтобы вам пришлось присвоить ему имя.

person Ṃųỻịgǻňạcểơửṩ    schedule 04.12.2019
comment
Меня интересует только имя, с которым оно было инициализировано. Если позже этому объекту будет присвоено другое имя переменной, имеет смысл проследить его до исходного имени, создавшего экземпляр объекта. Это не оставило бы двусмысленности в имени и должно быть легко отслеживаемым, точно так же, как присвоение имени поля - person Audelia; 05.12.2019
comment
Python не «запоминает» имена переменных во время инициализации. Лучший способ — присвоить переменной обязательное имя поля. - person Ṃųỻịgǻňạcểơửṩ; 05.12.2019

Я завернул его в пакет: https://github.com/pwwang/python-varname

Вы можете легко сделать это с помощью пакета:

import time
from varname import varname

class timerstart:
    def __init__(self):
        self.name = varname()
        self.start = time.time()
        # Sets some variables with system time

    def stop(self):
        # Calculates current total time
        print(self.name, 'total time is ', time.time() - self.start)

allcode=timerstart()

# some code
time.sleep(1)

subcode=timerstart()

# some code
time.sleep(1)

subcode.stop()

# some code
time.sleep(1)

allcode.stop()

Это печатает:

subcode total time is  1.0007166862487793
allcode total time is  3.0030770301818848
person Panwen Wang    schedule 09.07.2020