2017-02-10 7 views
0

Я пытаюсь запустить симуляцию в Python. Для этого мне нужно определить ряд параметров и получить от них некоторые другие. Используя их, я вызываю несколько функций, которые действуют на эти параметры и возвращают определенный результат. В настоящее время мой код выглядит примерно такpythonic way для функции с множеством параметров и возвращаемыми значениями

common(ai, bi, ..., hi): 
    # calculations 
    return ao, bo, ..., fo 
func1(ai, bi, ..., xi): 
    ao, bo, ..., fo = common(ai, bi, ..., hi) 
    # calculations specific to func1 
    return y 
func1(ai, bi, ..., xi): 
    ao, bo, ..., fo = common(ai, bi, ..., hi) 
    # calculations specific to func2 
    return z 

ai = 0 
bi = 1 
... 
xi = 2 

print(func1(ai, bi, ..., xi)) 
print(func2(ai, bi, ..., xi)) 

где я сокращенном список параметров т.д., с ... и расчеты выполняются в # calculations разделах.

Я бы предпочел назвать функции с помощью func1(di=2) и иметь значение по умолчанию для всех остальных. Это, однако, означает использование именованных аргументов, и в этом случае я должен дважды указывать значения по умолчанию (в func1 и в func2). Я не думаю, что **kwargs будет работать здесь, так как это потребует передачи значений по умолчанию явно.

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

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

Мой вопрос в том, есть ли пифонический способ решить эту проблему.

+1

Вы пробовали с абстрактными классами? – AreTor

ответ

1

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

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

Было бы неплохо использовать наследование декоратора или класса.

Decorator позволяет определить фабричный метод, который возвращает такие функции, как func1 или func2. Интерфейс определяется только один раз, используя аргументы по умолчанию в декораторе, возвращаемые функции различаются в методах процесса или основных методах.

Class Наследование работает аналогичным образом, но через наследование метода оно более гибкое и общее.

+1

Я закончил тем, что поместил общий код в функцию декоратора и выписал конкретный код. Параметры устанавливаются с помощью '** kwargs' для декоратора, который по умолчанию имеет значение, если аргумент не указан. Это почти решает все мои проблемы, за исключением того, что как 'func1', так и' func2' явно снабжены списком аргументов. Таким образом, я могу держать мои уравнения доступными для чтения. Я понимаю, что это может быть не очень хорошая практика кодирования, но для меня использование python - это сокращение времени разработки и переход к реальной работе. Для меня, чем средство читаемых уравнений. – Octaviour

+0

На самом деле, это довольно общий шаблон проектирования в большинстве объектно-ориентированных программ. Вы будете в этом довольны. –

0

Вы можете сделать класс для хранения ВАРА в его свойствах:

class SimClass(object): 

    def __init__(self, **kw): 
     self.ao = kw.get('aa', VA_DEFAULT) 
     self.bo = kw.get('bb', VB_DEFAULT) 
     # ... 
     self.zo = kw.get('zz', VZ_DEFAULT) 

    def common(self, ai, bi, ..., hi): 
     # calculations set self.ao, self.bo, ..., self.fo 
     return 

    def func1(self, ai, bi, ..., xi): 
     self.common(ai, bi, ..., hi) 
     # calculations specific to func1 using self.ao, self.bo, ..., self.fo 
     return y 

    def func1(self, ai, bi, ..., xi): 
     common(ai, bi, ..., hi) 
     # calculations specific to func2 using self.ao, self.bo, ..., self.fo 
     return z 

ai = 0 
bi = 1 
... 
xi = 2 

sim = SimClass(bb='BB', cc='CC') 

print(sim.func1(ai, bi, ..., xi)) 
print(sim.func2(ai, bi, ..., xi)) 
0

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

z = sqrt((x2 - x1)^2 + (y2 - y1)^2),

, который легко читать, только если переменные имеют короткие имена. Понятно, что вы хотите сохранить это. Но языки программирования могут работать не так, они используют собственный синтаксис и инструменты.

Одним из важных принципов рефакторинга в программировании является уменьшение количества переданных параметров в функциях.Самый простой способ, чтобы инкапсулировать все переданные параметры в одном объекте, и передать только то, что объект между функциями:

import math 

class Line: 
    def __init__(self, x1, x2, y1, y2): 
     self.x1 = x1 
     self.x2 = x2 
     self.y1 = y1 
     self.y2 = y2 

def getLineLength(line):   
    return math.sqrt((line.x2 - line.x1)**2 + (line.y2 - line.y1)**2) 

line = Line(3, 5, -2, 7) 
print(getLineLength(line)) 

Конечно, вы должны использовать имя объекта, а исходное уравнение становится менее читабельным. И код Python не должен выглядеть точно как математическая формула. Но вместо этого теперь вы можете повторно использовать новый класс Line в других частях кода.

Если функция достаточно сложна, чтобы увидеть, что он делает, он может быть дополнительно переработан:

def getLineLength(line): 
    dx = line.x2 - line.x1 
    dy = line.y2 - line.y1  
    return math.sqrt(dx**2 + dy**2) 

Эта функция может перемещается внутри Line класса:

class Line: 
... 

def getLength(self): 
    dx = self.x2 - self.x1 
    dy = self.y2 - self.y1  
    return math.sqrt(dx**2 + dy**2) 

line = Line(3, 5, -2, 7) 
print(line.getLength()) 

... и даже реформатор далее:

import math 

class Point: 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

    def __sub__(self, other): 
     return Point(other.x - self.x, other.y - self.y) 

class Line: 
    def __init__(self, x1, x2, y1, y2): 
     self.start = Point(x1, y1) 
     self.end = Point(x2, y2) 

    def getLength(self): 
     d = self.start - self.end 
     return math.sqrt(d.x**2 + d.y**2) 

line = Line(3, 5, -2, 7) 
print(line.getLength()) 

Новый класс Point можно повторно использовать в других местах.

Таким образом, код может быть чистым, простым и пригодным для повторного использования. Повторное использование становится очень важным, так как сценарий растет.

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

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