【问题标题】:Python class instances introspectionPython 类实例自省
【发布时间】:2016-08-18 04:23:20
【问题描述】:

从内省的角度来看,有没有一种方法可以在不创建实例的情况下获取类实例变量。创建实例时很容易:

class Super:
    def __init__(self, name):
        self.name = name

class Sub(Super):
    pass

a = Super("Nice_Name")

print(a.__dict__.keys())

但我想在不创建实例的情况下获取该信息,只是为了反省。有办法吗?

【问题讨论】:

  • 问题是类实例在被赋值之前根本没有任何属性;班级没有“宣布”他们。 __init__ 只是将值分配给在首次创建实例后动态创建的属性。本质上,您要求模拟__init__ 的执行。
  • 更多,所以__init__ 函数甚至可能不会创建一组确定性的属性。它可能取决于参数、全局状态,甚至是诸如setattr(self, str(random.random()), "derp") 这样荒谬的东西
  • 好的,但可以说我是否会尝试使用 Sub 类并且不为其分配任何值。它会给我错误。正如 Sub“知道”它需要“名称”。超级类也是如此。因此,这意味着以某种方式存在该信息。因此,如果子类知道在哪里查找实例变量。我不能那样做吗?我希望我不会在这里混合一些东西,因为我对 Python 还是很陌生。
  • @Vy.Iv:参数与实例变量无关。它们只是函数的参数。可以随心所欲地为所欲为。

标签: python oop instance introspection


【解决方案1】:

不,你不能,因为python不是statically typed language,所以在一个对象被实例化之前,那个对象是没有类型的。例如,想象这样一个类:

class A:
def __init__(self):
    self.a = "a"

def change_type(self):
    self.a = 1

在实例化对象之前self.a 的类型是什么?如果你需要自省,你不能使用 python。

【讨论】:

  • 仅仅是因为这不是一个答案或者是一个仅链接的答案。将此作为评论。看看其他人对这个问题的看法:他们更长,更有建设性。 SO规则,对不起
  • @Apero 我不同意。他的问题完全被这个回答了,链接是为了澄清静态类型语言是什么,并且它本身并没有回答他的问题。
  • 确实,所以这应该是评论,而不是答案;-)
  • @Apero 我说的是链接,而不是答案。
【解决方案2】:

我一直在对此进行一些研究,似乎有一些场景您可以这样做,但没有完美的解决方案:

  1. 如果你使用@property装饰器定义实例变量,那么它会在做dir(class_type)时出现
  2. 同样,您可以使用__slots__ 魔术变量定义允许的实例属性列表,然后只需执行class_type.__slots__ 即可获取您的实例变量。
  3. 有点 hacky,但你可以阅读该类的源代码,然后查找对 self.varname = expression 的任何引用。这当然假设self 将始终是类实例的引用方式,并且在内部类或self 被重新分配给另一个varname 等情况下会失败。也不会选择像 setattr(self, varname, expression) 这样的东西,你需要其他逻辑来检测。
  4. 可能比选项#3 更健壮,您可以使用ast 模块并使用它来解析类源代码。然后进行一些搜索以查找可能会将属性写入类 self 的表达式。

看看这个例子:

import dill, re

class Test:
    __slots__ = ["x","y","z"]
    def __init__(self):
        self.x = 0
        self.y = 1
        self.z = 2
    @property
    def q(self):
        return self.x

# this grabs those defined using __slots__ or @property
print(dir(Test))

# this looks at class source
# may need to play around with the regex more...
s = dill.source.getsource(Test)
var_finder = re.compile("self\.([^\W]+)\s*\=")
print(set(var_finder.findall(s)))

我个人认为在课堂上添加__slots__ 是最好的方法。对于我的用例 sphinx 文档,这似乎是让 autosummary 指令获取这些实例变量的最佳方式。

【讨论】:

    猜你喜欢
    • 2013-06-10
    • 2013-05-09
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 2012-11-28
    • 2013-06-22
    • 1970-01-01
    相关资源
    最近更新 更多