Як отримати змінні екземпляри в 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()

7
FWIW, модуль перевірки дає вам більш надійний метод, ніж покладання на dict , який мають не всі екземпляри.
Thomas Wouters

1
Який екземпляр не має диктату ? Я жодного разу не стикався з ним.
Карл Мейєр

3
Певні вбудовані типи, наприклад, int. Спробуйте сказати "x = 5", а потім "x .__ dict__", і ви отримаєте AttributeError
Eli Courtwright

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.
Мартін Ш

3
@Martin: __methodприватний, __method__це спеціальний метод, не обов'язково приватний; Я хотів би сказати, що спеціальні методи визначають можливості об'єкта, а не методи.
u0b34a0f6ae

2
__method__це дуже потворно, і я думаю, що вони були названі таким чином, щоб спробувати відмовити людей від їх використання, якщо це абсолютно не потрібно. У цьому випадку ми маємо альтернативу vars ().
Мартін Шерберн

у моєму випадку я спробував викликати vars (ObjName), і він повертає dict_proxy зі словником, ключі якого є методами даного класу / об'єкта, але немає ознаки елементів init . Будь-які здогадки, чому?
користувач228137

Двічі Змінні підкреслення __str__, __method__є для самої мови нормально. Що відбувається, коли ти str(something)?
Zizouz212

15

Зазвичай ти не можеш отримати атрибути екземпляра, що задаються лише класом, принаймні не без інстанціювання класу. Ви можете отримати атрибути екземпляра, що задаються екземпляром, хоча або атрибути класу, що даються класу. Дивіться модуль "перевірити". Ви не можете отримати список атрибутів екземплярів, оскільки екземпляри дійсно можуть мати що-небудь як атрибут, а - як у вашому прикладі - звичайний спосіб їх створення - це просто призначити їм метод __init__.

Виняток становить, якщо ваш клас використовує слоти, що є фіксованим переліком атрибутів, якими клас дозволяє екземпляри. Слоти пояснюються на http://www.python.org/2.2.3/descrintro.html , але існують різні підводні камені з прорізами; вони впливають на компонування пам’яті, тому багаторазове успадкування може бути проблематичним, і спадкування взагалі має враховувати слоти.


Відхилення, оскільки "ви не можете отримати список атрибутів екземпляра", просто неправильно: і vars (), і dict дають саме це.
Карл Мейєр

2
Я припускаю, що він мав на увазі "ви не можете отримати список усіх можливих атрибутів примірника". Наприклад, я часто використовую ледачу генерацію та декоратор @property, щоб додати змінну екземпляра при першому запиті. Використання dict розповість вам про цю змінну, коли вона існувала, але не заздалегідь.
Елі Кортрайт

5
Я не сказав, і будь ласка, зверніть увагу на те, що я насправді сказав: ви не можете отримати список атрибутів екземпляра, що задаються просто класом , і це намагається зробити код, що супроводжує питання.
Thomas Wouters

2
@Carl: Будь-ласка, навчіться себе перед тим, як писати неправдиві коментарі та відмовлятись на підставі вашої недостатності знань.
nikow

14

І Vars (), і метод dict працюватимуть для прикладу, розміщеного в ОП, але вони не працюватимуть для "вільно" визначених об'єктів, таких як:

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

5
exec('print object.%s\n\n') % iслід писати якprint getattr(object, i)
user102008

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

Хоча це не є прямою відповіддю на питання ОП, є досить солодкий спосіб з'ясувати, які змінні знаходяться в області функції. погляньте на цей код:

>>> 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'

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('_')]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.