高级Python:学习这10个原则,写出大师级别的函数!

文章总结了写好函数的10个原则,全文近万字,干货满满,值得每一个python程序员收藏。

【蜂鸟数据:金融数据API提供商,想获得金融数据?查看我们的官方文档吧】

不管编程语言使用哪种实现机制,它们都为函数保留了席位。函数是任何代码项目中必不可少的部分,因为它们负责准备和处理数据以及配置用户界面元素。毫无疑问,Python被定位为面向对象的编程语言,它依赖于函数来执行与数据相关的操作。因此,编写良好的函数对于构建弹性代码库至关重要。

在一个小项目中定义一些简单的函数很简单。随着项目的扩大,函数可能变得更加复杂,对更多函数的需求也呈指数增长。即便是富有经验的程序员,要想将所有函数完美地结合在一起也是一件令人头疼的事情。随着项目的扩大,将最佳实践应用于函数声明变得越来越重要。在本文中,我想谈一谈声明函数的最佳实践,这是我经过多年编码积累的知识。

1. 通用准则

您可能熟悉这些通用准则,但我想首先讨论它们,因为它们是许多程序员不赞赏的高级高级实践。当开发人员不遵循这些准则时,他们会付出代价:代码很难维护。

使用有意义的名称

我们必须给我们的函数起有意义的名字。如您所知,函数也是Python中的对象,因此在定义函数时,我们基本上会创建函数类型的变量。因此,变量名称(即函数的名称)必须反映其执行的操作。

尽管在现代编码中可读性已得到越来越多的重视,但在注释方面却经常被谈论,而与代码本身有关的讨论则少得多。因此,如果您必须写大量注释来解释您的函数,则您的函数很可能没有好名字。不必担心函数名很长:几乎所有现代IDE都具有出色的自动完成提示,这将使您不必键入整个长名。

高级Python:学习这10个原则,写出大师级别的函数!_第1张图片

好的命名规则也应适用于函数的参数以及函数内的所有局部变量。还有一点要注意的是,如果打算在类或模块中使用您的函数,则可能需要在名称前加上下划线(例如def _internal_fun():),以表明这些函数供私人使用,而不是公共API。

单一功能原则

您的函数应保持较小,以便于管理。想象一下,您正在盖房子。但是,您使用的砖是一米的立方。它们易于使用吗?可能不是,它们太大了。相同的原理适用于函数。函数是项目的基础。如果函数非常庞大,那么您的构建将无法顺利进行。当它们很小时,它们更容易放入各种地方并在需要时四处移动。

这也是函数实现单一目的的关键,这可以帮助您使函数保持较小。单一目标的另一个好处是,您会发现命名此类函数要容易得多。您可以简单地根据其预期的单一用途来命名函数。以下是我们如何重构我们的函数,以使每个函数仅用于一个目的。要注意的另一件事是,这样做可以最大限度地减少需要编写的注释,因为所有函数名都可以说明问题。

高级Python:学习这10个原则,写出大师级别的函数!_第2张图片

不要重新发明轮子

您没有无限的精力和时间来编写所需的每项操作的函数,因此熟悉标准库中的常见函数至关重要。在定义自己的函数之前,请考虑一下特定的业务需求是否是通用的,如果是,则可能有人已经解决了这些特定的需求。例如,如果您使用CSV格式的数据,则可以查看CSV模块中的函数。另外,pandas库可以优雅地处理CSV文件。对于另一个实例,如果要统计列表中的元素,则应考虑collections模块中的Counter类,该模块是专门为这些操作而设计的。

2. 默认参数

相关场景

当我们第一次定义一个函数时,它通常有一个特定的用途。但是,当您向项目中添加更多函数时,您可能会意识到可以合并一些紧密相关的函数。唯一的区别是合并函数的调用有时涉及传递另一个参数或设置略有不同的参数。在这种情况下,您可以考虑为参数设置默认值。

另一个常见的情况是,在声明一个函数时,您已经期望该函数有多种用途,其中函数调用使用差分参数,而其他一些参数几乎不需要变化。 您应该考虑为较少变化的参数设置默认值。

设置默认参数

设置默认参数的好处很简单,在大多数情况下,您无需处理设置不必要的参数。但是,将这些参数保留在函数签名中的可用性使您可以在需要时更灵活地使用函数。例如,对于内置sorted()函数,有几种方法可以调用该函数,但是在大多数情况下,我们只使用基本形式:sorted(the_iterable),它将按字典序的升序对可迭代对象进行排序。但是,当您想更改升序或默认词典顺序时,我们可以通过指定reverse和key参数来覆盖默认设置。

我们应该对自己的函数声明采用相同的做法。根据我们应该设置的值,经验法则是您应该选择用于大多数函数调用的默认值。因为这是一个可选参数,所以您(或您的API用户)在大多数情况下都不想设置它。考虑以下示例:

高级Python:学习这10个原则,写出大师级别的函数!_第3张图片

避免易变的默认参数的陷阱

有一个设置默认参数的陷阱。如果您的参数是一个可变对象,请务必不要使用默认构造函数对其进行设置,这很重要,因为函数是Python中的对象,并且它们是在定义时创建的。副作用是,在函数声明时对默认参数进行了评估,因此将创建一个默认的可变对象,并成为该函数的一部分。每当您使用默认对象调用该函数时,实际上都在访问与该函数关联的相同可变对象,尽管您的意图可能是希望该函数为您创建一个全新的对象。以下代码段向您展示了设置默认可变参数的有害副作用:

高级Python:学习这10个原则,写出大师级别的函数!_第4张图片

如上所示,尽管我们打算创建两个不同的购物清单,但是第二个函数调用仍然访问相同的基础对象,这导致将Soccer商品添加到相同的清单对象中。要解决该问题,我们应该使用以下实现。具体来说,您应该None将可变参数用作默认值:

高级Python:学习这10个原则,写出大师级别的函数!_第5张图片

3. 考虑返回多个值

返回包含多个元素的元组

当您的函数执行复杂的操作时,这些操作很可能会生成两个或多个对象,所有这些对于后续的数据处理都是必需的。从理论上讲,可以创建一个类来包装这些对象,以便函数可以将类实例作为其输出返回。但是,在Python中,函数可能会返回多个值。更准确地说,这些多个值作为元组对象返回。以下代码显示了一个简单的示例:

高级Python:学习这10个原则,写出大师级别的函数!_第6张图片

返回值不能多于3个

需要注意的一件事是,尽管Python函数可以返回多个值,但您不应滥用此功能。一个值(当一个函数不显式返回任何值时,它实际上None隐式返回)是最好的,因为一切都很简单,而且大多数用户通常希望函数仅返回一个值。在某些情况下,返回两个值很好,返回三个值仍然可以,但是请不要返回四个值。它会给哪个用户带来很多混乱。如果发生这种情况,这很好地表明您应该重构您的函数,您的函数可能有多种用途,您应该创建较小的函数并承担更多责任。

4. 使用Try Except

在将函数定义为公共API时,不能总是假定用户为函数设置了所需的参数。即使我们自己使用函数,也有可能某些参数是在我们的控制范围之外创建的,并且与我们的函数不兼容。在这些情况下,我们应该在函数声明中做什么?

首先要考虑的是使用try…except语句,这是典型的异常处理技术。您将可能会出错(即引发某些异常)的代码嵌入该try子句中,并在该子句中处理可能的异常except。

让我们考虑以下情形。假设特定的业务需求是您的函数采用文件路径,并且如果文件存在并且被成功读取,则您的函数会对文件进行一些数据处理操作并返回结果,否则返回-1。有多种方法可以实现此需求。下面的代码为您展示了一种可能的解决方案:

高级Python:学习这10个原则,写出大师级别的函数!_第7张图片

换句话说,如果您期望函数的用户可以设置一些导致代码中出现异常的参数,则可以定义处理这些可能异常的函数。但是,这应该与用户清楚地进行沟通,除非它是示例中所示功能的一部分(-1当无法读取文件时返回)。

5. 考虑验证参数

使用try…except有时称为EAFP(请求宽恕而不是获得许可)编码风格。还有另一种称为LBYL的编码样式(使用前先了解),该样式强调在运行特定代码块之前进行的完整性检查。

在前面的示例之后,就将LBYL应用于函数声明而言,另一个考虑因素是验证函数的参数。参数验证的一种常见用例是检查参数是否具有正确的数据类型。众所周知,Python是一种动态类型的语言,它不执行类型检查。例如,函数的参数应为整数或浮点数。但是,通过设置字符串(调用本身)来调用函数,直到函数执行后才会提示任何错误消息。

以下代码显示了在运行代码之前如何验证参数:

高级Python:学习这10个原则,写出大师级别的函数!_第8张图片

应该注意的是,EAFP和LBYL不仅可以用于处理函数参数,还可以应用于其他方面。它们可以应用于您的函数中的任何位置。尽管EAFP在Python世界中是首选的编码样式,但是根据您的用例,您还应该考虑使用LBYL,它可以提供比EAFP样式所提供的通用内置错误消息更多的用户友好的特定于函数的错误消息。

6. Lambda函数

作为函数的参数

一些函数可以采用其他函数(或一般而言可调用)来执行特定操作。例如,该sorted()函数具有key允许我们定义更多自定义排序行为的参数。以下代码段显示了一个用例:

高级Python:学习这10个原则,写出大师级别的函数!_第9张图片

使用lambda函数

值得注意的是,该sorting_grade函数仅使用了一次,它是一个简单的函数,在这种情况下,我们可以考虑使用lambda函数。如果您不熟悉lambda函数,这里有一个简短的描述。lambda函数是使用lambda关键字声明的匿名函数。它需要零到更多的参数,并且具有一个适用于操作的表达式,格式为:lambda arguments: expression。以下代码显示了如何在函数中使用lambda函数,该sorted()函数看起来比上面的解决方案还干净:

在这里插入图片描述

与许多数据科学家相关的另一个常见用例是在与pandas配合使用时使用lambda函数。以下代码是一个简单的示例,该lambda函数如何使用该map()函数辅助数据操作,该函数操作pandas Series对象中的每个项目:

高级Python:学习这10个原则,写出大师级别的函数!_第10张图片

7. 考虑装饰器

装饰器是在不影响其核心功能的情况下修改其他函数的行为的函数。换句话说,它们在装饰水平上对装饰功能进行了修改。这是装饰器如何在Python中工作的简单示例。

高级Python:学习这10个原则,写出大师级别的函数!_第11张图片

如图所示,装饰器函数只需将装饰函数运行两次。要使用装饰器,我们只需将装饰器函数名称放在带@前缀的装饰函数上方即可。如您所知,修饰函数确实被调用了两次。例如,一种有用的装饰器是可以在自定义类中使用的属性装饰器。以下代码向您展示了它是如何工作的。本质上,@property装饰器转换实例方法以使其表现得像常规属性,从而允许使用点表示法进行访问。

高级Python:学习这10个原则,写出大师级别的函数!_第12张图片

装饰器的另一个用例是时间记录装饰器,当您关注函数的效率时,它可能特别方便。以下代码向您展示了这种用法:

高级Python:学习这10个原则,写出大师级别的函数!_第13张图片

8. 使用*args和**kwargs

在上一节中,您看到了*args以及**kwargs在装饰器函数时的使用,该装饰器函数的使用允许装饰器函数装饰任何函数。从本质上讲,我们用*args捕获所有的位置参数,而**kwargs捕获所有的关键字参数。具体而言,位置参数基于在函数调用中传递的参数的位置,而关键字参数基于将参数设置为专门命名的函数参数。

高级Python:学习这10个原则,写出大师级别的函数!_第14张图片

以下代码向您展示了**kwargs在函数声明的合法使用。

高级Python:学习这10个原则,写出大师级别的函数!_第15张图片

但是,在大多数情况下,您无需使用*args**kwargs。尽管它可以使声明更清晰,但它会隐藏函数的签名。换句话说,函数的用户必须准确地确定函数采用的参数。因此,我的建议是避免在不需要时使用它们。例如,我可以使用字典参数来替换**kwargs吗?同样,我可以使用列表或元组对象替换*args吗?在大多数情况下,这些替代方法可以正常工作。

9. 参数类型提示

如前所述,Python是一种动态类型的编程语言,也是一种解释型语言,其含义是Python在编码期间不会检查代码的有效性,包括类型兼容性。在您的代码实际执行之前,将出现与您的函数不兼容的类型(例如,在期望整数时将字符串发送给函数)。

由于这些原因,Python不会强制执行输入和输出参数类型的声明。换句话说,在创建函数时,无需指定它们应具有的参数类型。但是,在最近的Python版本中可以做到这一点。具有类型注释的主要好处是某些IDE(例如PyCharm或Visual Studio Code)可以使用注释来检查类型的兼容性,以便在您或其他用户使用您的函数时可以得到适当的提示。

另一个相关的好处是,如果IDE知道参数的类型,它可以给出适当的自动完成建议,以帮助您更快地进行编码。当然,当您为函数编写文档字符串时,这些类型注释也将为代码的最终开发人员提供信息。

高级Python:学习这10个原则,写出大师级别的函数!_第16张图片

10. 文档

我把好的文档与负责的文档等同起来。如果您的函数是供私人使用的,则不必编写非常详尽的文档,您可以假设您的代码清楚地讲述了故事。如果任何地方都需要澄清,您可以写一个非常简短的注释,当您重新访问代码时,它可以提醒您自己或其他读者。在这里,有关负责任文档的讨论更多地与作为公共API的函数的文档字符串有关。应包括以下方面:

  • 函数预期操作的简短摘要。这应该非常简洁。在大多数情况下,摘要不应超过一个句子。
  • 输入参数:类型和说明。您需要指定输入参数的类型,以及通过设置特定选项可以执行的操作。
  • 返回值:类型和说明。与输入参数一样,您需要指定函数的输出。如果未返回任何内容,则可以选择将其指定None为返回值。

结论

如果您有编码经验,您会发现大部分时间都花在编写和重构函数上。毕竟,您的数据本身通常不会发生太大变化,而是处理和操纵数据的函数。如果您将数据视为身体的躯干,那么函数就是手臂和腿部。因此,我们必须编写好的函数来使我们的程序更加敏捷。

原文来自于Medium,原文作者:Yong Cui, Ph.D,原文标题:Advanced Python: Consider These 10 Elements When You Define Python Functions,翻译校对:蜂鸟数据

如果喜欢我们的文章,记得点赞和收藏哦,我们每天都会为大家带来Python,数据科学和量化交易的精品内容。

【关于我们】

蜂鸟数据:国内领先的金融数据API提供商。

蜂鸟数据团队由业界顶尖的数据工程师,数据科学家和宽客组成,我们正努力构建一个强大的金融数据库,并提供API接口,目标是令金融数据开源化和平民化。

浏览并测试我们接口吧,目前覆盖股票,外汇,商品期货,数字货币和宏观经济领域,包括实时报价(tick)和历史数据(分钟),提供REST API和Websocket两种接入方式,能够满足金融分析师,量化交易和理财app的需求。

需要金融数据?利用蜂鸟API将数据整合到您的应用

如果您准备好了,请登录蜂鸟官网,注册免费获取API密钥,然后开始探索我们的金融数据库吧。

你可能感兴趣的:(python,技术杂谈,python,编程语言)