程序结构:Python中的类和函数

3 投票
3 回答
786 浏览
提问于 2025-04-15 15:02

我正在写一个程序,利用遗传技术来演变方程式。我想把一个叫做'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 个回答

0

我觉得你对Python中类的理解不太准确。也许你可以重新看看基础知识。这个链接会对你有帮助。

Python基础 - 类

3

这样构建你的程序是没问题的。很多命令行工具也是这样设计的:

#imports, utilities, other functions

def main(arg):
    #...

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

这样你就可以通过导入来从其他模块调用main函数,或者你也可以直接从命令行运行它。

1

如果你想让所有的 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 元组中返回默认值(最开始是一个空列表)。因为 g1g2 是不同的 g 函数实例,所以它们的 x 参数的默认值也是不同的实例,以上的例子就证明了这一点。

如果你想让这个过程更明确,而不是依赖默认值的巧妙副作用,这里有另一种方法:

def mainfunc(): if not hasattr(mainfunc, "ks"): setattr(mainfunc, "ks", KeySeq()) key = mainfunc.ks.next()

最后,有一点非常重要,而你发的代码没有提到:如果你要对共享数据进行并行处理,涉及到这些数据的代码需要实现锁定。看看 Parallel Python 文档中的 callback.py 示例,看看 Sum 类是如何使用锁定的,以及为什么要这样做。

撰写回答