python高级(六)——用一等函数实现设计模式

作者:编程技术

本文主要内容

经典的“策略”模式

 

python高级——目录

文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级

 

经典的“策略”模式

'''
    经典的策略模式:
        封装一系列可以互相替代的算法,使得算法可以独立与使用它的客户而变化。


    假设当代商城某服装店有以下三种打折规则:
        1、对于会员,全部商品8.5折
        2、同一件商品买两件及以上,除第一件外,剩余的7.5折
        3、买上5件不同商品,全部商品打8折
    三种规则只能享受一个。
'''


from abc import ABC, abstractmethod
from collections import namedtuple

Customer = namedtuple('Customer', 'name vip')     # 消费者对象


class Clothing:                # 服装类

    def __init__(self, name, quantity, price):
        self.name = name
        self.quantity = quantity
        self.price = price

    def total(self):
        return self.price * self.quantity


class Order:  # 订单类

    def __init__(self, customer, clothing, promotion=None):
        self.customer = customer
        self.clothing = list(clothing)
        self.promotion = promotion

    def total(self):
        if not hasattr(self, '__total'):
            self.__total = sum(item.total() for item in self.clothing)
        return self.__total

    def due(self):
        if self.promotion is None:
            discount = 0
        else:
            discount = self.promotion.discount(self)
        return self.total() - discount

    def __repr__(self):
        fmt = '<Order total: {:.2f} due: {:.2f}>'
        return fmt.format(self.total(), self.due())


class Promotion(ABC):  # 创建三种折扣的基类

    @abstractmethod
    def discount(self, order):
        ''':returns 计算折扣'''


class VipPromo(Promotion):  # 会员折扣
    """:returns 会员8.5折"""

    def discount(self, order):
        return order.total() * .15 if order.customer.vip  else 0


class TwoPromo(Promotion):  # 第二个
    ''':returns 同一件衣服两件以上,第二件及之后的7.5折'''

    def discount(self, order):
        discount = 0
        for item in order.clothing:
            if item.quantity >= 2:
                discount  = (item.total() - item.price) * .25
        return discount


class FivePromo(Promotion):  # 5种以上
    """ :returns 买5种不同服装以上,每件8折"""

    def discount(self, order):
        distinct_items = {item.name for item in order.clothing}
        if len(distinct_items) >= 5:
            return order.total() * .2
        return 0


if __name__ == "__main__":
    # 创建消费者
    joe = Customer('John Doe', 0)  # 非会员
    ann = Customer('Ann Smith', 1) # 会员

    # 创建购物车
    clothing = [Clothing('pants', 6, 200),
                Clothing('skirt', 1, 150),
                Clothing('shoes', 2, 230)]
    print(Order(joe, clothing, VipPromo()))  #   <Order total: 1810.00 due: 1810.00>    不是会员,不打折
    print(Order(ann, clothing, VipPromo()))  #   <Order total: 1810.00 due: 1538.50>    会员,打85折


    print(Order(joe, clothing, TwoPromo()))  # <Order total: 1810.00 due: 1502.50>   两件以上7.5折
    print(Order(joe, clothing, FivePromo())) # <Order total: 1810.00 due: 1810.00>   没到5种不打折

    clothing.extend([Clothing('shirt', 1, 90), Clothing('bra', 2, 130)])
    print(Order(joe, clothing, FivePromo())) # <Order total: 2160.00 due: 1728.00>  刚好5种打8折
'''
    下面使用函数完成"经典"策略
'''

from abc import ABC, abstractmethod
from collections import namedtuple

Customer = namedtuple('Customer', 'name vip')     # 消费者对象


class Clothing:                # 服装类

    def __init__(self, name, quantity, price):
        self.name = name
        self.quantity = quantity
        self.price = price

    def total(self):
        return self.price * self.quantity


class Order:  # 订单类

    def __init__(self, customer, clothing, promotion=None):
        self.customer = customer
        self.clothing = list(clothing)
        self.promotion = promotion

    def total(self):
        if not hasattr(self, '__total'):
            self.__total = sum(item.total() for item in self.clothing)
        return self.__total

    def due(self):
        if self.promotion is None:
            discount = 0
        else:
            discount = self.promotion(self)
        return self.total() - discount

    def __repr__(self):
        fmt = '<Order total: {:.2f} due: {:.2f}>'
        return fmt.format(self.total(), self.due())



def VipPromo(order):  # 会员折扣
    return order.total() * .15 if order.customer.vip  else 0


def TwoPromo(order):  # 第二个
    discount = 0
    for item in order.clothing:
        if item.quantity >= 2:
            discount  = (item.total() - item.price) * .25
    return discount


def FivePromo(order):  # 5种以上
    distinct_items = {item.name for item in order.clothing}
    if len(distinct_items) >= 5:
        return order.total() * .2
    return 0



if __name__ == "__main__":
    # 创建消费者
    joe = Customer('John Doe', 0)  # 非会员
    ann = Customer('Ann Smith', 1) # 会员

    # 创建购物车
    clothing = [Clothing('pants', 6, 200),
                Clothing('skirt', 1, 150),
                Clothing('shoes', 2, 230)]
    print(Order(joe, clothing, VipPromo))  #   <Order total: 1810.00 due: 1810.00>    不是会员,不打折
    print(Order(ann, clothing, VipPromo))  #   <Order total: 1810.00 due: 1538.50>    会员,打85折


    print(Order(joe, clothing, TwoPromo))  # <Order total: 1810.00 due: 1502.50>   两件以上7.5折
    print(Order(joe, clothing, FivePromo)) # <Order total: 1810.00 due: 1810.00>   没到5种不打折

    clothing.extend([Clothing('shirt', 1, 90), Clothing('bra', 2, 130)])
    print(Order(joe, clothing, FivePromo)) # <Order total: 2160.00 due: 1728.00>  刚好5种打8折
    promos = [VipPromo, TwoPromo, FivePromo]


    def best_stratety(order):
        return max(promo(order) for promo in promos)


    print(Order(joe, clothing, best_stratety))   # <Order total: 2160.00 due: 1728.00>  自动选择最优的策略
'''
    使用globals函数找出当前的全局号。其返回的是字典格式
'''
promos = [globals()[name] for name in globals()
              if name.endswith("Promo")]

    print(promos)   #  找到了三个策略函数 [<function FivePromo at 0x10c363b70>, <function TwoPromo at 0x10c363ae8>, <function VipPromo at 0x10abd3048>]

    def best_stratety(order):
        return max(promo(order) for promo in promos)

print(Order(ann, clothing, best_stratety))  #<Order total: 2160.00 due: 1728.00>
'''
   我们可以创建一个类,管理所有命令,并且将其实例重写为可调用对象
'''

class MacroCommand:
    def __init__(self, commands):
        self.commands = list(commands)

    def __call__(self):
        for command in self.commands:
            command()

 

一等对象

'''
    在python中,"一等对象"指的是满足下述条件的程序实体:
    (1)在运行时创建
    (2)能赋值给变量或数据结构中的元素
    (3)能作为参数传给函数
    (4)能作为函数的返回结果

    整数、字符串和字典都是一等对象。在面向对象编程中,函数也是对象,并满足以上条件,所以函数也是一等对象,称为"一等函数"
'''


if __name__ == "__main__":
    # 函数的一等性质
    def foo(n):
        '''returns  n!'''
        return 1 if n < 2 else n * foo(n-1)

    print(foo(5))    # 120

    my_foo = foo
    print(my_foo)    # <function foo at 0x1010e3f28> 能赋值给变量
    print(list(map(my_foo, range(6))))   # [1, 1, 2, 6, 24, 120]   能赋值给函数

    def foo2():
        return foo

    my_foo2 = foo2()
    print(my_foo2(5))     # 120 可作为函数的返回结果

 

经典的“策略”模式

'''
    经典的策略模式:
        封装一系列可以互相替代的算法,使得算法可以独立与使用它的客户而变化。


    假设当代商城某服装店有以下三种打折规则:
        1、对于会员,全部商品8.5折
        2、同一件商品买两件及以上,除第一件外,剩余的7.5折
        3、买上5件不同商品,全部商品打8折
    三种规则只能享受一个。
'''


from abc import ABC, abstractmethod
from collections import namedtuple

Customer = namedtuple('Customer', 'name vip')     # 消费者对象


class Clothing:                # 服装类

    def __init__(self, name, quantity, price):
        self.name = name
        self.quantity = quantity
        self.price = price

    def total(self):
        return self.price * self.quantity


class Order:  # 订单类

    def __init__(self, customer, clothing, promotion=None):
        self.customer = customer
        self.clothing = list(clothing)
        self.promotion = promotion

    def total(self):
        if not hasattr(self, '__total'):
            self.__total = sum(item.total() for item in self.clothing)
        return self.__total

    def due(self):
        if self.promotion is None:
            discount = 0
        else:
            discount = self.promotion.discount(self)
        return self.total() - discount

    def __repr__(self):
        fmt = '<Order total: {:.2f} due: {:.2f}>'
        return fmt.format(self.total(), self.due())


class Promotion(ABC):  # 创建三种折扣的基类

    @abstractmethod
    def discount(self, order):
        ''':returns 计算折扣'''


class VipPromo(Promotion):  # 会员折扣
    """:returns 会员8.5折"""

    def discount(self, order):
        return order.total() * .15 if order.customer.vip  else 0


class TwoPromo(Promotion):  # 第二个
    ''':returns 同一件衣服两件以上,第二件及之后的7.5折'''

    def discount(self, order):
        discount = 0
        for item in order.clothing:
            if item.quantity >= 2:
                discount  = (item.total() - item.price) * .25
        return discount


class FivePromo(Promotion):  # 5种以上
    """ :returns 买5种不同服装以上,每件8折"""

    def discount(self, order):
        distinct_items = {item.name for item in order.clothing}
        if len(distinct_items) >= 5:
            return order.total() * .2
        return 0


if __name__ == "__main__":
    # 创建消费者
    joe = Customer('John Doe', 0)  # 非会员
    ann = Customer('Ann Smith', 1) # 会员

    # 创建购物车
    clothing = [Clothing('pants', 6, 200),
                Clothing('skirt', 1, 150),
                Clothing('shoes', 2, 230)]
    print(Order(joe, clothing, VipPromo()))  #   <Order total: 1810.00 due: 1810.00>    不是会员,不打折
    print(Order(ann, clothing, VipPromo()))  #   <Order total: 1810.00 due: 1538.50>    会员,打85折


    print(Order(joe, clothing, TwoPromo()))  # <Order total: 1810.00 due: 1502.50>   两件以上7.5折
    print(Order(joe, clothing, FivePromo())) # <Order total: 1810.00 due: 1810.00>   没到5种不打折

    clothing.extend([Clothing('shirt', 1, 90), Clothing('bra', 2, 130)])
    print(Order(joe, clothing, FivePromo())) # <Order total: 2160.00 due: 1728.00>  刚好5种打8折
'''
    下面使用函数完成"经典"策略
'''

from abc import ABC, abstractmethod
from collections import namedtuple

Customer = namedtuple('Customer', 'name vip')     # 消费者对象


class Clothing:                # 服装类

    def __init__(self, name, quantity, price):
        self.name = name
        self.quantity = quantity
        self.price = price

    def total(self):
        return self.price * self.quantity


class Order:  # 订单类

    def __init__(self, customer, clothing, promotion=None):
        self.customer = customer
        self.clothing = list(clothing)
        self.promotion = promotion

    def total(self):
        if not hasattr(self, '__total'):
            self.__total = sum(item.total() for item in self.clothing)
        return self.__total

    def due(self):
        if self.promotion is None:
            discount = 0
        else:
            discount = self.promotion(self)
        return self.total() - discount

    def __repr__(self):
        fmt = '<Order total: {:.2f} due: {:.2f}>'
        return fmt.format(self.total(), self.due())



def VipPromo(order):  # 会员折扣
    return order.total() * .15 if order.customer.vip  else 0


def TwoPromo(order):  # 第二个
    discount = 0
    for item in order.clothing:
        if item.quantity >= 2:
            discount  = (item.total() - item.price) * .25
    return discount


def FivePromo(order):  # 5种以上
    distinct_items = {item.name for item in order.clothing}
    if len(distinct_items) >= 5:
        return order.total() * .2
    return 0



if __name__ == "__main__":
    # 创建消费者
    joe = Customer('John Doe', 0)  # 非会员
    ann = Customer('Ann Smith', 1) # 会员

    # 创建购物车
    clothing = [Clothing('pants', 6, 200),
                Clothing('skirt', 1, 150),
                Clothing('shoes', 2, 230)]
    print(Order(joe, clothing, VipPromo))  #   <Order total: 1810.00 due: 1810.00>    不是会员,不打折
    print(Order(ann, clothing, VipPromo))  #   <Order total: 1810.00 due: 1538.50>    会员,打85折


    print(Order(joe, clothing, TwoPromo))  # <Order total: 1810.00 due: 1502.50>   两件以上7.5折
    print(Order(joe, clothing, FivePromo)) # <Order total: 1810.00 due: 1810.00>   没到5种不打折

    clothing.extend([Clothing('shirt', 1, 90), Clothing('bra', 2, 130)])
    print(Order(joe, clothing, FivePromo)) # <Order total: 2160.00 due: 1728.00>  刚好5种打8折
    promos = [VipPromo, TwoPromo, FivePromo]


    def best_stratety(order):
        return max(promo(order) for promo in promos)


    print(Order(joe, clothing, best_stratety))   # <Order total: 2160.00 due: 1728.00>  自动选择最优的策略
'''
    使用globals函数找出当前的全局号。其返回的是字典格式
'''
promos = [globals()[name] for name in globals()
              if name.endswith("Promo")]

    print(promos)   #  找到了三个策略函数 [<function FivePromo at 0x10c363b70>, <function TwoPromo at 0x10c363ae8>, <function VipPromo at 0x10abd3048>]

    def best_stratety(order):
        return max(promo(order) for promo in promos)

print(Order(ann, clothing, best_stratety))  #<Order total: 2160.00 due: 1728.00>
'''
   我们可以创建一个类,管理所有命令,并且将其实例重写为可调用对象
'''

class MacroCommand:
    def __init__(self, commands):
        self.commands = list(commands)

    def __call__(self):
        for command in self.commands:
            command()

 

本文主要内容

经典的“策略”模式

 

python高级——目录

文中代码均放在github上:

 

本文主要内容

一等对象

普通函数 & 高阶函数

可调用对象 & 自定义可调用类型

  函数内省

  函数注释

 

python高级——目录

文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级

 

python高级系列文章目录

python高级——目录

 

python高级系列文章目录

python高级(六)——用一等函数实现设计模式。python高级——目录

 

本文主要内容 经典的“策略”模式 python高级——目录 文中代码均放在githu...

函数注释

'''
    函数注解很简单,用下面例子简单讲解即可明了
'''


if __name__ == "__main__":
    def foo(num: int, step: 'int 间隔(大于0小于num)'=1) -> int:
        ''':returns 求num的阶乘,可以设置步长'''     # 这里的注释存储在__doc__中
        return num if num <= step else num * foo(num-step,step)

    print(foo(5))  # 120   (5*4*3*2*1)
    print(foo(5, 2))  # 15 (5*3)

    # 函数声明中的各个参数可以在冒号(:)之后增加注释,该注释可以直接写参数类型,也可以写字符串
    # -> 符号后面是对函数返回值进行注解

    # 这些注释内容存储在属性 __annotations__中
    print(foo.__annotations__)  # {'step': 'int 间隔(大于0小于num)', 'num': <class 'int'>, 'return': <class 'int'>}

    # 这样注释后,在使用pycharm时会出现自动提示

 

 

 

python高级(六)——用一等函数实现设计模式,python设计模式

python高级(六)——用一等函数实现设计模式。普通函数 & 高阶函数

'''
    我们一般将函数分为"普通函数"和"高阶函数",接受函数为参数的函数为高阶函数,其余为普通函数

    普通函数大家再熟悉不过,本文不讲,主要讲一下map、filter、reduce三个高阶函数
'''


if __name__ == "__main__":
    # map第一个参数接受一个函数,并将这个函数作用于后面可迭代对象的每一个元素中
    l = map(lambda x : x ** 2, range(11))   # 返回的是生成器类型
    print(list(l))     # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    w = map(str.upper, 'asfafasfasfaf')
    print(list(w))     # ['A', 'S', 'F', 'A', 'F', 'A', 'S', 'F', 'A', 'S', 'F', 'A', 'F']

    # filter第一个参数也接受函数,并返回所有满足该函数的元素
    l = filter(lambda n: n % 2, range(10))   # 返回n % 2为真的数,就是奇数
    l2 = filter(lambda n: n % 2 ==0, range(10))  # 返回偶数
    print(list(l))                           # [1, 3, 5, 7, 9]
    print(list(l2))                          # [0, 2, 4, 6, 8]

    # reduce 从python3开始,reduce放在functools中
    # reduce将某个操作连续应用到序列元素上,即其会将前一步的结果继续应用到下一个元素上
    from functools import reduce
    s = reduce(lambda x,y: x   y, range(101))
    print(s)       # 5050 对1到100求和

 

 可调用对象 & 自定义可调用类型

'''
    我们在使用函数或者实例化对象的时候会用到括号(即()),这个括号实际上是调用运算符,python里面有7中可调用对象:

    1、用户定义的函数
        def和lambda创建
    2、内置函数
        使用C语言实现的函数,如len或time.strftime
    3、内置方法
        使用C语言实现的方法,如dict.get
    4、方法
        在类的定义体中定义的函数
    5、类
        调用类时其实首先运行的是__new__方法,然后运行__init__方法。这里很有意思,自定义类中其实没有重写__new__方法,
        而是调用的超类的__new__方法,如果查看源代码的实现逻辑,相信你会有新的发现,这里不做讨论。
    6、类的实例
        如果类定义了__call__方法,那么它的实例可以作为函数调用
    7、生长器函数
        使用yield关键字的函数或方法。
'''


if __name__ == "__main__":
    # 创建一个自定义可调用类
    class Foo():
        def __init__(self):
            self.name = "Foo"
        def __call__(self, *args, **kwargs):
            print("调用__call__")

    Foo()()     # 输出:调用__call__

    # 以上使用 Foo()() 这种写法看上去很有意思。首先,Foo()会创建一个Foo实例,调用__init__构造方法,; 然后使用实例(),此时
    # 调用__call__方法

 

python高级系列文章目录

python高级——目录

 

函数内省

'''
    函数内省我们通过例子来看
'''


if __name__ == "__main__":
    # 先创建一个函数
    def foo(n):
        ''':returns n!'''
        return 1 if n<2 else n*foo(n-1)

    print(foo.__doc__)   # :returns n!   __doc__里面存储了注释内容

    # 看看这个函数中有多少属性
    print(dir(foo))
    '''
        ['__annotations__', '__call__', '__class__', '__closure__', '__code__', 
        '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
        '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', 
        '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', 
        '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', 
        '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
    '''

    # 下表对一些属性做了说明
名称 类型 说明
__annotations__ dict 参数和返回值的注解
__call__ method-wrapper 实现()运算符
__closure__ tuple 函数闭包
__code__ code 编译成字节码的函数元数据和函数定义体
__defaults__ tuple 形式参数的默认值
__get__ method-wrapper 实现只读描述符协议
__globals__ dict 函数所在模块中的全局变量
__kwdefaults__ dict 仅限关键字形式参数的默认值
__name__ str 函数名称
__qualname__ str 函数的限定名称

 

本文由分分快三计划发布,转载请注明来源

关键词: 分分快三计划