Доступ к имени экземпляра в Python для печати - PullRequest
2 голосов
/ 23 августа 2010

Итак, в рамках задачи 17.6 в «Думай как компьютерный ученый» я написал класс под названием «Кенгуру»:

class Kangaroo(object):

    def __init__(self, pouch_contents = []):
        self.pouch_contents = pouch_contents

    def __str__(self):
        '''
        >>> kanga = Kangaroo()
        >>> kanga.put_in_pouch('olfactory')
        >>> kanga.put_in_pouch(7)
        >>> kanga.put_in_pouch(8)
        >>> kanga.put_in_pouch(9)
        >>> print kanga
        "In kanga's pouch there is: ['olfactory', 7, 8, 9]"
        '''

        return "In %s's pouch there is: %s" % (object.__str__(self), self.pouch_contents)

    def put_in_pouch(self, other):
        '''
        >>> kanga = Kangaroo()
        >>> kanga.put_in_pouch('olfactory')
        >>> kanga.put_in_pouch(7)
        >>> kanga.put_in_pouch(8)
        >>> kanga.put_in_pouch(9)
        >>> kanga.pouch_contents
        ['olfactory', 7, 8, 9]
        '''

        self.pouch_contents.append(other)

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

In <__main__.Kangaroo object at 0x4dd870>'s pouch there is: ['olfactory', 7, 8, 9]

В сущности, мне интересно, есть ли какая-нибудь функция, которую я могу выполнять на kanga = Kangaroo, чтобы вывод этой функции составлял те 5 символов,т.е. функция (канга) -> "канга".

Есть идеи?

Редактировать: Чтение первого ответа заставило меня понять, что есть более краткий способ задать мой первоначальный вопрос.Есть ли способ переписать __init__ так, чтобы следующий код действовал как написано?

>>> somename = Kangaroo()
>>> somename.name
'somename'

Ответы [ 5 ]

6 голосов
/ 23 августа 2010

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

marsupials = []
marsupials.append(Kangaroo()) 

Это классическое эссе от effbot дает превосходноеобъяснение.

Чтобы ответить на пересмотренный вопрос в вашем редакторе: Нет.

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

В реализациях Python по крайней мере в любой момент времени все существующие объекты имеют уникальный идентификатор, который может быть получен с помощью id(obj).Это может быть достаточно для отладки.Обратите внимание, что если объект удален, этот идентификатор (который является адресом памяти) может быть повторно использован впоследствии созданным объектом.

2 голосов
/ 23 августа 2010

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

import sys

class Kangaroo(object):
    def __str__(self):
        flocals = sys._getframe(1).f_locals
        for ident in flocals:
            if flocals[ident] is self:
                name = ident
                break
        else:   
            name = 'roo'
        return "in {0}'s pouch, there is {1}".format(name, self.pouch_contents)

kang = Kangaroo()
print kang

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

Работает путем извлечения словаря f_locals из стекового фрейма, представляющего пространство имен, в котором вызывается print kang.Ключи f_locals - это имена переменных в кадре, поэтому мы просто циклически повторяем его и проверяем, является ли каждая запись self.Если это так, мы break.Если break не выполняется, то мы не нашли запись, и предложение loops else присваивает значение 'roo' в соответствии с запросом.

Если вы хотите получить его из контейнера некоторогоsort, вам нужно расширить это, чтобы просмотреть любые контейнеры в f_locals.Вы можете либо вернуть ключ, если это контейнер типа dict, либо индекс, если это что-то вроде кортежа или списка.

2 голосов
/ 23 августа 2010
class Kangaroo(object):

    def __init__(self, pouch_contents=None, name='roo'):
        if pouch_contents is None:
            self.pouch_contents = []  # this isn't shared with all other instances
        else:
            self.pouch_contents = pouch_contents
        self.name = name
    ...

kanga = Kangaroo(name='kanga')

Обратите внимание, что это хороший стиль , а не - ставить пробелы вокруг = в аргументах

0 голосов
/ 23 августа 2010

То, что вы хотите, практически невозможно в Python, даже с предлагаемыми "хаки".Например, что напечатал бы следующий код?

>>> kanga1 = kanga2 = kanga3 = Kangaroo()
>>> kanga2.name 
???
>>> kanga3.name
???

или

>>> l = [Kangaroo()]
>>> l[0].name
???

Если вы хотите "именованные" объекты, просто укажите имя для вашего объекта

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

Более явный (что нам нравится в Python) и непротиворечивый во всех случаях.Конечно, вы можете сделать что-то вроде

>>> foo = Kangaroo("bar")
>>> foo.name
'bar'

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

0 голосов
/ 23 августа 2010

Я не видел хакерского ответа aaronasterling, когда начал работать над этим, но в любом случае вот мой хакерский ответ:

class Kangaroo(object):

    def __init__(self, pouch_contents = ()):
        self.pouch_contents = list(pouch_contents)

    def __str__(self):
        if not hasattr(self, 'name'):
            for k, v in globals().iteritems():
                if id(v) == id(self):
                    self.name = k
                    break
                else:
                    self.name = 'roo'                    
        return "In %s's pouch there is: %s" % (self.name, self.pouch_contents)

kanga = Kangaroo()
print kanga

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

...