加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

在Python中使用函数式编程的最佳实践!

发布时间:2019-01-29 13:49:49 所属栏目:建站 来源:菜鸟带你学编程
导读:简介 Python 是一种功能丰富的高级编程语言。它有通用的标准库,支持多种编程语言范式,还有许多内部的透明度。如果你愿意,还可以查看 Python 的底层并修改,甚至能在程序运行的时候直接修改运行时。 我最近注意到一个有经验的 Python 程序员使用 Python

第一次运行 test_pluraize 时该测试能够通过,但以后每次运行都会失败,因为它会反复添加“s”和“es”。为了让它变成纯函数, 可以这样写:

  1. dictionary = ['fox', 'boss', 'orange', 'toes', 'fairy', 'cup']  
  2. def puralize(words):  
  3.  result = []  
  4.  for word in words:  
  5.  word = words[i]  
  6.  if word.endswith('s') or word.endswith('x'):  
  7.  plural = word + 'es')  
  8.  if word.endswith('y'):  
  9.  plural = word[:-1] + 'ies'  
  10.  else:  
  11.  plural = + 's'  
  12.  result.append(plural)  
  13.  return result  
  14. def test_pluralize():  
  15.  result = pluralize(dictionary)  
  16.  assert result == ['foxes', 'bosses', 'oranges', 'toeses', 'fairies', 'cups'] 

注意这里并没有使用任何 FP 特有的概念,只是创建并返回了一个新的对象,而不是重用并修改已有的旧对象。这样输入的内容也会保持不变。

虽然这个例子像个玩具,但想象一下,如果你传递并改变了某个复杂的对象,或者通过数据库连接进行了某些操作。当编写很多很多测试用例时就会发现,你必须非常小心地处理测试用例的顺序,或者花大量代价在每个测试用例之后清除并重新创建状态。这些工作应该是在 e2e 集成测试阶段的活儿,不应该在比较小的单元测试阶段进行。

理解(并避免)可修改性

先来个调查,你认为哪些数据结构是可修改的?

为什么这一点很重要?有些时候列表和元组可以互换使用,因此人们经常会在代码中随机使用两者之一。于是当你试图修改一个元组(比如给其中一个元素赋值)时就会出错。或者试图用列表作为字典的键,也会导致 TypeError,因为列表是可修改的。元组和字符串可以作为字典的键使用,因为它们不可修改,可以得到确定的哈希值,而其他数据结构都不行,因为它们的对象标识即使保持不变,值也会改变。

最重要的是,在传递字典、列表或集合时,它们可能会在其他上下文中被意料之外地改变。这种问题非常难以调试。可修改的默认参数就是个经典的例子:

  1. def add_bar(items=[]):  
  2.  items.append('bar')  
  3.  return items  
  4. l = add_bar() # l is ['bar']  
  5. l.append('foo')  
  6. add_bar() # returns ['bar', 'foo', 'bar'] 

字典、集合和列表很强大、效率很高、非常 Python,而且非常有用。写代码时完全不使用它们是不明智的。但即使如此,我永远会在默认参数的位置使用元组或 None(代替空字典或空列表),并且在缺乏足够的防御代码的情况下,避免将可修改的数据结构在不同的上下文中传递。

减少类的使用

类(及其实例)的可修改性是把双刃剑。随着写的 Python 代码越来越多,,我开始倾向于仅在绝对必要时才使用类,而且我几乎从不使用可修改的类属性。对于那些高度面向对象的语言(如 Java)的程序员来说这一点可能很难做到,但许多其他语言中在类层面完成的东西,在 Python 可以在模块层面完成。例如,如果需要将函数或常量或命名空间分组,那么可以把它们一起放到另一个 .py 文件中。

我经常看到一些类的目的是保存几个命名变量的值,这种情况下 namedtuple(其类型是 typing.NamedTuple)就足够,而且还是不可改变的。

  1. from collections import namedtuple  
  2. VerbTenses = namedtuple('VerbTenses', ['past', 'present', 'future'])  
  3. # versus  
  4. class VerbTenses(object):  
  5.  def __init__(self, past, present, future):  
  6.  self.past = past,  
  7.  self.present = present  
  8.  self.future = future 

如果确实需要状态的来源,而且多个视图都需要改变该状态,那么类是绝佳的选择。此外,与静态方法相比,我更倾向于单例纯函数,这样它们能在其他上下文中组合使用。

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读