3

I'm trying to print out the instance name of a class. In this example it's a timer that prints out how long various overlapping sections of my code are running:

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

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

So when I call it in my code it would look something like:

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

Which would output:

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

I know I can initialize the function with it's name: allcode=timerstart(name='allcode') which is annoying.

I am also running into issues with traceback using: inspect.currentframe().f_back.f_locals.items()

Is there a way to print the instance name, like print(self.selfname) or something?

Audelia
  • 101
  • 1
  • 3
  • Consider this question: [Getting the name of a variable as a string](https://stackoverflow.com/questions/18425225/getting-the-name-of-a-variable-as-a-string) – Ṃųỻịgǻňạcểơửṩ Dec 04 '19 at 15:41
  • 1
    No, instances don't *have* names. A variable is a one-way mapping, as multiple variables can refer to the same object, but that object knows nothing about what names refer to it. – chepner Dec 04 '19 at 15:43
  • 1
    You probably want to make `timerstart` a context manager anyway, so that you can write `with timerstart("allcode"): ...`. The body of the `with` statement will delimit the block to be timed, rather than being ended with an explicit call to `stop`. – chepner Dec 04 '19 at 15:44
  • 1
    Does this answer your question? [python obtain variable name of argument in a function](https://stackoverflow.com/questions/11583526/python-obtain-variable-name-of-argument-in-a-function) – Fred Larson Dec 04 '19 at 15:44

3 Answers3

0

Make timerstart a context manager. Then you don't necessarily need a reference to the timer object at all.

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}')

Then you'll write your code using with statements:

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

You might be able to define the manager using contextlib.contextmanager rather than explicitly defining __enter__ and __exit__ methods on a class.

import contextlib


@contextlib.contextmanager
def timer(name):
    start = time.time()
    yield
    print(f'{name} total time {time.time() - start}')
chepner
  • 497,756
  • 71
  • 530
  • 681
0

The short answer is: Cannot always work. Python variable names are one-way mappings to that object. The same instance may go under multiple names, meaning that multiple variables refer to the same instance. A simple example is:

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]

Here, the object instantiated by obj1 also goes under the name of obj2. Printing or obtaining the instance name of this class is now ambiguous.

The best way to get the name the object allcode and subcode is to assign a name field, and instantiate it like what you did before, or modify the constructor so you have to assign a name to it.

  • 1
    I'm only interested in the name it was initialized with. If another variable name is assigned to that object later, it makes sense for it to still get traced back to the original name that instantiated the object. This would leave no ambiguity in the name and *should* be easy to keep track of, just like assigning a field name – Audelia Dec 05 '19 at 14:49
  • Python does not 'remember' variable names at time of initialization. The best way is to assign a mandatory field name to the variable. – Ṃųỻịgǻňạcểơửṩ Dec 05 '19 at 15:53
0

I have wrapped it into a package: https://github.com/pwwang/python-varname

You can easily do it with the package:

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()

This prints:

subcode total time is  1.0007166862487793
allcode total time is  3.0030770301818848
Panwen Wang
  • 3,573
  • 1
  • 18
  • 39