简体   繁体   中英

Python class instances introspection

From the introspection perspective is there a way to get a class instances variables without creating an instance. When an instance is created it is easy:

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

class Sub(Super):
    pass

a = Super("Nice_Name")

print(a.__dict__.keys())

But I want to get that information without creating an instance, just to introspect. Is there way to do?

No, you cannot, because python is not a statically typed language , so before an object is instantiated, that object has no type. For example, imagine a class like this:

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

def change_type(self):
    self.a = 1

What would the type of self.a be before an object is instantiated? If you need introspection, you cannot use python.

I've been doing some research into this and there appear to be a few scenarios where you can do this, however no perfect solution:

  1. If you define instance variables using @property decorators, then it will show up when doing dir(class_type)
  2. Similarly, you can define the allowed list of instance attributes using __slots__ magic var, and then just do class_type.__slots__ to get your instance vars.
  3. A bit more hacky, but you can read the source code of the class, and then look for any references to self.varname = expression . This of course assumes self will is always how the class instance is referenced, and would fail in scenarios like inner classes or self being reassigned to another varname. Also wouldn't pick up things like setattr(self, varname, expression) , which you'd need other logic to detect.
  4. Probably more robust than option #3, you could use the ast module and use that to parse the class source code. Then do some searching to find expressions that might write attributes to the class self .

Check out this example:

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)))

I personally think adding __slots__ on your class is the best approach. For sphinx documentation, which was my use case, that seems to be the best way to get autosummary directive to pick up those instance variables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM