2013-09-24 2 views
1

Есть ли способ получить имя объекта, когда имя класса известно. Если для класса есть несколько объектов, они также должны быть напечатаны.Как получить объект для заданного имени класса в Python?

Class A(): 
    pass 

Предположим, что кто-то создал объекты для класса A в некоторых других файлах. Итак, я хочу посмотреть все экземпляры «класс А»

+1

0 Вы еще не добавили код ко всему, что вы пытаетесь это сделать? Я не понимаю, что вы имеете в виду с именем объекта в этом контексте. – RickyA

+4

Вы хотите получить все * экземпляры * данного класса? – Bakuriu

+0

Я думаю, вы можете найти ответ [здесь] (http://stackoverflow.com/questions/6566767/how-to-obtain-all-instances-of-a-class-within- the-current-module). – OBu

ответ

1

Вот версия получать экземпляры из памяти, я бы не рекомендовал использовать это в прямом коде, но это может быть удобно для отладки:

import weakref 


class SomeClass(object): 
    register = [] 

    def __init__(self): 
     self.register.append(weakref.ref(self)) 

a = SomeClass() 
b = SomeClass() 
c = SomeClass() 

# Now the magic :) 
import gc 


def get_instances(class_name): 
    # Get the objects from memory 
    for instance in gc.get_objects(): 
     # Try and get the actual class 
     class_ = getattr(instance, '__class__', None) 
     # Only return if the class has the name we want 
     if class_ and getattr(class_, '__name__', None) == class_name: 
      yield instance 

print list(get_instances('SomeClass')) 
+2

Одна из проблем с этим подходом заключается в том, что каждый из созданных SomeClass будет существовать вечно (так как класс сохраняет ссылку на него). – NPE

+0

На самом деле, объект для этого класса не создан мной. Поскольку я знаю имя класса, я хочу перечислить объекты, созданные для этого класса, на основе имени класса. – Sobhan

+0

@Sobhan См. Мой ответ за это, но я твердо верю, что вы просто попали в проблему [XY problem] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) и вы должны были спросить о вашей реальной проблеме, а не о вашем попытке решения. – Bakuriu

0
>>> class TestClass: 
...  pass 
... 
>>> foo = TestClass() 
>>> for i in dir(): 
...  if isinstance(eval(i), TestClass): 
...    print(i) 
... 
foo 
>>> 
0

экземпляры создаются в пространстве имен:

def some_function(): 
    some_object = MyClass() 

В этом случае some_object это имя внутри «пространства имен» функции, что указывает на MyClass экземпляра. Когда вы покидаете пространство имен (т. Е. Заканчивается функция), сборщик мусора Python очищает имя и экземпляр.

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

Итак: нет, нет места, где хранится список экземпляров.

Это был бы другой случай, когда вы использовали базу данных с ORM (объектно-реляционным преобразователем). В ORM Django вы можете сделать MyClass.objects.all(), если MyClass является объектом базы данных. Что-то посмотреть, если вам действительно нужна функциональность.

Обновление: См. Bakuriu's answer. Сборщик мусора (о котором я упоминал) знает обо всех случаях :-) И он предлагает модуль «weakref», который предотвращает мою проблему с очисткой.

2

Если вы один создания класса вы можете просто хранить слабые ссылки при создании экземпляра класса:

import weakref 

class A(object): 
    instances = [] 
    def __init__(self): 
     A.instances.append(weakref.ref(self)) 

a, b, c = A(), A(), A() 
instances = [ref() for ref in A.instances if ref() is not None] 

Использование слабых ссылок позволяет экземпляры должны быть высвобождены перед классом.

Подробные сведения о том, что он делает, см. В модуле weakref.


Обратите внимание, что вы может быть в состоянии использовать эту технику, даже с классами, которые вы не писали. Вам просто нужно monkey-patch класс. Например:

def track_instances(cls): 
    def init(self, *args, **kwargs): 
     getattr(self, 'instances').append(weakref.ref(self)) 
     getattr(self, '_old_init')(self, *args, **kwargs) 
    cls._old_init = cls.__init__ 
    cls.__init__ = init 
    return cls 

Тогда вы можете сделать:

track_instances(ExternalClass) 

И все экземпляры, созданные после исполнения этого утверждения можно найти в ExternalClass.instances.

В зависимости от класса вам, возможно, придется заменить __new__ вместо __init__.


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

import gc 

candidates = gc.get_referrers(cls_object) 
instances = [candidate for candidate in candidates if isinstance(candidate, cls_object)] 

И вы всегда можете получить объект класса, так как вы можете найти его с помощью object.__subclasses__ метод:

cls_object = next(cls for cls in object.__subclasses__() if cls.__name__ == cls_name) 

(предполагая, что только класс с этим именем, в противном случае вы должны попробовать все из них)

Однако я не могу представить себе ситуацию, когда это правильная вещь, поэтому избегать этого кода в реальных приложениях.


Я сделал некоторые испытания, и я считаю, что это решение не может работать для встроенных классов или классов, определенных в расширениях C.

Если вы в этом случае последнего средством является использование gc.get_objects() для получения всех отслеживаемых объектов. Однако это будет работать только в том случае, если объект поддерживает циклическую сборку мусора, поэтому нет способа, который работает в каждые возможной ситуации.

+0

Хороший ответ! Я обновил мой, чтобы указать на ваш, поскольку это лучше :-) У меня есть кое-что, что нужно сделать относительно модуля weakref. –

0

Python предоставляет модуль types, который определяет классы для встроенных типов и функции locals() и globals(), которые возвращают список локальных и глобальных переменных в приложении.

Одним быстрым способом поиска объектов по типу является это.

import types 

for varname, var_instance in locals().items(): 
    if type(var_instance) == types.InstanceType and var_instance.__class__.__name__ == 'CLASS_NAME_YOU_ARE_LOOKING_FOR': 
    print "This instance was found:", varname, var_instance 

Стоит ознакомиться с документацией библиотеки Python и прочитать документы для модулей, которые работают с кодом напрямую. Некоторые из них: inspect, gc, types, codeop, code, imp, ast. bdb, pdb. Исходный код IDLE также очень информативен.

+0

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

+0

Правда, это не лучший способ сделать это. Использование gc и weakref, как предложено в одном из приведенных выше ответов, является лучшим решением – MrD

0

Вы можете получить имена для всех экземпляров, так как они могут иметь не все имена, или имена, которые у них есть, могут быть в области видимости. Вы можете получить экземпляры.

Если вы готовы следить за экземплярами себя, используйте WeakSet:

import weakref 
class SomeClass(object): 
instances = weakref.WeakSet() 
def __init__(self): 
    self.instances.add(self) 


>>> instances = [SomeClass(), SomeClass(), SomeClass()] 
>>> other = SomeClass() 
>>> SomeClass.instances 
<_weakrefset.WeakSet object at 0x0291F6F0> 
>>> list(SomeClass.instances) 
[<__main__.SomeClass object at 0x0291F710>, <__main__.SomeClass object at 0x0291F730>, <__main__.SomeClass object at 0x028F0150>, <__main__.SomeClass object at 0x0291F210>] 

Обратите внимание, что только удаление имени не может уничтожить экземпляр. other до сих пор существует, пока мусор не собрали:

>>> del other 
>>> list(SomeClass.instances) 
[<__main__.SomeClass object at 0x0291F710>, <__main__.SomeClass object at 0x0291F730>, <__main__.SomeClass object at 0x028F0150>, <__main__.SomeClass object at 0x0291F210>] 
>>> import gc 
>>> gc.collect() 
0 
>>> list(SomeClass.instances) 
[<__main__.SomeClass object at 0x0291F710>, <__main__.SomeClass object at 0x0291F730>, <__main__.SomeClass object at 0x0291F210>] 

Если вы не хотите, чтобы отслеживать их вручную, то можно использовать gc.get_objects() и отфильтровать экземпляры, которые вы хотите, но это означает, что вы должны отфильтровать через все объекты в вашей программе каждый раз, когда вы это делаете. Даже в приведенном выше примере это означает, что вы можете обрабатывать почти 12 000 объектов, чтобы найти 3 экземпляра, которые вы хотите.

>>> [g for g in gc.get_objects() if isinstance(g, SomeClass)] 
[<__main__.SomeClass object at 0x0291F210>, <__main__.SomeClass object at 0x0291F710>, <__main__.SomeClass object at 0x0291F730>] 
0

Наконец-то нашел способ пройти.

Как я знаю имя класса, я бы искать объект, созданный для данного класса в сборщика мусора (ГЦ), как это ...

for instance in gc.get_objects(): 

      if str(type(instance)).find("dict") != -1: 

       for k in instance.keys(): 

        if str(k).find("Sample") != -1: 

         return k 

Приведенный выше код возвращает экземпляр класса, который будет быть таким. К сожалению, его формат в формате String не соответствует требованиям. Он должен быть типа «obj».

<mod_example.Sample object at 0x6f55250> 

Из приведенного выше значения, разобрать идентификатор (0x6f55250) и получить ссылку на объект, основанный на его идентификатор.

obj_id = 0x6f55250 
for obj in gc.get_objects(): 
      # Converting decimal value to hex value 
      if id(obj) == ast.literal_eval(obj_id): 
       required_obj = obj 

Следовательно, required_obj будет хранить ссылку на объект точно в формате 'obj'.

:-)

Смежные вопросы