2014-01-16 2 views
0

Я хотел бы внести изменения с именованными переменными в отношении порядка появления.Обработка аргументов для предварительной обработки в Python, когда вопросы порядка

Я хочу иметь конвейер для редактирования изображений, для которых имеет значение то, какие методы я применяю в первую очередь. Вместо того, чтобы вызывать функции отдельно, я все равно хотел бы использовать функцию обертки.

т.д .:

def preprocess(cutoff=None, resize=None, blur=None): 
    .... 

Теперь, если я вызываю функцию как preprocess(resize=(100, 100), cutoff=55), я хотел бы, чтобы первый resize, а затем сделать отрезана, хотя наоборот, когда preprocess(cutoff=55, resize=(100,100)).

Каков наилучший способ для этого?

+0

Почему вы хотите, чтобы это была единственная функция?Это похоже на контр-интуитивный дизайн, и если бы мы знали причины этого, я бы пообещал, что кто-то может придумать лучший дизайн, который бы разрешил те же проблемы. – abarnert

+0

Основная причина в том, что я знаю, что в основном будет поведение по умолчанию, но теперь я узнаю, что, возможно, в некоторых случаях я хотел бы снова переключить порядок. Таким образом, все еще можно кратко называть его как 'preprocess (5, (10,10))', но все же цикл не является полностью детерминированным, и многие длинные имена функций теперь не нужны. – PascalVKooten

+0

Что касается метода 'resize', метода' cutoff', метода 'blur', а затем метода' preprocess', который существует только для (очень распространенного) случая, когда вам нужно от 1 до 3 из них в большинстве общий порядок? Итак, обычно вы просто вызываете 'preprocess (5, (10,10))', но если вы хотите сделать что-то назад, вы будете изменять размер (10, 10) .cutoff (5) '? – abarnert

ответ

2

Вы не можете использовать аргументы ключевого слова для этого. Если вы принимаете их с помощью обычных параметров, как вы пробовали, единственным порядком является порядок параметров. Если вы принимаете их через **kwargs, вы получаете dict (у которого нет порядка).

Если вы хотите знать порядок аргументов, они должны быть позиционными аргументами; это действительно не так.

Однако для этого может быть лучше. Например, почему бы не просто сделать их отдельными методами? Затем, вместо этого:

newfoo = foo.preprocess(resize=(100, 100), cutoff=55) 

... вы это делаете:

newfoo = foo.resize(100, 100).cutoff(55) 

Или предоставляют простые типы, которые не делают ничего, кроме завернуть аргументы:

newfoo = foo.preprocess(Resize(100, 100), Cutoff(55)) 

Тогда вам может иметь preprocess принять свои аргументы *args и отправить на основе type(arg).


И если вы посмотрите на то, как вы бы осуществить это, он указывает на другую возможность:

class DumbArgWrapper(object): 
    def __init__(self, *args): 
     self.args = args 

class Resize(DumbArgWrapper): pass 
class Cutoff(DumbArgWrapper): pass 
class Blur(DumbArgWrapper): pass 

class ImageProcessor(object): 
    def preprocess(self, *args): 
     for arg in args: 
      if isinstance(arg, Resize): 
       do_resize(*arg.args) 
      # etc. 

Если вы просто переместить do_resize код в Resize (другими словами, сделать это своего рода "ленивая функция" объект), это гораздо чище:

class SmartArgWrapper(object): 
    def __init__(self, *args): 
     self.args = args 

class Resize(SmartArgWrapper): 
    def __call__(self, target): 
     do_resize(target, *self.args) 
# etc. 

class ImageProcessor(object): 
    def preprocess(self, *args): 
     for arg in args: 
      arg(self) 

И, сделав это , вы можете просто создать простую оболочку, которая превращает любую функцию в SmartArtWrapper вместо того, чтобы создавать кучу подклассов.

А потом ...


Дело в том, есть много возможностей. Для того, кто знает, чего вы хотите и почему, должен быть один и только один очевидный способ сделать это ... но кому-то, кто понятия не имеет, чего вы хотите и почему, это не так.

+0

«Есть много других возможностей». Например, одна вещь, которая довольно популярна среди разработчиков сторонних библиотек во всех языках программирования, поддерживающих перегрузку операторов, заключается в объединении последовательных операций с использованием оператора '|'. Таким образом, в этом случае без функции 'preprocess' и напишите' foo | изменение размера (100 100) | отсечки (55) '. Это может привести к некоторым грязным интерфейсам, хотя, как я подозреваю, именно поэтому сторонние разработчики языка стремятся к нему с меньшей готовностью ;-) –

+0

@SteveJessop: Я бы не сказал, что он популярен во всех языках программирования, которые поддерживают перегрузку оператора " В частности, он не популярен и не идиоматичен в Python. (В С ++, с другой стороны ...) – abarnert

+0

«Популярное» может быть неправильным словом. Я просто хочу сказать, что кто-то всегда пытается это сделать, а не то, что люди делают это регулярно. Последнее, что я посмотрел, я нашел пару попыток для Python, и я не выглядел тяжело. Это не похоже на то, что каждый писатель библиотек в C++ имеет прямое значение для '' 'как оператора конвейера, большинство по-прежнему используют вызовы функций. Но уверен, что это намного более распространено в C++, чем в Python. –

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