2016-04-12 7 views
3

Я пишу класс оболочки Python для C# API, доступ к которому осуществляется через Pythonnet. Как я хочу, чтобы расширить API со своими собственными методами я решил обернуть его с помощью композиции подхода, изложенного here:Python property factory или класс дескриптора для обертывания внешней библиотеки

C# API делает интенсивное использование свойств, которые я хочу, чтобы имитировать в моем коде Python. Следующий минимальный пример показывает мой нынешний подход к примеру класса # Surface C с двумя свойствами ширина и высота:

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 

В целом, мне приходится иметь дело с около 50 свойств. Для нескольких групп свойств я хочу добавить свои собственные проверки ошибок, тип конверсий и т. Д. То, что я ищу, - это метод Pythonic для определения свойств, например. через фабрику или с использованием дескрипторов. Спасибо за вашу помощь!

Редактировать: Я хочу иметь возможность использовать вкладку в оболочке python, то есть на поверхности. {hit tab} должен предлагать surface.width и surface.height. Это не представляется возможным с помощью подхода getattr, изложенного Грегом.

ответ

3

Я был в состоянии решить эту проблему с помощью следующего свойства фабрики:

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) 

С помощью этой функции определения класса сводится к:

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

Это действительно хороший пример альтернативного шаблона композиции в Python (вместо использования '__getattr__' и' __setattr__' для делегирования поиска атрибутов члену). –

1

Вы можете использовать getattr и setattr, если хотите избежать всего ручного кодирования. Этот ответ будет работать для python2 btw.

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

я уже экспериментировал с подобным подходом. Одна из моих основных целей - иметь соответствующее завершение кода (завершение табуляции) при использовании обернутого класса в интерактивном сеансе Python. Это, похоже, не работает с намеченным подходом, когда пользователь должен заранее знать имя участника. – Olaf

+0

должен, вероятно, включить это в ваш вопрос. Я не могу придумать гораздо больше, что вы можете сделать, кроме того, что вручную определяете все свои свойства, иначе – Greg

 Смежные вопросы

  • Нет связанных вопросов^_^