2014-10-27 1 views
0

Если я импортировать класс и переименовать его подклассов, это довольно просто, чтобы найти новое имя класса:Можем ли мы найти имя класса _local_ для объекта, созданного из класса, импортированного с помощью «import as»?

>>> from timeit import Timer 
>>> class Test(Timer): 
...  pass 
... 
>>> test = Test() 
>>> test.__class__.__name__ 
'Test' 

Однако, если я псевдоним класса, как я импортировать его, он сохраняет свое название от своего модуля хоста :

>>> from timeit import Timer as Test2 
>>> test2 = Test2() 
>>> test2.__class__.__name__ 
'Timer' 

Позже, я хочу, чтобы предоставить пользователю, выход, который знает о названии они данного класса в их имен. Рассмотрите:

def report_stats(timer): 
    print("Runtime statistics for %s:" % timer.__class__.__name__) 
    ... 

Есть ли способ, чтобы получить строку для чтения «test2», не хватает итерацию переменных в пространстве имен, чтобы проверить точное совпадение?

+2

Нет. Вам придется искать его, и у него всегда может быть несколько имен. Имя, которое было во время определения, - это все, что было сохранено в классе. Когда вы подклассифицируете его, вы не переименовываете его, вы создаете новый класс с исходным классом в качестве одной из его баз. – agf

+0

Если вы ответите на это, @agf, я приму это. Я также дам свой собственный ответ, основанный на ужасных вещах, которые я обнаружил в нижней части кроличьей дыры. – abathur

ответ

0

В моем собственном вопросе есть действительно ужасный ответ; Я не буду принимать это, поскольку он, вероятно, довольно хрупкий (я тестировал только ограниченный набор условий вызова). Я в основном просто охотился за этой проблемой; Скорее всего, я буду использовать что-то более долговечное для моего фактического использования.

Это предполагает, что мы имеем доступ к инициализации функции класса мы пытаемся импортировать, как бэ, и какое-то постоянного внешнего хранилища данных, по крайней мере, для более сложных случаев края:

import inspect, dis 

class Idiom(object): 
    description = None 
    alias = None 

    def __init__(self, desc): 
     global data_ob 
     self.description = desc 

     if self.__class__.__name__ == 'Idiom': 
      #cheat like hell to figure out who called us 
      self.alias = data_ob.name_idiom(inspect.currentframe().f_back) 
     else: 
      self.alias = self.__class__.__name__ 

class DataOb(object): 
    code = None 
    locations = {} 
    LOAD_NAME = 101 
    codelen = None 

    def name_idiom(self, frame): 
     if not self.code: 
      self.code = frame.f_code 
      self.codelen = len(self.code.co_code) 
      self.locations = {y:x for x, y in dis.findlinestarts(self.code)} 

     target_line = frame.f_lineno 
     addr_index = self.locations[target_line]+1 
     name_index = self.code.co_code[addr_index] 

     # there's a chance we'll get called again this line, 
     # so we want to seek to the next LOAD_NAME instance(101) 
     addr_index += 1 
     while addr_index < self.codelen: 
      if self.code.co_code[addr_index] == self.LOAD_NAME: 
       self.locations[target_line] = addr_index 
       break 
      addr_index += 1 

     return self.code.co_names[name_index] 

Краткое объяснение того, как это работает:

  • мы смотрим предыдущий кадр из функции инициализации
  • получить код объекта
  • место находки байткода для начала каждой строки в коде
  • использовать строки-номер из кадра, чтобы захватить место байткода для начала этой строки
  • найти индикатор LOAD_NAME в байткоде для этой линии (Я действительно не придерживаюсь этого; мой код предполагает, что он будет там)
  • взгляд в следующую позицию байткода для индекса, который указывает на то, какое положение в кортеже code.co_names содержит «имя» LOAD_NAME вызова

Отсюда мы можем сделайте что-нибудь вроде:

>>> from rabbit_hole import Idiom as timer_bob 
>>> with timer_bob("down the rabbit hole"): 
...  waste_some_time = list(range(50000)) 
... 
timer_bob: down the rabbit hole 
    runtime: 0:00:00.001909, children: 0:00:00, overhead: 0:00:00.001909 
+1

Поздравляем, вы выиграли премию Evil Python на этой неделе. –

+0

@ IgnacioVazquez-Abrams Надеюсь, я надеюсь, что это связано с высокими вечными расходами на обслуживание. – abathur