首页 > 解决方案 > 将目录树遍历与需要在 python 中运行的代码分离

问题描述

我在一个看起来像这样的目录结构中运行模拟rootDir/*pot/*K/*Ang/lambda_*。星号具有其通常的通配符含义并被各种不同的参数替换。

过去,我们小组使用 bash 完成大多数此类任务,其中使用此类通配符非常简单。但是,我们正在尝试切换到 python,因为它总体上更强大。但是在 python 中,cat *K/file >> newfile有点糟糕,这意味着通常需要更多的代码。

此外,编写真正需要运行嵌套 5 次循环的关键代码也很糟糕,尤其是当您必须进一步进行更改时。它只是杂乱无章。

所以我写了一个模块,将遍历和代码执行分离得相当不错。优点是我可以为给定的文件夹结构创建一个模板,然后只需添加很少的几行就可以在我想要的任何位置运行不同的代码。但是,它使用了一种你们大多数人会讨厌我的 hack,并且也有问题,因为应该运行的代码实际上是在帮助模块的范围内执行的,所以几乎必须选择从那里运行所有代码,或没有。

这是模块(我称之为“actionChain.py”):

#!/usr/bin/env python3

import os
import shutil
import fnmatch
import re

j = os.path.join

class actionChain:
    def __init__(self, path):
        self.path = os.path.abspath(path)
        self.basename = os.path.basename(self.path)
        self.firstCommands = []
        self.lastCommands = []
        self.actionSteps = []

    def setPath(self, path):
        self.path = os.path.abspath(path)
        self.basename = os.path.basename(self.path)

    def addActionSteps(self, *actionSteps):
        for step in actionSteps:
            self.actionSteps.append(step)

    def addFirstCommands(self, *firstCommands):
        for command in firstCommands:
            self.firstCommands.append(command)

    def addLastCommands(self, *lastCommands):
        for command in lastCommands:
            self.lastCommands.append(command)

    def run(self):
        currentDir = os.getcwd()
        os.chdir(self.path)
        
        for c in self.firstCommands:
            exec(c)
        # Do not ever repeat this hack unless you know _very_ well what you're doing
        globals().update(locals())
       
        if self.actionSteps:
            self.actionSteps[0].run(self.actionSteps[1:])
      
        for c in self.lastCommands:
            exec(c)
        # Do not ever repeat this hack unless you know _very_ well what you're doing
        globals().update(locals())

        os.chdir(currentDir)


class actionStep:
    def __init__(self, pattern):
        self.pattern = pattern
        self.firstCommands = []
        self.lastCommands = []

    def setPattern(self, pattern):
        self.pattern = pattern

    def addFirstCommands(self, *firstCommands):
        for command in firstCommands:
            self.firstCommands.append(command)

    def addLastCommands(self, *lastCommands):
        for command in lastCommands:
            self.lastCommands.append(command)

    def run(self, subsequentSteps):

        files = os.listdir(".")
        for f in files:
            if os.path.isdir(f) and fnmatch.fnmatch(f, self.pattern):
                os.chdir(f)
                
                for c in self.firstCommands:
                    exec(c)
                # Do not ever repeat this hack unless you know _very_ well what you're doing
                globals().update(locals())

                if subsequentSteps:
                    subsequentSteps[0].run(subsequentSteps[1:])

                for c in self.lastCommands:
                    exec(c)
                # Do not ever repeat this hack unless you know _very_ well what you're doing
                globals().update(locals())

                os.chdir("..")

这很好,因为它允许我使用这样的代码:

#!/usr/bin/env python3

import actionChain as ac

chain = ac.actionChain(".")

rootDir = ac.actionStep("mtp_to_mtp_allVT")

targetDir = ac.actionStep("target_*")

refDir = ac.actionStep("reference_*")

TDir = ac.actionStep("*K")

aLatDir = ac.actionStep("*Ang")

lambdaDir = ac.actionStep("lambda_*")

chain.addActionSteps(rootDir, targetDir, refDir, TDir, aLatDir, lambdaDir)



# Get variables from structure -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-

targetDir.addFirstCommands(r"""
target = re.search('(?<=target_).*', os.path.basename(os.getcwd())).group(0)
print('target:', target)
""")

refDir.addFirstCommands(r"""
ref = re.search('(?<=reference_).*', os.path.basename(os.getcwd())).group(0)
print('ref:', ref)
""")

TDir.addFirstCommands(r"""
T = re.search('.*(?=K)', os.path.basename(os.getcwd())).group(0)
print('T:', T)
""")

aLatDir.addFirstCommands(r"""
aLat = re.search('.*(?=Ang)', os.path.basename(os.getcwd())).group(0)
""")

lambdaDir.addFirstCommands(r"""
l = re.search('(?<=lambda_).*', os.path.basename(os.getcwd())).group(0)
""")

# get variables from structure -^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-




# Your code goes here -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v

chain.addFirstCommands("noAtoms = 125")

refDir.addFirstCommands(r"""
extract = open('extractedData.tsv', 'w')
extract.write('#T[K]\taLat[Ang]\tpotEne[eV]\tpotEneRef[eV]\tpotEne-potEneRef[meV/atom]\n')
""")
refDir.addLastCommands(r"""
extract.close()
""")


lambdaDir.setPattern("lambda_1.00")

lambdaDir.addFirstCommands(r"""
f = open('dUdL', 'r')
line = f.readlines()[1].split()
f.close
potEne = line[9]
potEneRef = line[10]
extract.write('{}\t{}\t{}\t{}\t{}\n'.format(T, aLat, potEne, potEneRef, (float(potEne)-float(potEneRef))/noAtoms))
""")

# Your code goes here -^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-



chain.run()

如您所见,这些字符串代码中的语法高亮也是一个问题。

我意识到这是一个相当广泛的问题,但是您对如何更好地解决这个问题有什么建议吗?少hacky?还是比较简单易用?

这些是我需要修复的东西:

标签: pythonfilesystemstraversal

解决方案


推荐阅读