1

我目前正在移植一个相当大的 Perl 问题是它使用小的 Perl 技巧来使其代码可用于useing。我对 Python 做了同样的事情,使代码库成为一个大模块import。我已经牢牢掌握 Python 很长时间了,但是我没有使用 Python 编写的大型项目的经验,这些项目需要在保持内部状态的同时访问自身的其他部分。

我还没有尝试将整个内容简单地导入一行 ( import core),但我知道我目前没有以最好的方式做事。这是主脚本中的一个示例,它设置了所有内容:

self.Benchmark = Benchmark(self)

self.Exceptions = Exceptions

self.Settings = Settings(self)
self.Cache = Cache(self)

self.Deal = Deal(self)
self.Utils = Utils(self)
self.FileParsers = FileParsers(self)
self.Network = Network(self)
self.Plugins = Plugins(self)
self.Misc = Misc(self)

有效,但我对此不满意。现在,主类脚本导入core模块的每个部分并创建包含的类的实例,将自身作为参数传递给__init__这些类。像这样:

class FileParsers:
    def __init__(self, parent):
        self.parent = parent

现在该类中的代码可以通过父类访问整个代码库的其余部分。

self.parent.Settings.loadSysConfig()

所以我的问题是:考虑到上述情况,重组项目和重构代码以保持其当前访问其他所有内容的能力的最佳方式是什么?代码非常不重要,所以我并不担心内部数据的完整性,我只是不喜欢以如此丑陋的方式遍历父类。那些长链也会减慢代码的速度。

编辑:哎呀,忘记了这些:两个项目的 SVN 存储库的链接。我的在这里,我正在移植的项目在这里

4

2 回答 2

1

如果没有真正能够看到代码,真的很难判断,但您可能应该考虑在该模块中导入每个模块使用的项目。有很长的进口清单并不罕见 - 这是我自己网站上的一个例子:

# standard
import inspect
import linecache
import neo_cgi
import neo_cs
import neo_util
import os
import random
import sys
import time
from _apache import SERVER_RETURN
from mod_python import apache
from mod_python import util
from mod_python.util import FieldStorage
from os.path import dirname, isfile, join, splitext

# set up path
pydir = dirname(__file__)
if pydir not in sys.path:
    sys.path.append(pydir)

# things I wrote
import auth
import handlers.accounts, handlers.publish, handlers.standard
import logger
import markup
import programs
import summarize
from auth import check_auth
from common import hdf_iterate, load_hdf_cgi_vars, load_hdf_common_vars
from common import hdf_insert_value, hdf_insert_list, hdf_insert_dict
from handlers import chain, farm, opt
from handlers import URIPrefixFilter
from handlers.standard import TabBarHandler

而且我敢肯定很多更大的模块有更长的列表。

在您的情况下,可能有一个Settings带有单例对象的模块(或将设置作为模块属性)并执行

import Settings

管他呢。

于 2009-04-11T01:23:40.797 回答
0

重组项目和重构代码以保持其当前访问其他所有内容的能力的最佳方式是什么?

我认为你实际上已经很接近了,并且可能比许多 Python 项目更好,他们只是假设只有一个应用程序实例,并将应用程序特定的值存储在模块全局或单例中。

(这对于许多简单的应用程序来说是可以的,但实际上最好能够将所有内容捆绑到一个 Application 对象中,该对象拥有所有需要了解应用程序状态的内部类和方法。)

从上面的代码来看,我要做的第一件事是剔除那些不是应用程序核心能力的模块和类,这些东西不一定需要访问应用程序的状态。像“Utils”和“Misc”这样的名字听起来很可疑,因为它们的大部分内容并不是你的应用程序所特有的;它们也许可以重构为单独的独立模块,或者包的子模块,它们只有静态函数,不依赖于应用程序状态的东西。

接下来,我会将主要所有者 Application 类放在包的 __init__.py 中,而不是“主脚本”中。然后从您的运行脚本或解释器中,您可以获得应用程序的完整实例,如下所示:

import myapplication

a= myapplication.Application()

您还可以考虑将任何基本部署设置从 Settings 类移动到初始化程序中:

a= myapplication.Application(basedir= '/opt/myapp', site= 'www.example.com', debug= False)

(如果您只有一组可能的设置,并且每次实例化 Application() 时都会得到相同的设置,那么拥有所有这些能力来封装整个应用程序几乎没有用处;您还不如简单地使用模块全局变量。)

我对我的一些应用程序所做的是将拥有的类猴子修补成所有者应用程序对象的实际成员:

# myapplication/__init__.py

class Application(object):
    def __init__(self, dbfactory, debug):
        # ...
        self.mailer= self.Mailer(self)
        self.webservice= self.Webservice(self)
        # ...

import myapplication.mailer, myapplication.webservice


# myapplication/mailer.py

import myapplication

class Mailer(object):
    def __init__(self, owner):
        self.owner= owner

    def send(self, message, recipients):
        # ...

myapplication.Application.Mailer= Mailer

然后可以通过替换/子类化内部类从外部扩展、更改或配置应用程序:

import myapplication

class MockApplication(myapplication.Application):
    class Mailer(myapplication.Application.Mailer):
        def send(self, message, recipients):
            self.owner.log('Mail send called (not actually sent)')
            return True

我并不担心内部数据完整性

好吧,不,这是 Python 而不是 Java:我们不用太担心邪恶的程序员使用他们不应该使用的属性和方法,我们只是在名称的开头加上“_”,让它成为对所有人的适当警告。

那些长链也会减慢代码的速度。

不是很明显。可读性是重要因素;其他任何事情都是过早的优化。

于 2009-04-11T15:35:41.497 回答