Python从基础到进阶——「函数&函数式编程」

函数式编程

在这里插入图片描述

在 Python 中一切皆对象,一切函数都是一等对象(first-class object)。什么是一等对象?它应该满足下述条件:

  • 在运行时创建
  • 能赋值给变量或数据结构中的元素
  • 能作为参数传给函数
  • 能作为函数的返回结果

举个例子:

# 我在控制台上定义这个函数,可以独立执行
>>> def factorial(n):      
...     '''returns n!'''
...     return 1 if n < 2 else n * factorial(n-1)
...
>>> factorial(5)
120
# __doc__是一等对象factorial众多属性中的一个
>>> factorial.__doc__
'returns n!'
# factorial 是函数(function)类的一个实例,也就是一个对象
>>> type(factorial)
<class 'function'>

函数本身就是对象!
Python 函数是真正的对象的同时,任何 Python 对象都可以表现的像函数。

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用,让我们分别用面向对象和函数式编程的方式实现一个经典的模式(策略模式),来体会个中优劣。

《设计模式:可复用面向对象软件的基础》这样描述策略模式:

定义一系列算法,把它们逐个封装起来,并且使它们可以相互替换,本模式使得算法可以独立于使用它的客户而变化。

举例来说,比如我们要去办公室上班,开车去或者是坐公交车去都是可选的出行方式,不同的人可以选择不同的出行方式,比如张三开车,李四坐公交。

如果用面向对象的写法其 UML 类图大概如下:
在这里插入图片描述
代码实现的话,大概如下:

from abc import ABC, abstractmethod

# 要去办公室的人
class Person:
    def __init__(self,name, transportation = None):
        self.name = name
        self.transportation = transportation

    def go_to_office(self):
        print(self.transportation.go_to_office(self))

# 抽象基类
class Transportation(ABC):
    @abstractmethod
    def go_to_office(self):
        """ return how to go to office """

# 策略1 开车
class ByCar(Transportation):
    def go_to_office(self):
        return (self.name + " 开车")

# 策略2 坐公交
class ByBus(Transportation):
    def go_to_office(self):
        return (self.name + " 坐公交")

# 测试输出
zhang_3 = Person('张三',ByCar)
zhang_3.go_to_office()
li_4 = Person('李四',ByBus)
li_4.go_to_office()

输出:

张三 开车
李四 坐公交

那么如果用函数式实现,该怎么写呢?

import types

# 要去办公室的人
class Person:
    def __init__(self,name, transportation = None):
        self.name = name
        # 让模块方法在调用的时候自动传入被调用对象作为self参数
        self.go_to_office = types.MethodType(transportation, self)

    def go_to_office(self):
        pass

# 策略1 开车
def by_car(person):
   print(person.name + " 开车")

# 策略2 坐公交
def by_bus(person):
   print(person.name + " 坐公交")

# 测试输出
zhang_3 = Person('张三',by_car)
zhang_3.go_to_office()
li_4 = Person('李四',by_bus)
li_4.go_to_office()

输出:

张三 开车
李四 坐公交

相比之下,函数式的方法用了相对较少的代就实现了策略模式并且有以下特点:

  • 只需要调用 self.go_to_office 来判断用何种方式出行
  • 没有抽象类
  • 各个策略都是函数

面向对象也好,面向过程也罢,都是编程思想里的瑰宝,它们联起手来让写代码这件事变的有哲学意味。它们之间的恩怨纠葛,孰是孰非,放在每个程序员的故事里都有自己的版本。我的观点,两手抓,两手都要硬。

新手误区

1.、函数只有再被调用后才会执行函数体里面对的内容
为什么提到这一点,因为在函数还未被调用时,把它当做空气对看到问题的核心是很有帮助的。看下面的例子,

def fun_out(a):
    c = 1
    def fun_in(b):
        return a + b + c
    c = 3
    return fun_in

在外部函数内部,先忽略内部函数fun_in,只有当外部函数被调用并 return 内部函数fun_in时,变量c会在最近的局部变量c=3

2、执行函数需要在函数名后面加上括号()

不带括号时,调用的是这个函数本身 ,是整个函数体,是一个函数对象,不须等该函数执行完成
带括号(参数或者无参),调用的是函数的执行结果,须等该函数执行完成的结果

3、闭包不仅仅是函数+自由变量,还必须满足外部函数return内部函数

参考:
2. Python之美
3. python中的lambda函数用法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值