ฉันสามารถพิมพ์ชื่ออินสแตนซ์ของคลาสได้หรือไม่

ฉันกำลังพยายามพิมพ์ชื่ออินสแตนซ์ของคลาส ในตัวอย่างนี้ เป็นตัวจับเวลาที่จะพิมพ์ว่าส่วนต่างๆ ที่ทับซ้อนกันในโค้ดของฉันทำงานนานแค่ไหน:

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 แหล่งที่มา
comment
ไม่ อินสแตนซ์ไม่มี มี ชื่อ ตัวแปรคือการแมปทางเดียว เนื่องจากตัวแปรหลายตัวสามารถอ้างถึงออบเจ็กต์เดียวกันได้ แต่ออบเจ็กต์นั้นไม่รู้อะไรเลยเกี่ยวกับชื่อที่อ้างถึง   -  person chepner    schedule 04.12.2019
comment
คุณอาจต้องการทำให้ timerstart เป็นตัวจัดการบริบทอยู่ดี เพื่อที่คุณจะได้เขียน with timerstart("allcode"): ... ได้ เนื้อความของคำสั่ง with จะกำหนดขอบเขตของบล็อกที่จะกำหนดเวลา แทนที่จะจบลงด้วยการเรียก stop อย่างชัดเจน   -  person chepner    schedule 04.12.2019


คำตอบ (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 คือการกำหนดฟิลด์ชื่อ และสร้างอินสแตนซ์เหมือนที่คุณเคยทำมาก่อน หรือแก้ไข Constructor ดังนั้นคุณต้องกำหนดชื่อให้กับวัตถุนั้น

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