Структурирование программы.Классы и функции в Python

StackOverflow https://stackoverflow.com/questions/1561282

  •  21-09-2019
  •  | 
  •  

Вопрос

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

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

В параллельном 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)
Это было полезно?

Решение

Если вы хотите, чтобы все экземпляры 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 аргумент заключается в также другой пример, который демонстрируется выше.

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

защита от основной функции():если не имеет hasattr(mainfunc, "ks"):setattr(mainfunc, "ks", KeySeq()) ключ = mainfunc.ks.next()

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

Другие советы

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

#imports, utilities, other functions

def main(arg):
    #...

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top