从另外两个文件生成混合*.py文件

2024-09-27 22:20:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试编写一个python脚本,它可以将两个python文件合并成一个混合体,使用第二个文件中的方法重写第一个文件中的方法(这些方法可以是独立的,也可以存在于类中)。在

例如,假设我有原始.py公司名称:

from someclass import Class0

def fun1(a, b):
    print "fun1", a, b

def fun2(a):
    print "fun2", a

class Class1(Class0):
    def __init__(self, a):
        print "init", a

    def fun3(self, a, b):
        print "fun3", a, b

以及新建.py公司名称:

^{pr2}$

运行联合收割机('原始.py', '新建.py')我希望它生成一个如下所示的新文件:

import someclass

def fun1(a, b):
    print "fun1", a, b

def fun2(a, b):
    print "new fun2", a, b

class Class1:
    def __init__(self, a):
        print "init", a

    def fun3(self, a, b):
        print "new fun3"

我想弄清楚什么是最干净的方法。一开始我考虑使用regex,但是跟踪缩进量和我所在的当前级别(类中的方法会有一个级别的深度,但是如果一个文件在类中有类或者在其他方法中有方法,就像使用decorator时发生的那样)听起来像是等待发生的灾难。我还考虑使用tokenize模块来生成一个语法树,然后尝试导航到两个树中的同一个元素,用另一个树的一部分替换一个树的部分(这看起来很复杂,因为我看到的tokenize的所有使用都是为了修改单个python标记而不是整个方法)。你们有什么建议?这似乎是一项简单的任务,但我看不出一个干净利落的方法来完成它。在

另外,我不在乎第二个文件是完整的还是有效的(注意,尽管继承了类0,但缺少导入),尽管使第二个文件有效可以让我使用一些内部python技巧(比如修改python导入逻辑,使用来自不同文件的导入方法覆盖导入的方法,然后将导入的版本从内存转储到新文件中),那么我也可以接受。

编辑(关于我为什么要这样做而不是使用继承的更多解释):

我想我的问题需要更好地解释我为什么要这么做。我有几个团体/客户我提供我的源代码。功能需要根据客户需求而有所不同(在某些情况下,这只是一些简单的事情,比如像sarnold提到的那样调整参数文件;在其他情况下,用户要求的特性/挂钩与其他组无关,只会给UI增加更多的混乱)。另外,有些源代码是特定于客户的和/或专有的(因此,虽然我可以与某些组共享,但不允许与其他组共享),这正是我试图避免继承的原因。我想我仍然可以依赖普通继承,只要它是专有的子类版本,而不是原始版本,但是对于大多数特性,目前只有一个组没有特权(而且每个特性也不总是相同的组),而其他组有。因此,如果我要使用继承,我可能需要一堆目录/文件,比如“SecretFromA”、“SecretFromB”…、“SecretFromZ”,然后对于每个其他组,我需要为每个模块使用“from SecretFromZ import*”,而使用我描述的替换技术,我只需为要过滤的功能添加存根。这也是我将来经常用到的东西,所以现在写这个剧本会很痛苦,我觉得我以后可以节省很多,因为我不必维护继承会强加给我的过多的“from*import*”类型的文件(更不用说以后在客户决定移动特性时必须区分每个版本)。在

另外,在回应萨诺尔德的评论时,我想我的描述太模糊了。这不是在飞行中发生的事。我将生成一次新的*.py文件(每个版本/交付),并将生成的源代码提供给客户。另外,只有在第二个文件(新建.py在我的例子中)实际上存在,否则原始的将被复制。因此,与继承不同,我的组特定目录将相对较小,最终版本将部署在to一个单独的目录,我不需要维护它,除了交付给客户。在


Tags: 文件方法frompyimportself版本客户
1条回答
网友
1楼 · 发布于 2024-09-27 22:20:25

有了您新的改进描述,我可以提出一个我过去和其他团队使用过的解决方案,效果非常好:使用您的源代码管理通过分支或新存储库来管理差异。在

首先,请使用某种source control系统。更高级的,如^{}^{}SubversionBazaarClearCaseBitKeeperDarcsPerforce等,都支持某种形式的合并跟踪,这可以使这个特定的问题更容易解决。(无论您是否决定以这种方式使用分支,请务必使用源代码管理系统。)

您将维护一个主分支(如果您愿意,可以将其称为trunkmaster),其中包含几乎所有的开发工作、bug修复等。从这里分支特定于给定客户的所有代码。您可能更喜欢基于特性而不是客户名称,因为您可能有10个客户需要SCTP支持,而其他20个客户则需要TCP支持。(而且您希望对更奇特的协议收取更多费用,因此将其全部合并到配置选项中会对业务不利。)

当需要交付新产品时,您可以将分支(或存储库)更改为专门的分支、git pull(不同的存储库)或{}(不同的分支),或者{}或类似的命令,将更新从主开发主干线拉到专门的分支中。取决于您是否处理了冲突的代码,您可能需要修复一些合并冲突,或者它可能会非常干净。修复所有合并冲突,提交到分支,然后转到下一个分支。在

你很可能会得到一棵看起来像这样的“树”:

             I J K      supremely magic feature
            /     /
     D E F L M N     magic feature
    /        /     /
A B C G H O P Q    main trunk

获取太多的分支是一条快速的疯狂之路;如果可以,请确保将错误修复和共享特性提交到主干中,如果不能,则尽可能靠近主干。这将使它更容易合并回所有的后代分支。最好是在编写bug fix的新特性时尽可能地进行合并,因为那时它在您的脑海中是最新鲜的。在

维护多个版本的代码可能会让你发疯,尽管当你可以让你的代码更模块化,并简单地向你的用户交付不同的“模块”代码时,你可以大大降低你需要管理的复杂性。对模块化接口进行编程需要遵守纪律,而且大量的前期工作可能会让人望而却步,但是用五个插件来管理一个工具通常要比五个特性的不同组合更容易,因为客户会在五个特性中进行选择。在

您将认识到在每个客户分支中最有意义的修改类型,以及应该作为主干中的模块维护的修改。这种情况并不总是一目了然:尽你所能,尽你所能,采取一种使总体复杂度最低的方法。在

相关问题 更多 >

    热门问题