
在不少情形下, 于深夜时分, 我们瞅着自己三个月之前所编写的代码, 会萌生出一种想要“毁掉自己双眼”的冲动, 而这冲动是如此强烈。有一种感觉, 它极为微妙。每一行的语法, 都不存在错误, 其中的逻辑, 也能够顺利运行, 缩进呢, 还是标准的四个空格。然而, 当你打算给某个功能添加一个小补丁, 或者尝试把一段逻辑分离出来进行复用的时候, 你会察觉到, 整个代码就好似一团煮得过烂的面条, 牵一发而动全身, 改动一个变量, 就会导致三个模块崩溃。为什么会这样事实上, 这属于我在刚开始进入行业的起初若干年之中, 所遭遇的最为重大的困惑之处。通常情况下, 我们常常过度地沉醉于“术”的范畴里, 去机械性记忆编程库里各项运用方式, 甚至于无比执着地钻研那些极为生僻的语法特性, 然而令人忽略不计的却是对于“道”的深入修炼。在的世界里这种“道”就是编程范式。它之所迷人, 在于其极为宽容, 它身为一门具备多范式的语言, 既准许你如同写脚本那般随意涂抹, 又准许你好似建高楼那样严格架构, 甚至还准许你好像数学家那样摆弄数据流, 它支撑着过程式、面向对象式OOP以及函数式这三种主要的思维方式。这并非单纯写法不一样那么简单, 而是压根就是三种完全不同、毫无相似之处的世界观, 这般情况之下, 今天, 我打算跟大伙说一说这三种各不相同的范式, 在深入了解以后, 没准儿就是你从被称作“码农”的状态转变为成为“工程师”的那个具有决定性意义的转折点了。第一阶段直觉的陷阱——过程式编程这是我们所有人的起点。随着当下的我们处在起始学习阶段, 那时脑海之中所呈现的思维形态是呈线状排列的。这恰似日常清晨我们起身的行为模式, 首先进行刷牙的动作, 再来借助水洗脸面, 之后开展进食早餐的行为。符合这种思维直接映射的是过程式编程, 它最为契合人类直觉, 具备简单、粗暴、有效的特性, 它以“流程”作为核心, 你好似一位手持扩音器的导演, 指挥计算机的步骤为, 先开展A, 接着进行B, 倘若满足条件C, 便去执行D。于该种范式之中, 函数乃我们用以组织代码的基本单元。我们将一大块代码切成一个个之小逻辑, 依靠顺序、选择以及循环来把它们串联起来。看一个最经典的例子模拟银行取款balance 1000 def withdraw(amount): global balance if amount balance: balance - amount print(f取款 {amount} 元成功) else: print(余额不足) withdraw(300) print(balance) # 700这段代码看起来非常清爽对吧有某个东西逻辑呈线性, 其流程清晰明确, 要去定义一个全局范围的变量, 接着写一个函数用来对它进行修改, 针对编写那种几十行的小型脚本, 或者从事做个简单的自动化方面的任务情况下呢, 处在正常的逻辑思维里, 这种写法是具备无敌特性的, 它所具有的让人们去学习掌握的曲线是特别低的, 基本上无需负担任何多余而显得特殊额外产生需要认知投入较多精力的负担的。但是请注意那个 。在这一行代码的背后, 潜藏着过程式编程于大型项目内最为严重的隐患, 数据也就是变量, 和操作数据的方法也就是函数, 它们是相互分离的情形结构, 全局变量恰似一个被放置在广场中央位置的箱子, 任何一个人没错就是任何函数, 路过此处的时候都能够踢上一脚, 甚至还能对里面所放置的东西做出更改的行为动作。当你仅持这单单的一个函数之际, 所有状况皆处安好之态。然而倘若你的项目规模有所扩张, 存在着几十个数目的函数都在从事读取或者修改的行为, 而你突然间发觉余额出现了对不上的情形, 那么你便需要对这几十个函数展开排查工作, 去找出究竟是哪一个“暗暗地”实施了手脚。随着代码量开始膨胀, 那种“先做什么, 以后再做什么”的流水账形式, 会致使模块之间的耦合程度变得极高。你想要拆卸一个轮子下来, 然而结果却是发现连着轴承以及发动机。这便是为什么很多遗留系统维护起来极其痛苦的缘由所在。第二阶段构建世界的秩序——面向对象编程OOP当你被全局变量折磨得睡不着觉时你开始渴望秩序。程序不再仅是一条条执行的指令, 而是一群相互协作的所谓的“个体”, 正是这样一种思维方式发生了根本地转变, 这正是面向对象编程也就是说是那在混乱中努力建立秩序的尝试也就是OOP。面向对象编程理念觉得世界是由“对象”构建而成的, 每一个对象都存在着自身的范畴, 它将数据也就是属性以及操作这些数据所运用的方法行为表现紧紧地包裹在一起, 整合成一个统一的整体。这宛如原本置于广场中央的钱箱子, 也就是全局变量, 此刻被锁进了一个名为“账户”的保险柜内。唯有拿着钥匙的特定人员, 即对象的方法, 方可打开柜子去操作里面的钱。外界无需晓得柜子里的齿轮如何转动, 仅需告知柜子: “我要取钱”。这种思维方式让程序设计从“做什么”变成了“谁来做”。来看看同样的取款逻辑用 OOP 是怎么写的class Account: def __init__(self, balance): self.balance balance def withdraw(self, amount): if amount self.balance: self.balance - amount print(f取款 {amount} 元成功) else: print(余额不足) acc Account(1000) acc.withdraw(300) print(acc.balance) # 700发现区别了吗这里没有 。转变成为了 self. , 其归属于经由 这个类实例化而得来的对象 acc。除非借助 acc 对象去予以调用 , 不然的话谁都休想轻易触动里面所蕴含的钱。OOP的核心魅力之一便是封装, 那便在于, 它使复杂性得以潜藏, 让数据获得了保护。除此以外, OOP存在继承以及多态这两种有力手段。设想一下, 要是你需要一个“信用卡账户”, 你无需再次全部重写逻辑, 只对这个类进行继承, 接着改写一下透支的逻辑就行。面向对象编程恰似建筑师抑或公司的首席执行官, 你于设计一套系统之际, 界定每个角色的职责, 继而让这些角色借由消息传递以协作达成任务, 此消息传递即为方法调用。针对那些具备复杂的结构, 并且需要进行长久维护的大型项目而言, 面向对象编程差不多就是标准的答案, 它能够使代码拥有框架, 进而拥有可以扩展的空间。第三阶段数据的纯粹流动——函数式编程倘若讲过程式好似撰写剧本, OOP 仿若建造房屋, 那么函数式编程便如同在解答数学题目。这可能是初学者最难理解但也最优雅的一种范式。极为高冷的函数式编程, 其对“副作用”颇具厌憎之情。于它所处的世界中, 数据理应是不可变的。存在这样一个函数, 当给予其相同的输入时, 绝对必须始终返回相同的输出, 并且绝不能够暗自去修改外部的状态。还记不记得, 过程式编程当中的那个, 是吧? 函数式编程对于这样的一种写法, 那可是深恶痛绝的了。它并不去关注, 到底应该怎样一步步地去做, 它所关注的重点在于, 是“数据流”了。程序在这种情况下, 是被看作成为一条长长的管道的, 原始数据从管道的一端进入进去, 经过一个个纯函数的变换, 这里所说的变换诸如映射、过滤、归纳等, 最后从另一端流出最终的结果, 就是这样的情况了。程序员此时的思维模式是“输入如何映射为输出”虽说并非那种纯粹意义上的函数式语言, 然而它却给予了强大有力的支撑, 像是map(), 还有(), (), 以及咱们最为偏爱的列表推导式。来看看函数式编程如何处理数据from functools import reduce data [1000, -300, 200, -100] final_balance reduce(lambda x, y: x y, data) print(final_balance) # 800这里没有变量在中间被反复修改也没有状态的跳变。一种被命名为 data 的存在, 是输入流形态的, 是属于处理管道这一范畴的, 它还定义了变换规则。以水流这样的形式流淌穿梭过去的数据, 那结果自然而然就在这样的过程中产生。这类范式的代码常常极为简洁, 甚至携带着某种数学的美感, 由于它不存在副作用, 故而它天生适配并行处理, 鉴于大家都不争抢去修改同一个变量, 所以我开启十个线程同时进行计算, 全然不用担心数据冲突之处。大数据处理, 正变得越发重要, 并发计算, 同样变得越发重要, 在此背景之下, 有着函数式编程的理念, 正在重新变得火热。融会贯通并不存在的“最佳范式”聊了这么多你可能会问所以我到底该用哪一种这是个陷阱题。从事软件开发工作的实际情形, 从来都不是要么全盘肯定要么全盘否定的。具有强大能力的关键在于不强制你非得站入某一边。而且它准许你以灵活多变的方式混合使用, 依据具体情況应对解决种种问题。这同样是我所觉得的, 一名出色程序员必定要拥有的本领, 即依据场景来转变思维。要是你仅仅是编写一个用于备份日志的、五十行的运维脚本 , 那就毫不犹豫地采用过程式 , 其逻辑直观 , 写完活儿就可以收工。要是用面向对象编程去设计几个类 , 那可就是过度设计 , 属于矫情。要是正在开展电商后端开发工作, 其中有着涉及用户、订单、库存相互间极为复杂交错的关系, 并且预估维持时间超过三年, 这般情形下必须得采用面向对象方式, 运用类与对象去构建模型, 如此能够让自己的系统稳固仿若稳固的大山, 就连新加入的同事依据类图也能够较为快速地熟悉上手。倘若你正投身于数据分析工作, 或者着手处理一段繁杂的ETL逻辑, 且需要对海量数据进行清洗, 那么函数式便是你的得力助手。借助map以及替代繁杂的for循环, 代码将会清晰得仿若诗歌一般。真正的“道”往往是融合的。在实际开发中我们经常会看到这样的架构将入口设置为那种按步骤依次执行的程序代码, 以此来把整个原本的主要程序流程连接起来运用面向对象的方式去界定那核心的业务模型, 从而架构起整个对应系统的大体框架在特定某一个具体的方法里面, 采用函数式的思考逻辑去处置有关数据的计算以及转换。流程式仿若导演, 肩负着指挥的职责, 函数式恰似数学家, 承担计算的任务面向对象如同设计师, 从事构造的工作。进阶编程, 绝非是学会了若干个库, 而是你颅内“工具箱”里是否存有足够多的思维模型。当你不止执着于某一文法, 而是能够依据当下需求, 随手选取最适配的那一种范式之际, 你才真正领悟了 , 。期望你所编写的代码, 具备逻辑方面的严谨性, 拥有数学层面的优雅特质, 还秉持架构领域的智慧特性。