如何编写支持Windows和Linux的Python代码?

时间:2019-11-02 11:44:43

标签: python linux windows

我有一些代码需要在Windows和Linux上做非常相似的事情。不幸的是,我需要几个特定于系统的功能(例如,隐藏文件:Python cross platform hidden file)。为了提高可读性和可维护性,编写代码的最佳方法是什么?

当前,代码使用许多if语句在不同平台上的行为有所不同。我考虑过的另一种方法是将代码分为两个单独的函数,一个用于Windows,一个用于Linux,但这将意味着在两个位置更新代码的主要部分。

请注意,代码的主要部分比这更长,更复杂。

组合方法(最大的可维护性,但有许多if语句):

import os

def sort_out_files():
    if is_linux:
        do_linux_preparations()
    else:
        do_windows_preparations()

    # Main part of the code:
    for file in os.listdir(folder):
        if is_correct_file(file):
            if is_linux:
                do_main_actions_for_linux()
            else:
                do_main_actions_for_windows()

    if is_linux:
        do_linux_tidying_up()
    else:
        do_windows_tidying_up()

单独的方法(需要更多的维护,但需要更少的if语句):

import os

def sort_out_files_linux():
    do_linux_preparations()

    # Main part of the code:
    for file in os.listdir(folder):
        if is_correct_file(file):
            do_main_actions_for_linux()

    do_linux_tidying_up()


def sort_out_files_windows():
    do_windows_preparations()

    # Main part of the code:
    for file in os.listdir(folder):
        if is_correct_file(file):
            do_main_actions_for_windows()

    do_windows_tidying_up()

def sort_out_files():
    if is_linux:
        sort_out_files_linux():
    else:
        sort_out_files_windows()

do_preparations()do_tidying_up()函数涉及复制文件,提取等。

is_correct_file()检查文件是否具有正确的名称和正确的时间戳。

do_main_actions()涉及分析,移动和隐藏文件。

以上示例均有效,但似乎不是实现长期代码可维护性的最Pythonic或最佳方法。

3 个答案:

答案 0 :(得分:4)

我将所有仅适用于一个OS的文件都放在一个文件中,但名称相同。然后,您可以在主文件的开头添加以下内容:

if is_linux:
    import linux_tools as tools
else:
    import windows_tools as tools

如果这两个文件具有相同的界面(例如顶级方法),则可以互换使用。

在您的示例中,linux_toolswindows_tools都将包含它们各自的sort_out_files的实现,但是都被命名为sort_out_files,因此您可以将其与{{1} }。

请记住,将尽可能多的通用代码保留在这些模块之外。

答案 1 :(得分:1)

为了使您的代码更具可维护性,我建议您研究similar issue

例如:您可以创建一个适配器类,而不是每次需要运行os特定函数时都调用if语句。在运行时,您将使用适当的特定于操作系统的实现来创建适配器,并在需要时引用它。

适配器设计示例:

class TabbarViewWidget extends StatefulWidget {
  TabbarViewWidget({this.selectedList});

  final List<String> selectedList;

  @override
  _TabbarViewWidgetState createState() => _TabbarViewWidgetState();
}

class _TabbarViewWidgetState extends State<TabbarViewWidget> {
  TextEditingController textController = TextEditingController();

  var items = List<String>();

  void filteredSearch(String query) {
    List<String> dummySearchList = List();
    dummySearchList.addAll(widget.selectedList);
    if (query.isNotEmpty) {
      List<String> dummyListData = List();
      dummySearchList.forEach((item) {
        if (item.contains(query)) {
          dummyListData.add(query);
        }
      });
      setState(() {
        items.clear();
        items.addAll(dummyListData);
      });
      return;
    } else {
      setState(() {
        items.clear();
        items.addAll(widget.selectedList);
      });
    }
  }

  @override
  void initState() {
    items = widget.selectedList;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        Padding(
          padding: EdgeInsets.all(15.0),
          child: TextField(
            onChanged: (value) {
              filteredSearch(value.toUpperCase());
            },
            controller: textController,
            decoration: InputDecoration(
                hintText: "Search",
                labelText: "Search",
                prefixIcon: Icon(Icons.search),
                border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(
                  Radius.circular(25.0),
                ))),
          ),
        ),
        Expanded(
            child: ListView.builder(
                itemCount: items.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text('${items[index]}'),
                  );
                })),
      ],
    );
  }
}

答案 2 :(得分:1)

为避免整个代码出现重复情况,您可以在专用子模块(每个平台一个子模块)中定义所有特定于平台的功能,然后有条件地导入与主机匹配的子模块

主文件

if is_linux:
    import .fs_platform_windows as fs
else:
    import .fs_platform_linux as fs

def sort_out_files():
    fs.do_preparations()

    # Main part of the code:
    for file in os.listdir(folder):
        if is_correct_file(file):
            fs.do_main_actions()

    fs.do_tidying_up()

显然,您需要让两个子模块实现相同的功能(具有相同的名称)。 这是一种多态性,如果要将所有代码都放在同一个文件中,则可以通过类获得相同的结果。