лучший способ распространения аргументов ключевых слов? - PullRequest
0 голосов
/ 12 ноября 2018

Какой утвержденный шаблон программирования для распределения аргументов ключевых слов среди вызываемых функций?

Рассмотрим этот надуманный (и ошибочный) пример:

def create_box(**kwargs):
    box = Box()
    set_size(box, **kwargs)
    set_appearance(box, **kwargs)

def set_size(box, width=1, height=1, length=1):
    ...

def set_appearance(box, material='cardboard', color='brown'):
    ...

Очевидно, что метод set_size() будет возражать против полученияmaterial или color аргументы ключевых слов, так же как set_appearance() будет возражать против получения width, height или length аргументов.

Есть действительный аргумент, что create_box() должен сделать все ключевое слово и значения по умолчанию явными, но очевидная реализация довольно громоздка:

def create_box(width=1, height=1, length=1, material='cardboard', color='brown'):
    box = Box()
    set_size(box, width=width, height=height, length=length)
    set_appearance(box, material=material, color=color)

Есть ли более Pythonic способ приблизиться к этому

Ответы [ 3 ]

0 голосов
/ 12 ноября 2018

Хм, лично я передал бы объект, содержащий все необходимые мне параметры. Таким образом, вы пропускаете только один параметр.

Пример:

class BoxDefinition:
    def __init__(self, width=1, height=1, length=1, material='cardboard', color='brown'):
        self.width = width 
        self.height = height
        # and so on for the rest of the params ...

Внутри каждого метода вы можете прочитать из этого объекта:

def create_box(box_definition):
    box = Box()
    set_size(box, box_definition)
    set_appearance(box, box_definition)

def set_size(box, box_definition):
    width = box_definition.width

def set_appearance(box, box_definition):
    color = box_definition.color

Тогда вы можете назвать это так:

definition = BoxDefinition(width=2, height=3, length=4)
create_box(definition)

На самом деле, вы даже можете сделать BoxDefinition и атрибут класса Box, и тогда единственное, что вам нужно будет передать - это Box.

0 голосов
/ 12 ноября 2018

Предполагая, что вы не можете изменить set_size или set_appearance, вы можете фильтровать kwargs в зависимости от ожидаемых аргументов keword, но я не уверен, что это самый питонический способ ...

import inspect

def create_box(**kwargs):
    box = None
    set_size_args = inspect.getargspec(set_size).args
    set_size(box, {k:v for k,v in kwargs.items() if k in set_size_args})
    set_appearance_args = inspect.getargspec(set_appearance).args
    set_appearance(box, {k:v for k,v in kwargs.items() if k in set_appearance_args})


def set_size(box, width=1, height=1, length=1):
    pass

def set_appearance(box, material='cardboard', color='brown'):
    pass

create_box(width=1, height=1, length=1, material='', color='')

(используйте inspect.signature() для Python 3)

0 голосов
/ 12 ноября 2018

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

def create_box(**kwargs):
    box = Box()
    set_size(box, **kwargs)
    set_appearance(box, **kwargs)

def set_size(box, width=1, height=1, length=1, **kwargs):
    ...

def set_appearance(box, material='cardboard', color='brown', **kwargs):
    ...
...