Структурирование программы. Классы и функции в Python - PullRequest
3 голосов
/ 13 октября 2009

Я пишу программу, которая использует генетические методы для разработки уравнений. Я хочу иметь возможность отправить функцию 'mainfunc' в функцию 'submit' в Parallel Python. Функция mainfunc вызывает два или три метода, определенных в классе Utility. Они создают другие классы и вызывают различные методы. Я думаю, что я хочу все это в одном NAMESPACE. Поэтому я создал несколько (может быть, все) классов внутри функции 'mainfunc'. Я называю метод Utility «generate ()». Если бы мы следовали, это цепь исполнения это будет включать в себя все классы и методы в коде.

Теперь уравнения хранятся в дереве. Каждый раз, когда дерево генерируется, видоизменяется или пересекается Кроме того, узлам необходимо дать новый ключ, чтобы к ним можно было получить доступ из словарного атрибута дерева. Класс KeySeq генерирует эти ключи.

В Parallel Python я собираюсь отправить несколько экземпляров mainfunc в функцию submit в PP. Каждый должен иметь доступ к «KeySeq». Было бы хорошо, если бы все они обращались к одному и тому же экземпляру KeySeq, чтобы ни один из узлов в возвращенных деревьях не имел одинаковый ключ, но я мог бы обойти это в случае необходимости.

Итак: мой вопрос о вставке ВСЕХ в mainfunc. Спасибо (Правка) Если я не включаю все в mainfunc, я должен попытаться рассказать PP о зависимых функциях и т. Д., Передавая различные аргументы в разных местах. Я пытаюсь избежать этого.

(позднее редактирование), если ks.next () вызывается внутри функции «generate ()», она возвращает ошибку «NameError: глобальное имя« ks »не определено»

class KeySeq:
    "Iterator to produce sequential \
    integers for keys in dict"
    def __init__(self, data = 0):
        self.data = data
    def __iter__(self):
        return self
    def next(self):
        self.data = self.data + 1
        return self.data
class One:
    'some code'
class Two:
    'some code'
class Three:
    'some code'
class Utilities:
    def generate(x):
        '___________'
    def obfiscate(y):
        '___________'
    def ruminate(z):
        '__________'


def mainfunc(z):
    ks = KeySeq()
    one = One()
    two = Two()
    three = Three()
    utilities = Utilities()
    list_of_interest = utilities.generate(5)
    return list_of_interest

result = mainfunc(params)

Ответы [ 3 ]

3 голосов
/ 13 октября 2009

Хорошо структурировать вашу программу таким образом. Многие утилиты командной строки следуют той же схеме:

#imports, utilities, other functions

def main(arg):
    #...

if __name__ == '__main__':
    import sys
    main(sys.argv[1])

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

1 голос
/ 14 октября 2009

Если вы хотите, чтобы все экземпляры mainfunc использовали один и тот же объект KeySeq, вы можете использовать трюк со значением параметра по умолчанию:

def mainfunc(ks=KeySeq()):
   key = ks.next()

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

Вот почему, если вы не знаете: функция - это объект. У него есть атрибуты. Один из его атрибутов называется func_defaults; это кортеж, содержащий значения по умолчанию всех аргументов в его сигнатуре, которые имеют значения по умолчанию. Когда вы вызываете функцию и не предоставляете значение для аргумента, который имеет значение по умолчанию, функция извлекает значение из func_defaults. Поэтому, когда вы вызываете mainfunc без указания значения для ks, он получает экземпляр KeySeq() из кортежа func_defaults. Который, для этого экземпляра mainfunc, всегда один и тот же KeySeq экземпляр.

Теперь вы говорите, что собираетесь отправить «несколько экземпляров mainfunc в submit функцию PP». Вы действительно имеете в виду несколько экземпляров? Если так, то механизм, который я описываю, не будет работать.

Но сложно создать несколько экземпляров функции (а код, который вы опубликовали, - нет). Например, эта функция возвращает новый экземпляр g каждый раз, когда она вызывается:

>>> def f():
        def g(x=[]):
            return x
        return g
>>> g1 = f()
>>> g2 = f()
>>> g1().append('a')
>>> g2().append('b')
>>> g1()
['a']
>>> g2()
['b']

Если я вызываю g() без аргумента, он возвращает значение по умолчанию (изначально пустой список) из своего кортежа func_defaults. Поскольку g1 и g2 являются разными экземплярами функции g, их значение по умолчанию для аргумента x равно , а также другому экземпляру, который демонстрируется выше.

Если вы хотите сделать это более явным, чем использовать хитрый побочный эффект значений по умолчанию, вот еще один способ сделать это:

def mainfunc (): если не hasattr (mainfunc, "ks"): setattr (mainfunc, "ks", KeySeq ()) key = mainfunc.ks.next ()

Наконец, очень важный момент, который пропускает код, который вы разместили: если вы собираетесь выполнять параллельную обработку совместно используемых данных, код, который касается этих данных, должен реализовать блокировку. Посмотрите на пример callback.py в документации по Parallel Python и посмотрите, как блокировка используется в классе Sum и почему.

0 голосов
/ 16 октября 2009

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

Основы Python - Классы

...