Структурирование программы.Классы и функции в Python
-
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 не совсем верна.Возможно, было бы хорошей идеей ознакомиться с основами.Эта ссылка поможет.