Skip to content

pydump support Python defined class #45

Description

@toaction

Python-Defined Classes

For Python-defined classes, the following symbol information is included:

  • Class name and inheritance relationships
  • Instance methods, magic methods, class methods, static methods
  • Instance properties (property), class attributes

Python demo:

class Animal:
    def __init__(self, name):
        self._name = name

    def speak(self):
        pass

class Dog(Animal):

    DOG_NAME = "Dog"

    def __init__(self, name, age):
        super().__init__(name)
        self._age = age

    def speak(self):
        print(f"Dog {self._name} is speaking")

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    @classmethod
    def bark(cls, msg):
        print(f"Dog is barking {msg}")

    @staticmethod
    def sleep():
        print("Dog is sleeping")

    def __str__(self):
        return f"Dog {self._name} is {self._age}

Symbol Information Extraction

Class Symbol Extraction

Extraction rules: Extract symbol information while minimizing hardcoded implementations.

Extract the following symbol information from Python-defined classes:

// Python class
type Class struct {
	Name            string      `json:"name"`
	Doc             string      `json:"doc"`
	Bases           []*Base     `json:"base"`
	InitMethod      *Symbol     `json:"initMethod"`
	InstanceMethods []*Symbol   `json:"instanceMethods"` // include override special methods
	ClassMethods    []*Symbol   `json:"classMethods"`
	StaticMethods   []*Symbol   `json:"staticMethods"`
	Properties      []*Property `json:"properties"`
	// TODO: attributes
}

How to determine if a Python object is a class? Use reflection:

inspect.isclass(obj)

Inheritance Relationships

Use __bases__ to get the direct parent classes of a class:

class B(A):
    pass

for base in B.__bases__:
    print(base.__name__)

Use inspect.getmro() to get the complete inheritance chain (in method resolution order):

print(inspect.getmro(B))
# (<class '__main__A'>)

Currently only consider getting direct parent classes:

// base class
type Base struct {
	Name   string `json:"name"`
	Module string `json:"module"`
}

Class Namespace

Directly accessing a class's __dict__ does not return a directly accessible dict object:

print(type(Dog.__dict__))
# <class 'mappingproxy'>

Convert using CPython API:

PyObject* dict = PyDict_Copy(proxy);

Instance Methods and Magic Methods

How to determine if a Python object in a class is an instance method or magic method? Use reflection:

inspect.isfunction(Dog.speak)

The difference between magic methods and instance methods is that magic method names have __ prefix and __ suffix:

def __str__(self):
    passs

Static Methods and Class Methods

How to determine if a Python object in a class is a static method or class method? Currently there is no good interface, only hardcoded approach:

if isinstance(Dog.sleep, staticmethod)

For methods decorated with @staticmethod and @classmethod, their __func__ is the actual underlying method:

func = Dog.speak.__func__

Property Attributes

Python classes typically use @property to decorate methods, providing users with interfaces to access and modify attributes. You can determine if getter and setter methods exist by checking if the property object has fget and fset attributes.

// @property
type Property struct {
	Name   string `json:"name"`
	Getter string `json:"getter"`
	Setter string `json:"setter"`
}

Currently there is no interface to directly determine if a Python object is a property, only hardcoded approach:

isinstance(Dog.age, property)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions