Как получить переменные экземпляра в Python?

120

Есть ли в Python встроенный метод для получения массива всех переменных экземпляра класса? Например, если у меня есть этот код:

class hi:
  def __init__(self):
    self.ii = "foo"
    self.kk = "bar"

Есть ли у меня способ сделать это:

>>> mystery_method(hi)
["ii", "kk"]

Изменить: изначально я ошибочно запрашивал переменные класса.

Крис Банч
источник
В вашем примере показаны «переменные экземпляра». Другое дело - переменные класса.
S.Lott

Ответы:

143

У каждого объекта есть __dict__переменная, содержащая все переменные и ее значения.

Попробуй это

>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()
CNU
источник
7
FWIW, модуль inspect дает вам более надежный метод, чем полагаться на dict , который есть не во всех экземплярах.
Томас Воутерс,
1
У какого экземпляра нет dict ? Никогда не встречал.
Карл Мейер,
3
Некоторые встроенные типы, например int. Попробуйте сказать «x = 5», а затем «x .__ dict__», и вы получите AttributeError
Эли Кортрайт
6
Также все, что использует слоты .
Томас Воутерс,
2
Зачем вам пытаться получить переменные экземпляра класса int? Это даже не класс (хотя я могу ошибаться в этом).
Мартин Шерберн,
103

Используйте vars ()

class Foo(object):
    def __init__(self):
        self.a = 1
        self.b = 2

vars(Foo()) #==> {'a': 1, 'b': 2}
vars(Foo()).keys() #==> ['a', 'b']
Джереми Кантрелл
источник
6
+1 Я лично считаю, что этот синтаксис чище, чем использование dict , поскольку атрибуты с двойным подчеркиванием должны быть «частными» в синтаксисе Python.
Martin W,
3
@Martin: __methodчастный, __method__это особый метод, не обязательно частный; Я хотел бы сказать, что специальные методы определяют возможности объекта, а не методы.
u0b34a0f6ae
2
__method__довольно некрасиво, и я думаю, что они были названы так, чтобы попытаться удержать людей от их использования без крайней необходимости. В этом случае у нас есть альтернатива vars ().
Мартин Шерберн
в моем случае я попытался вызвать vars (ObjName), и он возвращает dict_proxy со словарем, ключи которого являются методами данного класса / объекта, но без признаков элементов инициализации . Есть догадки почему?
user228137 05
Дважды Переменные подчеркивания __str__, __method__являются для самого языка нормально. Что происходит, когда ты str(something)?
Zizouz212
15

Обычно вы не можете получить атрибуты экземпляра, заданные только классом, по крайней мере, без создания экземпляра класса. Однако вы можете получить атрибуты экземпляра для данного экземпляра или атрибуты класса для класса. См. Модуль «инспектировать». Вы не можете получить список атрибутов экземпляра, потому что экземпляры действительно могут иметь что угодно в качестве атрибута, и - как в вашем примере - обычный способ их создания - просто назначить им в методе __init__.

Исключением является случай, если ваш класс использует слоты, которые представляют собой фиксированный список атрибутов, которые класс разрешает иметь экземплярам. Слоты описаны в http://www.python.org/2.2.3/descrintro.html , но со слотами есть различные подводные камни; они влияют на структуру памяти, поэтому множественное наследование может быть проблематичным, и при наследовании в целом также должны учитываться слоты.

Томас Воутерс
источник
Голосование вниз, потому что «вы не можете получить список атрибутов экземпляра», просто неверно: и vars (), и dict дают вам именно это.
Карл Мейер,
2
Я предполагаю, что он имел в виду «вы не можете получить список всех возможных атрибутов экземпляра». Например, я часто использую ленивую генерацию и декоратор @property, чтобы добавить переменную экземпляра при первом запросе. Использование dict сообщит вам об этой переменной, когда она существует, но не заранее.
Эли Кортрайт,
5
Я не голосовал против, и обратите внимание на то, что я на самом деле сказал: вы не можете получить список атрибутов экземпляра, заданный только классом , что пытается сделать код, сопровождающий вопрос.
Томас Воутерс,
2
@Carl: Пожалуйста, учитесь перед тем, как писать ложные комментарии и голосовать против, исходя из вашего незнания.
nikow,
14

Оба метода Vars () и dict будут работать для примера, опубликованного OP, но они не будут работать для «слабо» определенных объектов, таких как:

class foo:
  a = 'foo'
  b = 'bar'

Чтобы распечатать все невызываемые атрибуты, вы можете использовать следующую функцию:

def printVars(object):
    for i in [v for v in dir(object) if not callable(getattr(object,v))]:
        print '\n%s:' % i
        exec('print object.%s\n\n') % i
DMark
источник
5
exec('print object.%s\n\n') % iдолжно быть написано какprint getattr(object, i)
user102008 05
11

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

>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")
Даниил
источник
6

В вашем примере показаны «переменные экземпляра», а не переменные класса.

Ищите hi_obj.__class__.__dict__.items()переменные класса вместе с другими членами класса, такими как функции-члены и содержащий модуль.

class Hi( object ):
    class_var = ( 23, 'skidoo' ) # class variable
    def __init__( self ):
        self.ii = "foo" # instance variable
        self.jj = "bar"

Переменные класса используются всеми экземплярами класса.

С. Лотт
источник
6

Предлагать

>>> print vars.__doc__
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

Другими словами, он просто обертывает __dict__

Даниил
источник
5

Хотя это и не является прямым ответом на вопрос OP, есть довольно приятный способ узнать, какие переменные находятся в области видимости функции. взгляните на этот код:

>>> def f(x, y):
    z = x**2 + y**2
    sqrt_z = z**.5
    return sqrt_z

>>> f.func_code.co_varnames
('x', 'y', 'z', 'sqrt_z')
>>> 

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

def exec_command(self, cmd, msg, sig):

    def message(msg):
        a = self.link.process(self.link.recieved_message(msg))
        self.exec_command(*a)

    def error(msg):
        self.printer.printInfo(msg)

    def set_usrlist(msg):
        self.client.connected_users = msg

    def chatmessage(msg):
        self.printer.printInfo(msg)

    if not locals().has_key(cmd): return
    cmd = locals()[cmd]

    try:
        if 'sig' in cmd.func_code.co_varnames and \
                       'msg' in cmd.func_code.co_varnames: 
            cmd(msg, sig)
        elif 'msg' in cmd.func_code.co_varnames: 
            cmd(msg)
        else:
            cmd()
    except Exception, e:
        print '\n-----------ERROR-----------'
        print 'error: ', e
        print 'Error proccessing: ', cmd.__name__
        print 'Message: ', msg
        print 'Sig: ', sig
        print '-----------ERROR-----------\n'
tim.tadh
источник
2

построен на ответе dmark, чтобы получить следующее, что полезно, если вам нужен эквивалент sprintf и, надеюсь, кому-то поможет ...

def sprint(object):
    result = ''
    for i in [v for v in dir(object) if not callable(getattr(object, v)) and v[0] != '_']:
        result += '\n%s:' % i + str(getattr(object, i, ''))
    return result
Итан Джоффе
источник
0

Иногда вам нужно отфильтровать список на основе общедоступных / частных переменных. Например

def pub_vars(self):
    """Gives the variable names of our instance we want to expose
    """
    return [k for k in vars(self) if not k.startswith('_')]
hi2meuk
источник