Python3:装饰器、生成器与迭代器

Python3:装饰器、生成器与迭代器

    • 一、🎭 装饰器:给函数穿上"魔法外衣"
      • 装饰器基本概念
      • 为装饰器添加参数传递功能
      • 带参数的装饰器
      • functools.wraps:保留原函数的元信息
      • 实用装饰器示例
        • 1. 计时器装饰器
        • 2. 缓存装饰器(Memoization)
        • 3. 权限检查装饰器
        • 4. 类方法装饰器
        • 5. 类装饰器
    • 二、🔄 迭代器:数据流的"传送带"
      • 迭代器基本概念
      • 内置迭代器工具
    • 🌱 生成器:懒惰的迭代器
      • 生成器函数
      • 生成器表达式
      • 生成器的内存效率
      • 生成器的进阶特性
        • 1. 双向通信:send() 方法
        • 2. 生成器的异常处理:throw() 和 close()
        • 3. 委托生成器:yield from
      • 实用生成器示例
        • 1. 文件读取生成器
        • 2. 无限素数生成器
        • 3. 数据流处理管道
    • 三、🔗 将装饰器、迭代器和生成器结合使用
      • 装饰生成器函数
      • 可重用的迭代器类
    • 四、 📊 实际应用案例:数据分析管道
    • 总结
      • 1. 装饰器
      • 2. 迭代器
      • 3. 生成器
    • 练习建议

一、🎭 装饰器:给函数穿上"魔法外衣"

想象一下,如果函数是演员,装饰器就是能瞬间更换的戏服,让演员不改变本身,却能展现出全新的能力和特性。

装饰器基本概念

装饰器是一个接收函数作为参数并返回一个新函数的高阶函数,它能在不修改原函数代码的情况下,增强原函数的功能。

# 最简单的装饰器
def simple_decorator(func):def wrapper():print("🌟 函数执行前")func()print("🌟 函数执行后")return wrapper# 使用装饰器
@simple_decorator
def say_hello():print("Hello, World!")# 调用被装饰的函数
say_hello()
# 输出:
# 🌟 函数执行前
# Hello, World!
# 🌟 函数执行后

这里的@simple_decorator语法糖等同于:

say_hello = simple_decorator(say_hello)

为装饰器添加参数传递功能

实际使用中,原函数通常有参数,我们需要确保装饰器能正确传递这些参数:

def smart_decorator(func):def wrapper(*args, **kwargs):print(f"🔍 调用函数: {func.__name__}")result = func(*args, **kwargs)print(f"✅ 函数返回: {result}")return resultreturn wrapper@smart_decorator
def add(a, b):return a + bprint(add(3, 5))  # 使用装饰器包装的函数
# 输出:
# 🔍 调用函数: add
# ✅ 函数返回: 8
# 8

带参数的装饰器

如果我们想让装饰器本身也能接收参数,需要再包装一层函数:

def repeat(times):def decorator(func):def wrapper(*args, **kwargs):result = Nonefor _ in range(times):result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeat(times=3)
def greet(name):print(f"你好, {name}!")return "打招呼完成"greet("小明")
# 输出:
# 你好, 小明!
# 你好, 小明!
# 你好, 小明!

functools.wraps:保留原函数的元信息

默认情况下,装饰器会替换原函数,导致原函数的名称、文档字符串等元信息丢失。使用functools.wraps可以解决这个问题:

import functoolsdef my_decorator(func):@functools.wraps(func)  # 保留原函数的元信息def wrapper(*args, **kwargs):"""这是包装函数的文档"""print("Before function call")result = func(*args, **kwargs)print("After function call")return resultreturn wrapper@my_decorator
def example():"""这是原函数的文档"""print("Inside the function")print(example.__name__)  # 输出: example (而不是 wrapper)
print(example.__doc__)   # 输出: 这是原函数的文档

实用装饰器示例

1. 计时器装饰器
import time
import functoolsdef timer(func):@functools.wraps(func)def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)end_time = time.time()print(f"⏱️ 函数 {func.__name__} 执行耗时: {end_time - start_time:.4f} 秒")return resultreturn wrapper@timer
def slow_function():time.sleep(1)return "函数执行完成"slow_function()
# 输出: ⏱️ 函数 slow_function 执行耗时: 1.0012 秒
2. 缓存装饰器(Memoization)
def memoize(func):cache = {}@functools.wraps(func)def wrapper(*args):if args in cache:print(f"💾 使用缓存结果: {args}")return cache[args]result = func(*args)cache[args] = resultprint(f"📝 缓存新结果: {args} -> {result}")return resultreturn wrapper@memoize
def fibonacci(n):if n <= 1:return nreturn fibonacci(n-1) + fibonacci(n-2)print(fibonacci(10))
# 首次计算会缓存所有中间结果
print(fibonacci(10))  # 第二次直接使用缓存
3. 权限检查装饰器
def require_auth(role):def decorator(func):@functools.wraps(func)def wrapper(user, *args, **kwargs):if user.get('role') != role:raise PermissionError(f"需要 {role} 权限!")return func(user, *args, **kwargs)return wrapperreturn decorator@require_auth(role="admin")
def delete_user(current_user, user_id):print(f"用户 {user_id} 已被删除")# 测试权限
admin_user = {'name': 'Admin', 'role': 'admin'}
normal_user = {'name': 'User', 'role': 'user'}delete_user(admin_user, 123)  # 正常执行
try:delete_user(normal_user, 123)  # 抛出权限错误
except PermissionError as e:print(f"错误: {e}")
4. 类方法装饰器

装饰器也可以用于类方法:

def log_method_calls(func):@functools.wraps(func)def wrapper(self, *args, **kwargs):print(f"📞 调用方法 {self.__class__.__name__}.{func.__name__}")return func(self, *args, **kwargs)return wrapperclass Calculator:def __init__(self, name):self.name = name@log_method_callsdef add(self, a, b):return a + b@log_method_callsdef multiply(self, a, b):return a * bcalc = Calculator("科学计算器")
calc.add(5, 3)      # 输出: 📞 调用方法 Calculator.add
calc.multiply(5, 3) # 输出: 📞 调用方法 Calculator.multiply
5. 类装饰器

装饰器不仅可以装饰函数,还可以装饰整个类:

def add_greeting(cls):# 给类添加一个新方法def say_hello(self):return f"{self.name} 说:你好!"cls.say_hello = say_helloreturn cls@add_greeting
class Person:def __init__(self, name):self.name = namep = Person("张三")
print(p.say_hello())  # 输出: 张三 说:你好!

二、🔄 迭代器:数据流的"传送带"

迭代器基本概念

迭代器是一种特殊的对象,它实现了迭代协议,允许我们逐个访问集合中的元素,而不需要知道集合的底层结构。

在Python中,迭代器需要实现两个方法:

  • __iter__(): 返回迭代器对象本身
  • __next__(): 返回下一个元素,如果没有更多元素则抛出StopIteration异常
# 简单迭代器示例
class CountDown:def __init__(self, start):self.current = startdef __iter__(self):# 返回迭代器对象自身return selfdef __next__(self):# 如果计数结束,抛出StopIterationif self.current <= 0:raise StopIteration# 否则返回当前值并递减value = self.currentself.current -= 1return value# 使用for循环遍历迭代器
for num in CountDown(5):print(num)
# 输出: 5 4 3 2 1# 手动使用迭代器
iterator = iter(CountDown(3))  # 调用__iter__()
print(next(iterator))  # 3     # 调用__next__()
print(next(iterator))  # 2
print(next(iterator))  # 1
# print(next(iterator))  # 抛出StopIteration异常

内置迭代器工具

Python的itertools模块提供了许多强大的迭代器工具:

import itertools# 无限迭代器
counter = itertools.count(1)  # 从1开始计数
print([next(counter) for _ in range(5)])  # [1, 2, 3, 4, 5]# 循环迭代器
cycle = itertools.cycle(["红", "黄", "绿"])
print([next(cycle) for _ in range(5)])  # ['红', '黄', '绿', '红', '黄']# 重复迭代器
repeat = itertools.repeat("A", 3)
print(list(repeat))  # ['A', 'A', 'A']# 链接多个迭代器
chain = itertools.chain([1, 2], [3, 4], [5, 6])
print(list(chain))  # [1, 2, 3, 4, 5, 6]# 分组迭代器
data = ["苹果", "梨", "菠萝", "葡萄", "芒果"]
for k, group in itertools.groupby(sorted(data), key=len):print(f"{k}个字符: {list(group)}")
# 输出:
# 1个字符: ['梨']
# 2个字符: ['苹果', '菠萝', '芒果', '葡萄']# 排列组合
print(list(itertools.combinations("ABC", 2)))  # [('A', 'B'), ('A', 'C'), ('B', 'C')]
print(list(itertools.permutations("ABC", 2)))  # [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]

🌱 生成器:懒惰的迭代器

生成器是一种特殊的迭代器,它使用函数的方式创建,通过yield关键字返回值,并保存函数的执行状态,等待下次调用。

生成器函数

使用yield关键字的函数会变成生成器函数,调用时返回一个生成器对象:

def countdown(n):print("开始倒计时!")while n > 0:yield n  # 返回当前值并暂停函数执行n -= 1# 创建生成器对象
generator = countdown(3)
print(type(generator))  # <class 'generator'># 迭代生成器
print(next(generator))  # 开始倒计时! 3
print(next(generator))  # 2
print(next(generator))  # 1
# print(next(generator))  # StopIteration异常# 使用for循环更方便
for num in countdown(3):print(num)
# 输出:
# 开始倒计时!
# 3
# 2
# 1

生成器表达式

类似于列表推导式,但使用圆括号而不是方括号:

# 列表推导式:立即计算所有结果并存储在内存中
squares_list = [x**2 for x in range(5)]
print(squares_list)  # [0, 1, 4, 9, 16]# 生成器表达式:按需计算
squares_gen = (x**2 for x in range(5))
print(squares_gen)  # <generator object <genexpr> at 0x...># 使用生成器
for square in squares_gen:print(square)  # 0 1 4 9 16

生成器的内存效率

生成器的主要优势是内存效率,特别是处理大数据集时:

import sys# 比较列表和生成器的内存使用
def get_size(obj):return sys.getsizeof(obj)# 创建一个大范围
big_range = 10**6# 使用列表
big_list = [x for x in range(big_range)]
print(f"列表大小: {get_size(big_list)} 字节")# 使用生成器
big_gen = (x for x in range(big_range))
print(f"生成器大小: {get_size(big_gen)} 字节")# 虽然两者都可以提供相同的数字序列,但内存占用差异巨大

生成器的进阶特性

1. 双向通信:send() 方法

生成器不仅可以产生值,还可以接收外部发送的值:

def echo_generator():while True:received = yield "等待输入..."  # yield一个值,然后等待send()的输入if received == 'exit':breakyield f"你说: {received}"  # 返回处理后的输入# 创建生成器
echo = echo_generator()
print(next(echo))  # 启动生成器: "等待输入..."print(echo.send("你好"))  # 发送值并获取下一个yield的值: "你说: 你好"
print(next(echo))  # "等待输入..."
print(echo.send("Python"))  # "你说: Python"
print(next(echo))  # "等待输入..."
echo.send("exit")  # 结束生成器
2. 生成器的异常处理:throw() 和 close()

生成器可以接收和处理外部抛入的异常:

def number_generator():try:for i in range(5):yield iexcept ValueError:print("捕获到ValueError!")yield "错误处理完毕"finally:print("生成器清理资源...")gen = number_generator()
print(next(gen))  # 0
print(next(gen))  # 1
print(gen.throw(ValueError))  # 抛出异常,输出: 捕获到ValueError! 错误处理完毕
gen.close()  # 关闭生成器,触发finally: 生成器清理资源...
3. 委托生成器:yield from

yield from允许一个生成器委托给另一个生成器:

def subgenerator(n):for i in range(n):yield i * idef delegating_generator():# 等同于迭代subgenerator并yield每个值yield from subgenerator(5)yield "子生成器完成"for value in delegating_generator():print(value)
# 输出: 0 1 4 9 16 子生成器完成

实用生成器示例

1. 文件读取生成器

逐行读取大文件而不将整个文件载入内存:

def read_large_file(file_path):with open(file_path, 'r') as file:for line in file:yield line.strip()# 使用示例
# for line in read_large_file("very_large_file.txt"):
#     process(line)
2. 无限素数生成器
def is_prime(n):"""检查一个数是否为素数"""if n <= 1:return Falseif n <= 3:return Trueif n % 2 == 0 or n % 3 == 0:return Falsei = 5while i * i <= n:if n % i == 0 or n % (i + 2) == 0:return Falsei += 6return Truedef infinite_primes():"""无限生成素数"""num = 2while True:if is_prime(num):yield numnum += 1# 获取前10个素数
prime_gen = infinite_primes()
first_10_primes = [next(prime_gen) for _ in range(10)]
print(first_10_primes)  # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
3. 数据流处理管道

使用生成器构建数据处理管道:

def read_data():data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]for item in data:yield itemdef filter_even(items):for item in items:if item % 2 == 0:yield itemdef multiply_by_2(items):for item in items:yield item * 2def pipeline():# 构建处理管道result = multiply_by_2(filter_even(read_data()))return list(result)print(pipeline())  # [4, 8, 12, 16, 20]

三、🔗 将装饰器、迭代器和生成器结合使用

这些高级特性可以很好地结合使用,创建更强大的功能:

装饰生成器函数

def debug_generator(func):@functools.wraps(func)def wrapper(*args, **kwargs):gen = func(*args, **kwargs)for value in gen:print(f"🔍 生成器 {func.__name__} 产生: {value}")yield valuereturn wrapper@debug_generator
def counting(n):for i in range(n):yield i# 使用被装饰的生成器
for num in counting(3):print(f"使用值: {num}")
# 输出:
# 🔍 生成器 counting 产生: 0
# 使用值: 0
# 🔍 生成器 counting 产生: 1
# 使用值: 1
# 🔍 生成器 counting 产生: 2
# 使用值: 2

可重用的迭代器类

创建一个更复杂的可重用迭代器类:

class DataProcessor:def __init__(self, data):self.data = dataself.index = 0def __iter__(self):return selfdef __next__(self):if self.index >= len(self.data):raise StopIterationresult = self.process(self.data[self.index])self.index += 1return resultdef process(self, item):# 可在子类中重写的处理方法return item# 通过继承扩展功能
class SquareProcessor(DataProcessor):def process(self, item):return item ** 2# 使用迭代器
numbers = [1, 2, 3, 4, 5]
processor = SquareProcessor(numbers)
print(list(processor))  # [1, 4, 9, 16, 25]

四、 📊 实际应用案例:数据分析管道

结合所有概念创建一个数据处理管道:

import time
import functools# 装饰器:用于性能监控
def monitor(func):@functools.wraps(func)def wrapper(*args, **kwargs):start = time.time()result = func(*args, **kwargs)end = time.time()print(f"⏱️ {func.__name__} 处理耗时: {end - start:.4f}秒")return resultreturn wrapper# 生成器:数据读取
@monitor
def read_data(filename):"""模拟从文件读取数据"""print(f"📂 从{filename}读取数据...")# 模拟数据data = [{"id": 1, "name": "Product A", "price": 100, "category": "Electronics"},{"id": 2, "name": "Product B", "price": 50, "category": "Clothing"},{"id": 3, "name": "Product C", "price": 150, "category": "Electronics"},{"id": 4, "name": "Product D", "price": 80, "category": "Home"},{"id": 5, "name": "Product E", "price": 200, "category": "Electronics"}]time.sleep(0.1)  # 模拟I/O延迟for item in data:yield item# 生成器:数据过滤
@monitor
def filter_data(items, category):"""筛选特定类别的商品"""print(f"🔍 筛选{category}类别...")for item in items:if item["category"] == category:yield item# 生成器:数据转换
@monitor
def transform_data(items):"""计算商品价格的销售价(打八折)"""print("🔄 计算销售价...")for item in items:transformed = item.copy()transformed["sale_price"] = item["price"] * 0.8yield transformed# 消费生成器:保存结果
@monitor
def save_results(items, output_filename):"""保存处理后的数据"""print(f"💾 保存结果到{output_filename}...")results = list(items)  # 消耗生成器# 模拟保存操作time.sleep(0.1)print(f"✅ 已保存{len(results)}条记录")return results# 构建完整的数据处理管道
def process_sales_data(input_filename, output_filename, category):"""完整的数据处理流程"""# 构建处理管道data = read_data(input_filename)filtered_data = filter_data(data, category)transformed_data = transform_data(filtered_data)results = save_results(transformed_data, output_filename)# 打印结果示例if results:print("\n📊 处理结果示例:")for item in results[:2]:  # 只显示前两条print(f"  {item['name']}: 原价¥{item['price']}, 销售价¥{item['sale_price']:.2f}")if len(results) > 2:print(f"  ...以及其他{len(results)-2}条记录")# 执行数据处理管道
process_sales_data("products.csv", "electronics_sales.csv", "Electronics")

总结

1. 装饰器

  • 允许在不修改原函数的情况下添加新功能
  • 可以用于函数或类
  • 实用场景:日志记录、性能监控、访问控制、缓存等

2. 迭代器

  • 实现了__iter____next__方法的对象
  • 允许逐个访问集合元素,而不需要加载整个集合
  • Python内置了丰富的迭代器工具(itertools)

3. 生成器

  • 使用yield语句的特殊函数
  • 执行时会保存状态,按需生成值
  • 极大减少内存使用,适合处理大数据集
  • 高级特性:send(), throw(), close(), yield from

这三者是Python高级编程中的关键概念,掌握它们可以编写出更优雅、高效和可维护的代码。尤其在处理大量数据、构建数据处理管道或需要分布式计算时,这些概念尤为重要。

练习建议

  1. 构建装饰器库

    • 创建一组实用装饰器:计时、重试、缓存等
    • 尝试组合多个装饰器
  2. 设计自定义迭代器

    • 实现一个模拟数据库游标的迭代器
    • 创建一个分页迭代器,按批次返回数据
  3. 生成器应用

    • 实现一个大文件处理程序,使用生成器进行内存高效处理
    • 构建数据转换管道,将数据从一种格式转换为另一种格式
  4. 综合项目

    • 开发一个简单的ETL(提取-转换-加载)工具
    • 设计一个支持链式操作的数据处理框架

🚀 下一步学习:探索Python的函数式编程特性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80933.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL命令一:SQL 基础操作与建表约束

目录 引言 一、SQL 基础命令 &#xff08;一&#xff09;数据库相关操作 &#xff08;二&#xff09;表格相关操作 &#xff08;三&#xff09;MySQL 常用数据类型 二、增删改查&#xff08;CRUD&#xff09;操作 &#xff08;一&#xff09;增加数据 &#xff08;二&a…

Windows 桌面个性高效组件工具

软件介绍 Widgets 这款基于 Vue3 构建的开源 Windows 桌面小部件工具超实用。 其多样化组件库涵盖超 20 种&#xff0c;从倒计时、打工进度等实用工具&#xff0c;到抖音热榜等实时资讯组件应有尽有&#xff0c;各组件独立运行&#xff0c;满足多场景需求。 高度自定义布局支持…

PCB入门指南:从电阻到常见电路的全解析

知识点1【电阻】 常见的是 色环电阻和贴片电阻 1、色环电阻 色环电阻&#xff0c;早期是碳膜电阻&#xff0c;精度不是很高&#xff0c;一般是4个色环&#xff0c;红 橙 黄 绿 蓝 紫 灰 白 黑&#xff0c;每个颜色代表一个阻值 后期是金属膜电阻&#xff0c;5个色环&#x…

论文阅读的三个步骤

论文阅读的三个步骤 方法说明链接&#xff1a;https://www.academia.edu/4907403/How_to_Read_a_Paper 方法框架如下

Centos 7 ssh连接速度慢(耗时20秒+)

作系统&#xff1a;centos7.9 现象突然间通过 ssh、xshell等客户端工具连接时&#xff0c;连接速度缓慢&#xff0c;需要耗时20秒左右才能连接上 排查思路&#xff1a; 1. 查看操作系统日志 从系统日志里看到较多的错误&#xff0c;这个可能是一个bug &#xff08;现象类似&a…

通过脚本自动检查项目中全局的中文

现在越来越多的公司在做出海项目&#xff0c;出海项目首先要解决的就是语言国际化的问题&#xff0c;有很多如l18n、l10n的工具可以用&#xff0c;这些工具可以提供解决方案&#xff0c;但是不能约束开发者的开发行为。开发者仍然可能在代码中存留没有做过国际化处理的部分&…

软件分析师-第三遍-章节导图-13/14

系统设计&#xff0c;按步骤分&#xff1a;概要设计、详细设计。另一种分类方式&#xff1a;按设计内容和设计方法分。设计内容&#xff1a;处理流程、输入/输出原型、人机交互。设计方法&#xff1a;结构化、面向对象、设计模式。 软件实现&测试&#xff0c;分为实现、测…

通过全局交叉注意力机制和距离感知训练从多模态数据中识别桥本氏甲状腺炎|文献速递-深度学习医疗AI最新文献

Title 题目 Hashimoto’s thyroiditis recognition from multi-modal data via globalcross-attention and distance-aware training 通过全局交叉注意力机制和距离感知训练从多模态数据中识别桥本氏甲状腺炎 01 文献速递介绍 桥本氏甲状腺炎&#xff08;HT&#xff09;&a…

刀客doc:小红书商业技术负责人苍响离职

根据大厂日爆的爆料&#xff0c;小红书商业化再度迎来高层人事变动&#xff0c;原商业平台技术负责人苍响&#xff08;薯名&#xff09;&#xff0c;职级L2&#xff0c;已于本月正式离职&#xff0c;其下属团队现由电商业务负责人接管。 根据刀客doc获得的资料&#xff0c;苍响…

Manus AI多语言手写识别技术全解析:从模型架构到实战部署

简介 Manus AI作为当前多语言手写识别领域的领军技术&#xff0c;其核心创新在于融合三维卷积网络、动态特征融合引擎和混合解码系统&#xff0c;实现了对112种语言的98.7%识别准确率和8ms延迟的实时处理能力。本文将深入探讨Manus AI的架构设计、特征提取方法、数据预处理策略…

华为云Astro大屏从iotda影子设备抽取数据做设备运行状态的大屏实施步骤

目录 背景与意义 1. 准备阶段 2. IoTDA 开放影子查询API 3. Astro轻应用创建连接器 4. Astro大屏设计界面 5. 数据绑定与交互逻辑 6. 发布与测试 小结&#xff08;流程复盘&#xff09; 背景与意义 随着物联网技术的快速发展&#xff0c;越来越多的设备接入云端&#x…

为什么要学习《易经》?

《易经》精华解读&#xff1a;变易之道与人生智慧 《易经》&#xff08;《周易》&#xff09;是中国最古老的经典之一&#xff0c;被誉为“群经之首&#xff0c;大道之源”。它不仅是占卜之书&#xff0c;更是一部哲学经典&#xff0c;揭示了宇宙运行的规律和人生处世的智慧。…

逆传播AIGEO营销:破局生成式搜索时代,让AI成为品牌代言人!

当GS(Generative Search生成式搜索)成为用户的新“搜索入口”&#xff0c;你的品牌还在进行传统软文发布吗? Gartner分析师预测"到2026年70%企业将把生成式AI整合进核心营销系统"&#xff0c;传统SEO的正被AI搜索彻底重构。用户的搜索行为发生史诗级转变&#xff0…

WPF(Windows Presentation Foundation)的内容模型

WPF&#xff08;Windows Presentation Foundation&#xff09;的内容模型&#xff08;Content Model&#xff09;是其核心架构之一&#xff0c;定义了UI元素如何组织和呈现内容。以下是WPF内容模型的系统化解析&#xff1a; 1. 内容模型基础概念 WPF通过逻辑树和可视化树管理内…

52.[前端开发-JS实战框架应用]Day03-AJAX-插件开发-备课项目实战-Lodash

常用JavaScript库 1 认识前端工具库 前端工具类库 2 Lodash vs underscore underscore库 VS Lodash库 Lodash库 的安装 手写精简版的Lodash ;(function(g) {function Lodash() {}// 添加类方法Lodash.VERSION 1.0.0Lodash.join function(arr, separater) {// todo ......…

前端Ui设计工具

PS 稿、蓝湖、Sketch 和 Figma 前端 UI 设计工具的对比分析 PS 稿&#xff08;Adobe Photoshop&#xff09; 提供精准设计细节&#xff1a;PS 稿能让前端更精准地理解页面布局、元素尺寸、颜色等&#xff0c;通过精确测量和查看信息面板&#xff0c;把握设计元素的空间关系、…

映射关系5

明白&#xff01;&#x1f680; 你要我 继续扩展&#xff0c;在这套 C98 代码里加一个功能&#xff1a; 根据完整的5位ID&#xff0c;反查出对应的路径。 OK&#xff0c;我直接接着上面那版来&#xff0c;给你补充 getPathFromId 方法&#xff0c;并且保持整体风格统一&#…

编译原理:由浅入深从语法树到文法类型

文法与语言基础&#xff1a;从语法树到文法类型 文法&#xff08;Grammar&#xff09;和语言&#xff08;Language&#xff09;是计算机科学和语言学中解析和理解语言结构的核心概念。无论是编程语言的编译器设计&#xff0c;还是自然语言处理&#xff08;NLP&#xff09;中的…

第十三步:vue

Vue 1、上手 1、安装 使用命令&#xff1a;npm create vuelatestvue文件后缀为.vueconst app createApp(App)&#xff1a;初始化根组件app.mount("#app")&#xff1a;挂载根组件到页面 2、文件 script标签&#xff1a;编写jstemplate标签&#xff1a;编写htmls…

Pytest-mark使用详解(跳过、标记、参数 化)

1.前言 在工作中我们经常使用pytest.mark.XXXX进行装饰器修饰&#xff0c;后面的XXX的不同&#xff0c;在pytest中有不同的作 用&#xff0c;其整体使用相对复杂&#xff0c;我们单独将其抽取出来做详细的讲解。 2.pytest.mark.skip()/skipif()跳过用例 import pytest #无条…