Olaf Olaf - 4 months ago 6x
Python Question

Python property factory or descriptor class for wrapping an external library

I am writing a Python wrapper class for a C# API accessed through Pythonnet.
As I want to extend the API with my own methods I decided to wrap it using the composition approach outlined here:

The C# API makes heavy use of properties which I want to mimic in my Python code. The following minimal example shows my current approach for the example of the C# Surface class with the two properties width and height:

class MySurface:
def __init__(api_surface):
self.api_surface = api_surface

def width(self):
return self.api_surface.width

def width(self, value):
self.api_surface.width = value

def height(self):
return self.api_surface.height

def height(self, value):
self.api_surface.height = value

In total, I have to deal with about 50 properties. For several groups of properties I want to add my own error checks, type conversions, etc.
What I am looking for is a Pythonic way of defining the properties, e.g. through a factory or using descriptors. Thanks for your help!

Edit: I want to be able to use tab completion within a python shell, i.e. surface. {hit tab} should propose surface.width and surface.height. This does not seem to be possible with the getattr approach outlined by Greg.


I was able to solve the issue using the following property factory:

def surface_property(api_property_name, docstring=None):
    def getter(self):
        return self.api_surface.__getattribute__(api_property_name)

    def setter(self, value):
        self.api_surface.__setattr__(api_property_name, value)

    return property(getter, setter, doc=docstring)

With this function the class definition reduces to:

class MySurface:
    def __init__(api_surface):
        self.api_surface = api_surface

    width = surface_property('Width','Get and set the width.')
    height = surface_property('height', 'Get and set the height.')