如何在 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 中获取实例变量?的主要内容,如果未能解决你的问题,请参考以下文章