Welcome to 徐小波’s blog.|

河北大学-徐小波

园龄:2年2个月粉丝:1关注:4

Python Functools模块

代码:

复制代码
#coding=utf-8

import functools
from functools import cache
from functools import cached_property, lru_cache
from functools import partial, partialmethod
from functools import singledispatch, singledispatchmethod
from functools import update_wrapper, wraps
from functools import reduce
        
#################################################################
'''
@cache装饰器
它的主要作用是提高函数的执行效率,特别是在函数被多次调用且输入参数相同的情况下,避免重复计算,
如果一个函数在相同的输入参数下被多次调用,cache 会记住第一次调用的结果,并在后续调用中直接返
回缓存的结果,而不是重新计算。

它是线程安全的,因此可以在多个线程中使用。
'''
def func_test_no_cache(n):
    print("执行no-cache")
    return n
 
@cache
def func_test_cache(n):
    print("执行cache")
    return n

def test_cache():
    print("[test_cache:]")
    for i in range(3):
        func_test_no_cache(10)
        func_test_cache(10)
    print()
        
#################################################################
'''
@cached_property装饰器
用于将一个类的无参方法转换为缓存属性,意味着该方法在第一次调用时会被计算并缓存结果,
后续调用时直接返回缓存的结果。缓存的结果是实例级别的,即每个实例都有自己的缓存。即使
后续改变了方法内部涉及的类参数,输出也结果不会发生改变。
'''
class CircleCache:
    def __init__(self, radius):
        self.radius = radius
 
    @cached_property
    def area(self):
        '''
        如果类本身存在area属性,则此方法不生效。也就是本身属性读取和
        写入优先于 cached_property 方法
        '''
        print("计算面积")
        return 3.14159 * self.radius ** 2
        
def test_cached_property():
    print("[test_cached_property:]")
    # 创建 Circle 对象
    circle = CircleCache(5)
 
    # 第一次访问 area 属性时会计算并缓存结果
    print(circle.radius, circle.area)
    del circle.radius
    circle.radius = 60
    '''
    第二次访问 area 属性时直接返回缓存的结果,即使是中途改变了圆的半径
    或者是删除了参与计算的参数。
    '''
    print(circle.radius, circle.area)
    print()

#################################################################
'''
@lru_cache装饰器
lru_cache相较于cached_property,它装饰的方法是可以带参数的。
'''
class CircleLru:
    def __init__(self, radius):
        self.radius = radius
 
    @lru_cache(maxsize=128)  # 缓存最大容量
    def area(self, precision):
        '''
        如果类本身存在area属性,则此方法不生效。也就是
        本身属性读取和写入优先于 cached_property 方法
        '''
        print("计算面积")
        return 3.14159 * self.radius ** precision

def test_lru_cached():
    print("[test_lru_cached:]")
    # 创建 Circle 对象
    circle = CircleLru(5)
 
    # 第一次访问会计算并缓存结果
    print(circle.radius, circle.area(precision=2))
    '''
    第二次访问如果输入参数相同,则直接返回缓存的结果,如果
    输入参数不同,则重新计算并缓存。
    '''
    print(circle.radius, circle.area(precision=3))
    print(circle.radius, circle.area(precision=3))
    print(circle.radius, circle.area(precision=2))
    print()

#################################################################
class TestProperty:
    @property
    def test(self):
        print("TestProperty.test执行了")
        return 1

def test_property():
    print("[test_property:]")
    testProperty = TestProperty()
    print("TestProperty.test=%s" % testProperty.test)
    print()
    
#################################################################
'''
partial函数
它允许你固定一个或多个参数,从而创建一个新的函数,这个新函数在调用时只需要提供剩余的参数。
'''
# 计算一个数的幂
def power1(base, exponent1):
    return base ** exponent1

def power2(base, exponent1, exponent2):
    return base ** exponent1 + exponent2

def test_partial():
    print("[test_partial:]")
    square = partial(power1, exponent1=2)
    print(square(3))  # 输出: 9
    print(square(4))  # 输出: 16
    
    square = partial(power2, exponent1=2, exponent2=3)
    print(square(3))  # 输出: 12
    print(square(4))  # 输出: 19
    print()
    
#################################################################
'''
partialmethod函数
它与 partial 类似,但更适合用于类方法,因为它会正确处理 self 参数。
'''
class Demo1:
    def __init__(self, value):
        self.value = value
 
    def get_something(self, name, age):
        return (self.value, name, age)
 
    # 使用 partialmethod 定义一个部分应用的方法
    get_something_with_default = partialmethod(get_something, name="长期", age=16)

def test_partialmethod():
    print("[test_partialmethod:]")
    demo1 = Demo1(value=1)
    print(demo1.get_something(name=1, age=2))
    print(demo1.get_something_with_default())
    print()
    
#################################################################
'''
@singledispatch装饰器
它用于实现函数的多态性,即根据函数的第一个参数的类型来决定调用哪个具体的实现。singledispatch 允许
你为一个函数定义多个实现,每个实现对应不同的参数类型。
'''
# 定义一个通用的函数
@singledispatch
def process(arg):
    return f"Processing generic argument: {arg}"
 
 
# 为 int 类型定义一个特定的实现
@process.register
def _(arg: int):
    return f"Processing integer: {arg}"
 
 
# 为 str 类型定义一个特定的实现
@process.register(str)
def _(arg):
    return f"Processing string1: {arg}"

'''
@process.register
def _(arg: str):
    return f"Processing string2: {arg}"
'''


# 为 list 类型定义一个特定的实现
@process.register
def _(arg: list):
    return f"Processing list: {arg}"
 
 
def test_singledispatch():
    # 调用不同类型的参数
    print("[test_singledispatch:]")
    print(process(10))  # 输出: Processing integer: 10
    print(process("hello"))  # 输出: Processing string: hello
    print(process([1, 2, 3]))  # 输出: Processing list: [1, 2, 3]
    print(process(3.14))  # 输出: Processing generic argument: 3.14
    print()
    
#################################################################
'''
@singledispatchmethod装饰器
它与 singledispatch 类似,但专门用于类方法(class methods)
'''
class Demo2:
    @singledispatchmethod
    def process(self, arg):
        return f"Processing generic argument: {arg}"
 
    @process.register
    def _(self, arg: int):
        return f"Processing integer: {arg}"
 
    @process.register
    def _(self, arg: str):
        return f"Processing string2: {arg}"
 
    @process.register(str)
    def _(self, arg):
        return f"Processing string1: {arg}"
 
    @process.register
    def _(self, arg: list):
        return f"Processing list: {arg}"
 
 
def test_singledispatchmethod():
    print("[test_singledispatchmethod:]")
    # 创建类的实例
    demo = Demo2()
    
    # 调用不同类型的参数
    print(demo.process(10))  # 输出: Processing integer: 10
    print(demo.process("hello"))  # 输出: Processing string: hello
    print(demo.process([1, 2, 3]))  # 输出: Processing list: [1, 2, 3]
    print(demo.process(3.14))  # 输出: Processing generic argument: 3.14
    print()
    
#################################################################
def my_decorator1(func):
    def wrapper(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)
        print("After function call")
        return result
 
    # 使用 update_wrapper 更新 wrapper 的元数据
    update_wrapper(wrapper, func)
    return wrapper
 
 
@my_decorator1
def my_function1():
    """函数内注释内容111"""
    print("Inside my function")
 

def test_update_wrapper():
    print("[test_update_wrapper:]")
    # 调用被装饰的函数
    my_function1()
    print()
     
    # 检查被装饰函数的元数据
    print(my_function1.__name__)  # 输出: my_function
    print(my_function1.__doc__)  # 输出: This is my function.
    print()
    
#################################################################
'''
为了简化代码,functools 模块还提供了一个 wraps 装饰器,它实际上是 update_wrapper 的快捷方式。
你可以使用 wraps 装饰器来代替手动调用 update_wrapper。
'''
def my_decorator2(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)
        print("After function call")
        return result
 
    return wrapper
 
 
@my_decorator2
def my_function2():
    """函数内注释内容222"""
    print("Inside my function")
 
def test_wraps():
    print("[test_wraps:]")
    # 调用被装饰的函数
    my_function2()
    print()
     
    # 检查被装饰函数的元数据
    print(my_function2.__name__)  # 输出: my_function
    print(my_function2.__doc__)  # 输出: This is my function.
    print()
    
#################################################################
'''
Functools.reduce的应用
functools.reduce函数用于对可迭代对象中的元素进行累积操作。它将一个二元函数(接受两个参数的函数)
应用于序列的所有元素,以便从左到右累积它们。
'''
def test_reduce():
    print("[test_reduce:]")
    # 使用functools.reduce计算阶乘
    xs = [i for i in range(1, 6)]
    print(xs)
    factorial1 = reduce(lambda x, y: x * y, xs)
    factorial2 = reduce(lambda x, y: x + y, xs)
    # 输出120,即5的阶乘
    print(factorial1)
    print(factorial2)
    print()
    
#################################################################
'''
函数过滤:Functools.filterfalse的妙用
'''
def test_filterfalse():
    print("[test_filterfalse:]")
    # 使用functools.filterfalse筛选出奇数
    is_even = lambda x: x % 2 == 0
    even_numbers = []
    try:
        even_numbers = list(functools.filterfalse(is_even, range(10)))
        # 输出[1, 3, 5, 7, 9],即奇数
        print(even_numbers)
    except Exception as e:
        print(e)
    print()
    
#################################################################
'''
自定义排序:Functools.cmp_to_key的魔力
functools.cmp_to_key函数用于将比较函数(接受两个参数并返回负数、零或正数
的函数)转换为关键函数,以便用于排序操作
'''
# 自定义比较函数,按长度排序
def compare_length(s1, s2):
    return len(s2) - len(s1)

def test_cmp_to_key():
    print("[test_cmp_to_key:]")
    words = ["apple", "banana", "cherry", "date"]
    sorted_words = sorted(words, key=functools.cmp_to_key(compare_length))
    
    # 输出按长度排序的单词列表
    print(sorted_words)
    print()
    
#################################################################
'''
函数调用计数:Functools.total_ordering的精妙之处
functools.total_ordering是一个装饰器,它为类定义了一些特殊方法,以便使用比较操作符(如<、<=、>、>=)进行
对象比较。可以定义自定义类,支持完整的比较操作。
'''
@functools.total_ordering
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.age == other.age

    def __lt__(self, other):
        return self.age < other.age

def test_total_ordering():
    print("[test_total_ordering:]")
    # 创建两个Person对象
    person1 = Person("Alice", 30)
    person2 = Person("Bob", 25)
    
    # 使用比较操作符进行对象比较
    print(person1 < person2)  # 输出False
    print(person1 > person2)  # 输出True
    print()
    

if __name__ == '__main__':
    test_cache()
    test_cached_property()
    test_lru_cached()
    test_property()
    
    test_partial()
    test_partialmethod()
    
    test_singledispatch()
    test_singledispatchmethod()
    
    test_update_wrapper()
    test_wraps()
    
    test_reduce()
    test_filterfalse()
    test_cmp_to_key()
    test_total_ordering()
    
    pass
复制代码

 

输出:

复制代码
[test_cache:]
执行no-cache
执行cache
执行no-cache
执行no-cache

[test_cached_property:]
计算面积
5 78.53975
60 78.53975

[test_lru_cached:]
计算面积
5 78.53975
计算面积
5 392.69874999999996
5 392.69874999999996
5 78.53975

[test_property:]
TestProperty.test执行了
TestProperty.test=1

[test_partial:]
9
16
12
19

[test_partialmethod:]
(1, 1, 2)
(1, '长期', 16)

[test_singledispatch:]
Processing integer: 10
Processing string1: hello
Processing list: [1, 2, 3]
Processing generic argument: 3.14

[test_singledispatchmethod:]
Processing integer: 10
Processing string1: hello
Processing list: [1, 2, 3]
Processing generic argument: 3.14

[test_update_wrapper:]
Before function call
Inside my function
After function call

my_function1
函数内注释内容111

[test_wraps:]
Before function call
Inside my function
After function call

my_function2
函数内注释内容222

[test_reduce:]
[1, 2, 3, 4, 5]
120
15

[test_filterfalse:]
module 'functools' has no attribute 'filterfalse'

[test_cmp_to_key:]
['banana', 'cherry', 'apple', 'date']

[test_total_ordering:]
False
True
复制代码

 

posted @   河北大学-徐小波  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起