如何在 Python 中获取实例变量?

Posted

技术标签:

【中文标题】如何在 Python 中获取实例变量?【英文标题】:How to get instance variables in Python? 【发布时间】:2010-09-11 15:59:12 【问题描述】:

Python 中是否有内置方法来获取包含所有类的实例变量的数组?例如,如果我有这个代码:

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

有没有办法让我这样做:

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

编辑:我最初错误地要求类变量。

【问题讨论】:

您的示例显示“实例变量”。类变量是另一回事。 【参考方案1】:

每个对象都有一个__dict__ 变量,其中包含所有变量及其值。

试试这个

>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()

【讨论】:

FWIW,inspect 模块为您提供了一种比依赖 dict 更可靠的方法,并非所有实例都有。 什么样的实例没有dict?我从来没有遇到过。 某些内置类型,例如 int。尝试说“x = 5”,然后说“x.__dict__”,你会得到一个 AttributeError 还有,任何使用 slots 的东西。 为什么要尝试获取 int 的类实例变量?它甚至不是一门课(尽管我可能错了)。【参考方案2】:

使用 vars()

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

vars(Foo()) #==> 'a': 1, 'b': 2
vars(Foo()).keys() #==> ['a', 'b']

【讨论】:

+1 我个人认为这种语法比使用 dict 更简洁,因为带有双下划线的属性在 Python 语法中应该是“私有的”。 @Martin:__method是私有的,__method__是特殊方法,不一定是私有的;我想说的是特殊方法定义了一个对象的能力而不是方法。 __method__ 非常丑陋,我认为它们被这样命名是为了阻止人们使用它们,除非绝对必要。在这种情况下,我们有替代的 vars()。 在我的情况下,我尝试调用 vars(ObjName) 并返回一个带有字典的 dict_proxy,其键是给定类/对象的方法,但没有 init 的迹象元素。猜猜为什么? 双下划线变量__str____method__ 通常用于语言本身。当你str(something) 时会发生什么?【参考方案3】:

你通常不能只给一个类就获得实例属性,至少在没有实例化类的情况下是这样。但是,您可以获得给定实例的实例属性,或给定类的类属性。请参阅“检查”模块。您无法获得实例属性列表,因为实例实际上可以具有任何属性,并且 - 就像在您的示例中一样 - 创建它们的正常方法是在 __init__ 方法中分配给它们。

如果您的类使用插槽是一个例外,插槽是类允许实例具有的固定属性列表。插槽在http://www.python.org/2.2.3/descrintro.html 中有说明,但是插槽存在各种陷阱;它们会影响内存布局,因此多重继承可能会出现问题,而且继承通常也必须考虑插槽。

【讨论】:

投反对票,因为“你无法获得实例属性列表”是完全错误的:vars() 和 dict 都给了你。 我认为他的意思是“您无法获得所有可能的实例属性的列表”。例如,我经常使用惰性生成和@property 装饰器在第一次请求实例变量时添加它。使用 dict 会告诉你这个变量一旦存在而不是事先。 我没有投反对票,请注意我实际上所说的:仅给定一个类,您无法获得实例属性列表,这就是随附的代码这个问题试图做。 @Carl:在编写虚假的 cmets 和基于您缺乏知识的情况下投反对票之前,请先教育自己。【参考方案4】:

您还可以通过以下方式测试对象是否具有特定变量:

>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")

【讨论】:

【参考方案5】:

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

【讨论】:

exec('print object.%s\n\n') % i 应该写成print getattr(object, i)【参考方案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"

类变量由类的所有实例共享。

【讨论】:

【参考方案7】:

建议

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

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

换句话说,它本质上只是包装了 __dict__

【讨论】:

【参考方案8】:

虽然不是直接回答 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'

【讨论】:

【参考方案9】:

建立在 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

【讨论】:

【参考方案10】:

有时您想根据公共/私有变量过滤列表。例如

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('_')]

【讨论】:

【参考方案11】:

您需要首先,检查类,接下来,检查函数的字节码,然后,复制字节码,最后, 使用__code__.co_varnames这很棘手,因为有些类使用types 模块中的构造函数来创建它们的方法。我将在GitHub 上提供代码。

【讨论】:

以上是关于如何在 Python 中获取实例变量?的主要内容,如果未能解决你的问题,请参考以下文章

如何在python中记住其他程序实例变量[关闭]

如何优雅地检查对象/实例/变量的存在,如果它存在于python中,同时将其分配给变量?

如何修改模块中的变量和实例并在运行时在python中保存

类变量实例变量--python

如何判断 Swift 中实例变量的类是啥

python类实例变量和类变量