2016-04-12 21 views
3

Ich schreibe eine Python-Wrapper-Klasse für eine C# API, auf die über Pythonnet zugegriffen wird. Als ich die API mit meinen eigenen Methoden erweitern wollen habe ich beschlossen, es zu wickeln die Zusammensetzung Ansatz here umrissen:Python-Eigenschaft Factory oder Deskriptorklasse zum Umschließen einer externen Bibliothek

Die C# API starke Nutzung von Eigenschaften macht die ich in meinem Python-Code imitieren wollen. Das folgende Beispiel zeigt minimal meinen aktuellen Ansatz für das Beispiel der C# Oberflächenklasse mit den beiden Eigenschaften Breite und Höhe:

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

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

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

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

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

Insgesamt muß ich mit etwa 50 Eigenschaften beschäftigen. Für einige Gruppen von Eigenschaften möchte ich meine eigenen Fehlerprüfungen hinzufügen, Umwandlungen eingeben usw. Was ich suche, ist eine pythonische Art, die Eigenschaften zu definieren, z.B. durch eine Fabrik oder unter Verwendung von Deskriptoren. Danke für Ihre Hilfe!

Edit: Ich möchte Tab Komplettierung innerhalb einer Python-Shell, d. {Hit Tab} sollte Surface.width und Surface.height vorschlagen. Dies scheint mit dem von Greg umrissenen Ansatz getattr nicht möglich zu sein.

Antwort

3

konnte ich das Problem mit der folgenden Eigenschaft Fabrik lösen:

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) 

Mit dieser Funktion wird die Klassendefinition reduziert mich auf:

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.') 
+0

Dies ist ein wirklich gutes Beispiel für ein alternatives Kompositionsmuster in Python (anstatt '__getattr__' und' _setattr__' zu verwenden, um Attributsuchen an ein Mitglied zu delegieren). –

1

Sie können einfach getattr und setattr verwenden, wenn Sie die gesamte manuelle Codierung vermeiden möchten. Diese Antwort wird für python2 btw funktionieren.

class MySurface(object): 
    def __init__(self): 
     self.props = {"width": 0, "length": 0, ...} 

    def __setattr__(self, attr, val): 
     if attr in self.props: 
      self.props[attr] = val 
     else: 
      super(MySurface, self).__setattr__(attr, val) 

    def __getattr__(self, attr): 
     if attr in self.props: 
      return self.props[attr] 
     else: 
      return self.__getattribute__(attr) 
+0

ich bereits experimentiert mit einem ähnlichen Ansatz. Eines meiner Hauptziele ist es, bei der Verwendung der umschlossenen Klasse in einer interaktiven Python-Sitzung eine entsprechende Code-Vervollständigung (Tab-Vervollständigung) zu haben. Dies scheint nicht mit dem skizzierten Ansatz zu funktionieren, bei dem der Benutzer den Attributnamen im Voraus kennen muss. – Olaf

+0

sollte das wahrscheinlich in Ihrer Frage enthalten. Ich kann mir nicht viel mehr vorstellen, als manuell alle Ihre Eigenschaften zu definieren. – Greg