【问题标题】:Grouping Functions by Using Classes in Python在 Python 中使用类对函数进行分组
【发布时间】:2016-08-04 04:48:03
【问题描述】:

我从事 Python 科学程序员已有几年了,随着我的程序越来越大,我发现自己遇到了一个特定的问题。我是自学成才的,所以我从来没有接受过任何正式培训,并且花时间真正“正确”地使用 Python 进行编码的“约定”。

总之,我发现自己总是创建一个 utils.py 文件,我将所有定义的函数存储在我的程序使用的文件中。然后我发现自己将这些功能分组到各自的目的中。我知道对事物进行分组的一种方法当然是使用类,但我不确定我的策略是否与实际应该使用的类相反。

假设我有一堆功能大致相同:

def add(a,b):
    return a + b

def sub(a,b):
    return a -b

def cap(string):
    return string.title()

def lower(string):
    return string.lower()

现在显然这 4 个函数可以看作是做两个不同的目的,一个是计算,另一个是格式化。这就是逻辑告诉我要做的事情,但我必须解决它,因为我不想初始化一个与该类对应的变量。

class calc_funcs(object):

    def __init__(self):
        pass

    @staticmethod
    def add(a,b):
        return a + b

    @staticmethod
    def sub(a, b):
        return a - b

class format_funcs(object):
    def __init__(self):
        pass

    @staticmethod
    def cap(string):
        return string.title()

    @staticmethod
    def lower(string):
        return string.lower()

通过这种方式,我现在将这些方法“分组”到一个很好的包中,根据它们在程序中的角色,可以更快地找到所需的方法。

print calc_funcs.add(1,2)
print format_funcs.lower("Hello Bob")

话虽如此,我觉得这是一种非常“unpython-y”的做事方式,而且感觉很混乱。我是想以正确的方式思考还是有其他方法?

【问题讨论】:

  • 查看我在__init__.py上所做的编辑以获取更多信息
  • 非常好的问题。我也是自学成才,遇到类似的组织问题,并且与您尝试将功能分组到类中具有完全相同的直觉!我意识到这不可能是理想的……毕竟,我从未见过其他人这样做。下面的包/模块方法很棒。
  • 看到有人已经通过相同的程序来订购代码,我感到非常欣慰,想知道并询问它在现实世界中是如何完成的。谢谢@Uys of Spades

标签: python class conventions


【解决方案1】:

另一种方法是创建一个util,并将您的功能拆分为该包中的不同模块。包的基础知识:创建一个目录(其名称将是包名)并在其中放入一个特殊文件,__init__.py 文件。这个可以包含代码,但是对于基本的包组织,它可以是一个空文件。

my_package/
  __init__.py
  module1.py/
  modle2.py/
  ...
  module3.py

假设你在你的工作目录中:

mkdir util
touch util/__init__.py

然后在您的util 目录中,生成calc_funcs.py

def add(a,b):
    return a + b

def sub(a,b):
    return a -b

还有format_funcs.py:

def cap(string):
    return string.title()

def lower(string):
    return string.lower()

现在,在您的工作目录中,您可以执行以下操作:

>>> from util import calc_funcs
>>> calc_funcs.add(1,3)
4
>>> from util.format_funcs import cap
>>> cap("the quick brown fox jumped over the lazy dog")
'The Quick Brown Fox Jumped Over The Lazy Dog'

编辑添加

但请注意,如果我们重新启动解释器会话:

>>> import util
>>> util.format_funcs.cap("i should've been a book")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'util' has no attribute 'format_funcs'

这就是__init__.py 的用途!

__init__.py 中,添加以下内容:

import util.calc_funcs, util.format_funcs

现在,再次重启解释器:

>>> import util
>>> util.calc_funcs.add('1','2')
'12'
>>> util.format_funcs.lower("I DON'T KNOW WHAT I'M YELLING ABOUT")
"i don't know what i'm yelling about"

耶!我们可以通过轻松导入灵活地控制我们的命名空间!基本上,__init__.py 的作用类似于类定义中的__init__ 方法。

【讨论】:

  • juanpa,如果你有一堆模块属于一个包,这是一个很好的方法。我想知道在这种情况下它们是否真的都属于一个包。
  • @Jonathan,阅读我认为这是一个玩具示例的问题。无论如何,对我来说,包只是组织命名空间的一种方式。模块的数量无所谓,是一堆还是几个。
  • 赞成不使用星型导入,例如from util import *,此处推荐:docs.python-guide.org/en/latest/writing/structure“可以通过使用导入语句的特殊语法来模拟更标准的行为:from modu import *。这通常被认为是不好的做法。使用 import * 会使代码更难阅读,并使依赖关系不那么划分。”
【解决方案2】:

我不会为此使用class,我会使用module。仅由静态方法组成的类也让我感到代码味道。以下是使用模块的方法:每当您将代码粘贴在单独的文件中并将其导入另一个文件时,Python 都会将该代码粘贴在与该文件同名的模块中。所以在你的情况下:

mathutil.py

def add(a,b):
    return a+b

def sub(a,b):
    return a-b

main.py

import mathutil

def main():
    c = mathutil.add(a,b)

或者,如果您要在很多地方使用 mathutil 并且不想每次都输入(并阅读)完整的模块名称,请想出一个标准的缩写并在任何地方使用它:

main.py,备用版本

import mathutil as mu

def main():
    c = mu.add(a,b)

与您的方法相比,您将拥有更多文件,每个文件中的函数更少,但我认为以这种方式浏览代码更容易。

顺便说一句,命名文件/模块有一点 Python 约定:短名称,全部小写,单词之间没有下划线。这不是我开始做的事情,但我已经在我的代码中开始这样做了,这让我更容易理解我使用过的其他人模块的结构。

【讨论】:

    【解决方案3】:

    我认为这样做完全符合 Python 风格。这正是staticmethod构造函数的目的。

    有关 python 约定,请参阅PEP 8

    【讨论】:

    • 使用staticmethod会不会有性能成本(值得一提),而不是使用单个功能的模块?
    • @ajsp 我不知道有任何显着的性能损失。如果您真的担心,也许可以在您的特定平台上运行一些微基准测试? (如果有很大差异,我会感到惊讶。)
    猜你喜欢
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 2018-05-21
    • 2010-11-15
    • 1970-01-01
    相关资源
    最近更新 更多