在Python 3.5中,我说:
class Foo:
def __init__(self, bar, barbar):
self.bar = bar
self.barbar = barbar
我希望从课程中获取列表["bar", "barbar"]
。
我知道我能做到:
foo = Foo(1, 2)
foo.__dict__.keys()
有没有办法在没有实例化对象的情况下获取["bar", "barbar"]
?
答案 0 :(得分:26)
否,因为属性是动态的(所谓的实例属性)。请考虑以下内容,
class Foo:
def __init__( self ):
self.bar = 1
def twice( self ):
self.barbar = 2
f = Foo()
print( list(f.__dict__.keys() ) )
f.twice()
print( list(f.__dict__.keys() ) )
在第一次打印中,只设置了f.bar
,这是打印属性键时显示的唯一属性。但在致电f.twice()
后,您为f
创建新属性,现在打印它会显示bar
和barbar
。
答案 1 :(得分:10)
警告 -
以下并不总是提供100%正确的数据是万无一失的。如果您在self.y = int(1)
中最终得到__init__
这样的内容,则最终会在您的属性集合中包含int
,这不是您想要的目标结果。此外,如果您碰巧在代码中的某处添加了动态属性,例如Foo.some_attr = 'pork'
,那么您将永远不会看到它。请注意您正在检查代码的哪一点,并了解您的原因以及在结果中没有包含这些内容。可能还有其他"破损"这不会让你完全100%期望所有与类相关联的属性,但是,下面的内容应该为你提供的东西你可能正在寻找。
但是,我强烈建议您在此处获取其他答案的建议以及标记的副本,以解释您为什么不能/不应该这样做。
以下是您可以尝试解决的一种解决方案:
我将扩展inspect
答案。
但是,我在生产 -ready代码中做了类似的事情的问题(并且可能会建议反对)。出于调查目的,一定要把自己打倒。
通过使用其他一个答案中已指明的inspect模块,您可以使用getmembers方法,然后您可以迭代这些属性并检查您要调查的相应数据。
例如,您正在质疑__init__
因此,我们可以用这个例子来说明:
from inspect import getmembers
class Foo:
def __init__(self, x):
self.x = x
self.y = 1
self.z = 'chicken'
members = getmembers(Foo)
for member in members:
if '__init__' in member:
print(member[1].__code__.co_names)
您的输出将是一个元组:
('x', 'y', 'z')
最终,当您检查类Foo
以获取其成员时,您可以在迭代每个成员时进一步调查这些属性。每个成员都有进一步检查的属性,依此类推。对于此特定示例,我们专注于__init__
和检查 __code__
(每个文档:表示已编译函数体的__code__
对象)属性,该属性具有属性名为co_names
,它提供了如上所示的成员元组以及运行代码的输出。
答案 2 :(得分:-6)
正如Lærne所提到的,在函数内部声明的属性(如__init__
)是动态的。在调用__init__
函数之前,它们实际上不存在。
然而,有一种方法可以做你想要的。
您可以创建 class 属性,如下所示:
class Foo:
bar = None
barbar = None
def __init__(self, bar, barbar):
self.bar = bar
self.barbar = barbar
你可以访问这些属性:
[var for var in vars(Foo).keys() if not var.startswith('__')]
这给出了这个结果:
['bar', 'barbar']