2009-11-06 5 views
15

При создании нового объекта класса в python я хочу иметь возможность создать значение по умолчанию, основанное на имени экземпляра класса, без передачи дополнительного аргумента. Как я могу это сделать? Вот основной псевдо-код, который я пытаюсь для:Получение имени экземпляра внутри класса __init __()

class SomeObject(): 
    defined_name = u"" 

    def __init__(self, def_name=None): 
     if def_name == None: 
      def_name = u"%s" % (<INSTANCE NAME>) 
     self.defined_name = def_name 

ThisObject = SomeObject() 
print ThisObject.defined_name # Should print "ThisObject" 
+0

зачем вам это нужно? – SilentGhost

+0

Управление информацией о канале в скрипте irc для моей внутренней сети. –

+1

Это странно. Какой язык допускает такую ​​ссылку на переменную времени компиляции во время выполнения? –

ответ

20

У экземпляров нет имен. К моменту, когда глобальное имя ThisObject получает , связанный с экземпляром, созданным путем вычисления конструктора SomeObject, конструктор завершен.

Если вы хотите, чтобы объект имел имя, просто передайте имя в конструкторе.

def __init__(self, name): 
    self.name = name 
+0

Понравился этот ответ лучше всего, так как я уже знаю, что в Python нет истинных переменных (на самом деле все равно должен быть способ захватить имя, привязанное к экземпляру, но это еще один аргумент для другого дня, который я предполагаю). Логично, что у него не было бы привязанного имени к экземпляру, поэтому я предполагаю, что пока я просто требую «def_name» вместо «def_name = None» –

+4

. Нет такой вещи, как «переменная» вашего определение. На каком языке может быть привязан какой-то объект к одному имени? –

+1

@AkoiMeexx Серьезно, на каком языке есть «истинные» переменные по вашему определению? – Marcin

3

Это не может работать, только представьте себе: a = b = TheMagicObjet(). Имена не влияют на Ценности, они просто указывают на них.

+1

Правильно, но факт в том, что я не хочу самих значений, но имя указывает на них как на строку. –

+2

Дело в том, что на примере THC4k TheMagicObjet() имеет 2 имени, указывающих на него: «a» и «b» - какой вы хотите? – PaulMcG

+1

Каковы имена объектов в этом списке: 'L = [TheMagicObjet() для x в xrange (10)]'? – u0b34a0f6ae

2

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

Не имеет никакого значения для объекта, какие имена, если таковые имеются, могут быть связаны. Это может быть связано с десятками разных имен или нет. Кроме того, у Python нет никаких «обратных ссылок», которые указывают от объекта к имени.

Рассмотрим следующий пример:

foo = 1 
bar = foo 
baz = foo 

Теперь предположим, что у вас есть целое объект со значением 1, и вы хотите работать в обратном направлении и найти свое имя. Что бы вы напечатали? Три разных имени имеют связанный с ними объект, и все они одинаково действительны.

print(bar is foo) # prints True 
print(baz is foo) # prints True 

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

How do I get the string representation of a variable in python?

Существует известная презентация под названием «Кодекс Как Pythonista», который суммирует эту ситуацию как «Другие языки имеют„переменные“» и «Python имеет" имена»

http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables

+0

Прошу прощения, но в каком смысле у python нет переменных? – Marcin

+0

@ Марцин, вы нашли мое объяснение трудным для понимания? Я немного переписал его, и, возможно, вы поймете это позже. – steveha

+0

(1) Вы не объясняете утверждение, что на python отсутствуют переменные. (2) Это неверно. Все языки, использующие типы в штучной упаковке, имеют такие переменные, как python (за исключением того, что их переменные могут быть напечатаны). Это просто попытка заявить о различии для python, которого нет. – Marcin

19

Ну, есть почти способ сделать это:

#!/usr/bin/env python 
import traceback 
class SomeObject(): 
    def __init__(self, def_name=None): 
     if def_name == None: 
      (filename,line_number,function_name,text)=traceback.extract_stack()[-2] 
      def_name = text[:text.find('=')].strip() 
     self.defined_name = def_name 

ThisObject = SomeObject() 
print ThisObject.defined_name 
# ThisObject 

модуль отслеживающий позволяет заглянуть в сотрудничестве de используется для вызова SomeObject(). С небольшим перегибом строк, text[:text.find('=')].strip() вы можете угадать, что должно быть def_name.

Однако этот хак хрупкий.Например, это не работает так хорошо:

ThisObject,ThatObject = SomeObject(),SomeObject() 
print ThisObject.defined_name 
# ThisObject,ThatObject 
print ThatObject.defined_name 
# ThisObject,ThatObject 

Так что, если вы должны были использовать этот хак, вы должны иметь в виду, что вы должны вызвать SomeObject() с помощью простой питон заявление:

ThisObject = SomeObject() 

Кстати, в качестве еще одного примера использования отслеживающего, если определить

def pv(var): 
    # stack is a list of 4-tuples: (filename, line number, function name, text) 
    # see http://docs.python.org/library/traceback.html#module-traceback 
    # 
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2] 
    # ('x_traceback.py', 18, 'f', 'print_var(y)') 
    print('%s: %s'%(text[text.find('(')+1:-1],var)) 

то вы можете позвонить

x=3.14 
pv(x) 
# x: 3.14 

для печати имени переменной и ее значения.

+3

Woah, это настолько круто, почти кричит: «Вы не должны это делать!» :) – shylent

+7

Сначала это называется хак, потом круглая, ... довольно скоро его назовут идиомой :) – unutbu

0

Я думаю, что вопросы, имена, если они не являются указателями на любой объект .. не имеет значение, если:

foo = 1 
bar = foo 

Я знаю, что Foo указывает на 1 и бар указывает на то же значение 1 в той же памяти пространство. , но предположим, что я хочу создать класс с функцией, которая добавляет к нему объект.

Class Bag(object): 
    def __init__(self): 
     some code here... 
    def addItem(self,item): 
     self.__dict__[somewaytogetItemName] = item 

Так что, когда я создаю экземпляр класса мешок, как показано ниже:

newObj1 = Bag() 
newObj2 = Bag() 
newObj1.addItem(newObj2)I can do this to get an attribute of newObj1: 
newObj1.newObj2 
2

Один ужасный, ужасный способ сделать это, чтобы полностью изменить обязанности:

class SomeObject(): 
    def __init__(self, def_name): 
     self.defined_name = def_name 
     globals()[def_name] = self 

SomeObject("ThisObject") 
print ThisObject.defined_name 

Если вы хотите поддерживайте что-то, кроме глобального масштаба, вам придется сделать что-то еще более ужасное.

6

Вы можете создать метод внутри вашего класса, который проверяет все переменные в текущем фрейме и использует hash() для поиска переменной self.

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

В приведенном ниже классе, isinstance() используется, чтобы избежать проблем при применении hash(), так как некоторые объекты, как в numpy.array или list, например, являются unhashable.

import inspect 
class A(object): 
    def get_my_name(self): 
     ans = [] 
     frame = inspect.currentframe().f_back 
     tmp = dict(frame.f_globals.items() + frame.f_locals.items()) 
     for k, var in tmp.items(): 
      if isinstance(var, self.__class__): 
       if hash(self) == hash(var): 
        ans.append(k) 
     return ans 

Следующее испытание было сделано:

def test(): 
    a = A() 
    b = a 
    c = b 
    print c.get_my_name() 

Результат:

test() 
#['a', 'c', 'b'] 
-1

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

Если вы создаете экземпляр с «ThisObject = SomeObject()» из командная строка, вы можете получить имя объекта из командной строки в истории команд:

import readline 
import re 

class SomeObject(): 
    def __init__(self): 
     cmd = readline.get_history_item(readline.get_current_history_length())               
     self.name = re.split('=| ',cmd)[0] 

Если вы создаете экземпляр с помощью команды «EXEC», вы можете справиться с этим с:

if cmd[0:4] == 'exec': self.name = re.split('\'|=| ',cmd)[1]  # if command performed using 'exec' 
else: self.name = re.split('=| ',cmd)[0] 
Смежные вопросы