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

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

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

有没有办法让我这样做:

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

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

【问题讨论】:

  • 您的示例显示“实例变量”。类变量是另一回事。

标签: python methods instance-variables


【解决方案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 上提供代码。

              【讨论】:

                猜你喜欢
                • 2021-03-28
                • 1970-01-01
                • 2013-03-30
                • 2016-10-02
                • 1970-01-01
                • 1970-01-01
                • 2013-06-09
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多