程序结构:Python中的类和函数
我正在写一个程序,利用遗传技术来演变方程式。我想把一个叫做'mainfunc'的函数提交给Parallel Python的'submit'函数。这个'mainfunc'函数会调用Utility类里定义的两个或三个方法。这些方法会实例化其他类并调用各种方法。我觉得我想要的是把所有东西放在一个命名空间里。所以我在'mainfunc'函数里实例化了一些(也许应该是全部)类。我调用了Utility的方法'generate()'。如果我们跟着它的执行流程走,就会涉及到代码中的所有类和方法。
现在,这些方程式存储在一个树结构中。每次生成、变异或交叉繁殖一棵树时,树的节点需要被赋予一个新的键,以便可以通过树的字典属性来访问。'KeySeq'类就是用来生成这些键的。
在Parallel Python中,我打算把多个'mainfunc'的实例发送到PP的'submit'函数。每个实例都需要能够访问'KeySeq'。如果它们都能访问同一个'KeySeq'实例,那就太好了,这样返回的树上的节点就不会有相同的键,不过如果有必要的话,我也可以找到其他方法来解决这个问题。
所以,我的问题是关于如何把所有东西都放进'mainfunc'里。谢谢。
(编辑)如果我不把所有东西都放在'mainfunc'里,我就得试着通过在不同地方传递各种参数来告诉PP关于依赖函数的信息。我想避免这样做。
(晚些时候编辑)如果在'generate()'函数内部调用ks.next(),就会返回错误'NameError: global name 'ks' is not defined'。
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 个回答
我觉得你对Python中类的理解不太准确。也许你可以重新看看基础知识。这个链接会对你有帮助。
这样构建你的程序是没问题的。很多命令行工具也是这样设计的:
#imports, utilities, other functions
def main(arg):
#...
if __name__ == '__main__':
import sys
main(sys.argv[1])
这样你就可以通过导入来从其他模块调用main
函数,或者你也可以直接从命令行运行它。
如果你想让所有的 mainfunc
实例都使用同一个 KeySeq
对象,可以用一个小技巧,就是设置默认参数值:
def mainfunc(ks=KeySeq()):
key = ks.next()
只要你没有给 ks
传入一个值,所有调用 mainfunc
的地方都会使用在定义这个函数时创建的那个 KeySeq
实例。
这里面有个原因,如果你不知道的话:函数其实也是一种对象。它有一些属性,其中一个叫 func_defaults
,它是一个元组,里面包含了所有有默认值的参数的默认值。当你调用一个函数时,如果没有给某个有默认值的参数传值,函数就会从 func_defaults
中取出这个值。所以,当你调用 mainfunc
而没有给 ks
传值时,它就会从 func_defaults
元组中获取 KeySeq()
实例。对于这个 mainfunc
的实例来说,这个 KeySeq
实例总是相同的。
现在,你提到要把“多个 mainfunc
实例发送到 PP 的 submit
函数。”你真的指的是多个实例吗?如果是的话,我刚才说的机制就不适用了。
不过,创建多个函数实例其实是有点复杂的(而且你发的代码并没有做到这一点)。比如,这个函数每次被调用时都会返回一个新的 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(): if not hasattr(mainfunc, "ks"): setattr(mainfunc, "ks", KeySeq()) key = mainfunc.ks.next()
最后,有一点非常重要,而你发的代码没有提到:如果你要对共享数据进行并行处理,涉及到这些数据的代码需要实现锁定。看看 Parallel Python 文档中的 callback.py
示例,看看 Sum
类是如何使用锁定的,以及为什么要这样做。