-
核心实现方法方法 1:循环遍历构建字典(基础高效)1234567891011121314151617import json # 原始 JSON 数组(示例)json_array = [ {"key": "name", "value": "Alice"}, {"key": "age", "value": 25}, {"key": "city", "value": "Beijing"}] # 转换为字典对象result_dict = {}for item in json_array: result_dict[item["key"]] = item["value"] # 转为 JSON 字符串(可选)json_output = json.dumps(result_dict, indent=4, ensure_ascii=False)print(json_output)输出:12345{ "name": "Alice", "age": 25, "city": "Beijing"}特点:逻辑清晰,直接遍历数组,逐项提取 key 和 value适合初学者或需要显式控制流程的场景方法 2:字典推导式(简洁优雅)12result_dict = {item["key"]: item["value"] for item in json_array}json_output = json.dumps(result_dict, indent=4)特点:代码更简洁,单行完成转换适用于 Python 3.6+ 环境方法 3:使用reduce函数(函数式编程)123456from functools import reduceresult_dict = reduce( lambda obj, item: {**obj, item["key"]: item["value"]}, json_array, {})特点:函数式编程风格,适合复杂数据流处理可结合其他高阶函数(如 filter)进行数据预处理关键注意事项1.键名重复问题:若数组中存在重复的 key,后出现的值会覆盖先前的值。需提前检查:123keys = [item["key"] for item in json_array]if len(keys) != len(set(keys)): print("存在重复键名!")2.特殊数据类型处理:value 可能是嵌套对象或数组,转换时会保留原始结构若需自定义序列化(如处理日期),使用 default 参数:1json.dumps(result_dict, default=lambda x: x.isoformat() if hasattr(x, 'isoformat') else str(x))3.输出格式化优化:indent=4:美化输出,带缩进ensure_ascii=False:支持中文等非 ASCII 字符sort_keys=True:按键名字母排序输出完整流程示例123456789101112131415161718192021import json # 输入数据json_array = [ {"key": "product", "value": "笔记本电脑"}, {"key": "price", "value": 5999}, {"key": "in_stock", "value": True}, {"key": "specs", "value": {"CPU": "i7", "RAM": "16GB"}}] # 转换为字典result_dict = {item["key"]: item["value"] for item in json_array} # 输出为格式化的 JSON 字符串json_output = json.dumps( result_dict, indent=4, ensure_ascii=False, sort_keys=True)print(json_output)输出:123456789{ "in_stock": true, "price": 5999, "product": "笔记本电脑", "specs": { "CPU": "i7", "RAM": "16GB" }}应用场景与扩展API 数据处理:将从服务端获取的数组结构响应转为易操作的字典配置文件生成:将程序中的配置列表转为 JSON 配置文件结合 Pandas:若数据源是 DataFrame,可直接导出为 JSON:123import pandas as pddf = pd.DataFrame(json_array)df.set_index("key")["value"].to_dict() # 直接转为字典总结方法适用场景优势循环遍历兼容旧版 Python,逻辑清晰易于调试,显式控制流程字典推导式Python 3.6+,代码简洁化高效单行实现reduce 函数函数式编程场景,复杂数据处理支持链式操作和预处理选择方法时:优先推荐 字典推导式(简洁高效);若需兼容性或特殊处理,用 循环遍历;高级场景可尝试 reduce 函数 或结合 json.dumps 的参数定制输出格式。
-
1. 获取当前时间戳13位时间戳(毫秒级)12345678910import timeimport datetime # 方法1:使用time模块timestamp_13_1 = int(time.time() * 1000)print("13位时间戳(方法1):", timestamp_13_1) # 方法2:使用datetime模块timestamp_13_2 = int(datetime.datetime.now().timestamp() * 1000)print("13位时间戳(方法2):", timestamp_13_2)10位时间戳(秒级)1234567# 方法1:使用time模块timestamp_10_1 = int(time.time())print("10位时间戳(方法1):", timestamp_10_1) # 方法2:使用datetime模块timestamp_10_2 = int(datetime.datetime.now().timestamp())print("10位时间戳(方法2):", timestamp_10_2)2. 将时间戳转换为可读时间123456789# 13位时间戳转可读时间timestamp_13 = int(time.time() * 1000)readable_time_13 = datetime.datetime.fromtimestamp(timestamp_13 / 1000).strftime('%Y-%m-%d %H:%M:%S.%f')print("13位时间戳转可读时间:", readable_time_13) # 10位时间戳转可读时间timestamp_10 = int(time.time())readable_time_10 = datetime.datetime.fromtimestamp(timestamp_10).strftime('%Y-%m-%d %H:%M:%S')print("10位时间戳转可读时间:", readable_time_10)3. 将日期字符串转换为时间戳1234567891011from datetime import datetime date_str = "2023-01-01 12:00:00" # 转换为10位时间戳(秒级)timestamp_10 = int(datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S").timestamp())print("日期字符串转10位时间戳:", timestamp_10) # 转换为13位时间戳(毫秒级)timestamp_13 = int(datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S").timestamp() * 1000)print("日期字符串转13位时间戳:", timestamp_13)4. 注意事项时间戳的精度:10位时间戳表示秒级精度13位时间戳表示毫秒级精度时区问题:Python的time.time()和datetime.now()返回的是本地时间如果需要UTC时间,可以使用datetime.datetime.utcnow()跨平台兼容性:这些方法在Windows、Linux和macOS上都能正常工作大数处理:对于非常大的时间戳(如超过32位整数范围),确保使用Python 3的int类型5. 完整示例代码1234567891011121314151617181920212223242526272829303132import timeimport datetime def get_timestamps(): # 获取当前时间戳 now = datetime.datetime.now() # 13位时间戳(毫秒级) timestamp_13 = int(now.timestamp() * 1000) # 10位时间戳(秒级) timestamp_10 = int(now.timestamp()) # 转换为可读时间 readable_13 = now.strftime('%Y-%m-%d %H:%M:%S.%f') readable_10 = now.strftime('%Y-%m-%d %H:%M:%S') print(f"当前时间: {now}") print(f"13位时间戳: {timestamp_13}") print(f"10位时间戳: {timestamp_10}") print(f"13位时间戳对应时间: {readable_13}") print(f"10位时间戳对应时间: {readable_10}") # 示例:将日期字符串转换为时间戳 date_str = "2023-01-01 12:00:00" dt = datetime.datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S") print(f"\n日期字符串 '{date_str}' 转换为:") print(f"10位时间戳: {int(dt.timestamp())}") print(f"13位时间戳: {int(dt.timestamp() * 1000)}") if __name__ == "__main__": get_timestamps()
-
步骤1:项目架构设计目录结构:ai-agent-service/├── app/│ ├── __init__.py│ ├── main.py # FastAPI应用入口│ ├── core/ # 核心配置和工具│ │ ├── __init__.py│ │ ├── config.py # 配置管理│ │ ├── security.py # 安全工具│ │ └── logging.py # 日志配置│ ├── api/ # API路由│ │ ├── __init__.py│ │ ├── endpoints/ # 各个端点│ │ │ ├── __init__.py│ │ │ ├── chat.py # 聊天端点│ │ │ ├── tools.py # 工具端点│ │ │ └── admin.py # 管理端点│ │ └── dependencies.py # 依赖注入│ ├── services/ # 业务逻辑层│ │ ├── __init__.py│ │ ├── llm_service.py # LLM服务│ │ ├── chat_service.py # 聊天 服务│ │ └── tool_service.py # 工具服务│ ├── models/ # 数据模型│ │ ├── __init__.py│ │ ├── schemas.py # Pydantic模型│ │ └── database.py # 数据库模型│ ├── tools/ # 工具系统│ │ ├── __init__.py│ │ ├── base.py # 工具基类│ │ └── registry.py # 工具注册│ └── utils/ # 工具函数│ ├── __init__.py│ └── helpers.py├── tests/ # 测试文件├── docker/ # Docker配置├── k8s/ # Kubernetes配置├── scripts/ # 部署脚本├── requirements.txt # Python依赖├── Dockerfile├── docker-compose.yml└── README.md步骤2:核心依赖和配置123456789101112131415161718192021requirements.txt:fastapi==0.104.1uvicorn[standard]==0.24.0pydantic==2.5.0python-dotenv==1.0.0python-multipart==0.0.6sqlalchemy==2.0.23alembic==1.12.1psycopg2-binary==2.9.9redis==5.0.1httpx==0.25.2aiofiles==23.2.1python-jose[cryptography]==3.3.0passlib[bcrypt]==1.7.4prometheus-client==0.19.0opentelemetry-api==1.20.0opentelemetry-sdk==1.20.0opentelemetry-instrumentation-fastapi==0.41b0pytest==7.4.3pytest-asyncio==0.21.1pytest-cov==4.1.0app/core/config.py:1234567891011121314151617181920212223242526272829303132333435363738394041import osfrom typing import Optionalfrom pydantic_settings import BaseSettingsfrom dotenv import load_dotenv load_dotenv() class Settings(BaseSettings): """应用配置类""" # 应用配置 APP_NAME: str = "AI Agent Service" VERSION: str = "1.0.0" DEBUG: bool = False # API配置 API_V1_STR: str = "/api/v1" PROJECT_NAME: str = "ai-agent-service" # 安全配置 SECRET_KEY: str = os.getenv("SECRET_KEY", "your-secret-key-here") ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 # 数据库配置 DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql://user:pass@localhost/ai_agent") REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379") # LLM配置 OPENAI_API_KEY: Optional[str] = os.getenv("OPENAI_API_KEY") OPENAI_BASE_URL: Optional[str] = os.getenv("OPENAI_BASE_URL") MODEL_NAME: str = os.getenv("MODEL_NAME", "gpt-3.5-turbo") # 速率限制 RATE_LIMIT_PER_MINUTE: int = 60 class Config: case_sensitive = True env_file = ".env" settings = Settings()app/core/logging.py:12345678910111213141516171819202122232425262728293031323334import loggingimport sysfrom loguru import loggerfrom app.core.config import settings def setup_logging(): """配置结构化日志""" # 移除默认处理器 logger.remove() # 添加控制台处理器 logger.add( sys.stdout, level="DEBUG" if settings.DEBUG else "INFO", format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>", backtrace=True, diagnose=settings.DEBUG ) # 添加文件处理器(生产环境) if not settings.DEBUG: logger.add( "logs/ai_agent.log", rotation="10 MB", retention="30 days", level="INFO", format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}" ) return logger # 创建全局logger实例log = setup_logging()步骤3:数据模型设计app/models/schemas.py:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990from pydantic import BaseModel, Fieldfrom typing import List, Optional, Dict, Anyfrom datetime import datetimefrom enum import Enum class MessageRole(str, Enum): USER = "user" ASSISTANT = "assistant" SYSTEM = "system" TOOL = "tool" class ToolType(str, Enum): FUNCTION = "function" API = "api" DATABASE = "database" class ChatRequest(BaseModel): """聊天请求模型""" message: str = Field(..., description="用户消息") conversation_id: Optional[str] = Field(None, description="会话ID") tools: Optional[List[str]] = Field(None, description="要使用的工具列表") stream: bool = Field(False, description="是否流式响应") class Config: json_schema_extra = { "example": { "message": "你好,请帮我查询天气", "conversation_id": "conv_123", "tools": ["weather", "calculator"], "stream": False } } class ChatResponse(BaseModel): """聊天响应模型""" message: str = Field(..., description="AI回复") conversation_id: str = Field(..., description="会话ID") tool_calls: Optional[List[Dict[str, Any]]] = Field(None, description="工具调用") usage: Optional[Dict[str, int]] = Field(None, description="使用统计") class Config: json_schema_extra = { "example": { "message": "你好!我是AI助手,很高兴为您服务。", "conversation_id": "conv_123", "tool_calls": None, "usage": {"prompt_tokens": 10, "completion_tokens": 20} } } class ToolCall(BaseModel): """工具调用模型""" tool_name: str = Field(..., description="工具名称") parameters: Dict[str, Any] = Field(..., description="工具参数") class Config: json_schema_extra = { "example": { "tool_name": "weather", "parameters": {"city": "北京"} } } class ToolResponse(BaseModel): """工具响应模型""" tool_name: str = Field(..., description="工具名称") result: Any = Field(..., description="工具执行结果") success: bool = Field(..., description="执行是否成功") error_message: Optional[str] = Field(None, description="错误信息") class Conversation(BaseModel): """会话模型""" id: str = Field(..., description="会话ID") user_id: str = Field(..., description="用户ID") title: str = Field(..., description="会话标题") created_at: datetime = Field(..., description="创建时间") updated_at: datetime = Field(..., description="更新时间") message_count: int = Field(..., description="消息数量") class HealthCheck(BaseModel): """健康检查响应""" status: str = Field(..., description="服务状态") version: str = Field(..., description="服务版本") timestamp: datetime = Field(..., description="检查时间") class ErrorResponse(BaseModel): """错误响应模型""" error: str = Field(..., description="错误类型") message: str = Field(..., description="错误信息") details: Optional[Dict[str, Any]] = Field(None, description="错误详情")步骤4:路由和API设计app/main.py:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697from fastapi import FastAPI, Depends, HTTPExceptionfrom fastapi.middleware.cors import CORSMiddlewarefrom fastapi.middleware.trustedhost import TrustedHostMiddlewarefrom contextlib import asynccontextmanagerimport time from app.core.config import settingsfrom app.core.logging import logfrom app.api.endpoints import chat, tools, adminfrom app.api.dependencies import get_current_userfrom app.models.schemas import HealthCheck @asynccontextmanagerasync def lifespan(app: FastAPI): """应用生命周期管理""" # 启动时执行 log.info("🚀 Starting AI Agent Service") yield # 关闭时执行 log.info("🛑 Shutting down AI Agent Service") app = FastAPI( title=settings.PROJECT_NAME, version=settings.VERSION, description="企业级AI Agent微服务", docs_url="/docs" if settings.DEBUG else None, redoc_url="/redoc" if settings.DEBUG else None, lifespan=lifespan) # 中间件配置app.add_middleware( CORSMiddleware, allow_origins=["*"] if settings.DEBUG else ["https://yourdomain.com"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"],) app.add_middleware( TrustedHostMiddleware, allowed_hosts=["*"] if settings.DEBUG else ["yourdomain.com"]) @app.middleware("http")async def add_process_time_header(request, call_next): """添加请求处理时间头""" start_time = time.time() response = await call_next(request) process_time = time.time() - start_time response.headers["X-Process-Time"] = str(process_time) return response # 健康检查端点@app.get("/health", response_model=HealthCheck, tags=["health"])async def health_check(): return HealthCheck( status="healthy", version=settings.VERSION, timestamp=time.time() ) # 注册路由app.include_router( chat.router, prefix=settings.API_V1_STR, tags=["chat"], dependencies=[Depends(get_current_user)]) app.include_router( tools.router, prefix=settings.API_V1_STR, tags=["tools"], dependencies=[Depends(get_current_user)]) app.include_router( admin.router, prefix=settings.API_V1_STR + "/admin", tags=["admin"], dependencies=[Depends(get_current_user)]) @app.get("/")async def root(): return {"message": f"Welcome to {settings.APP_NAME}"} if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host="0.0.0.0", port=8000, reload=settings.DEBUG, log_level="info" if settings.DEBUG else "warning" )app/api/endpoints/chat.py:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556from fastapi import APIRouter, Depends, HTTPException, statusfrom fastapi.responses import StreamingResponsefrom typing import Optional from app.services.chat_service import ChatServicefrom app.models.schemas import ChatRequest, ChatResponse, ErrorResponsefrom app.api.dependencies import get_chat_servicefrom app.core.logging import log router = APIRouter() @router.post( "/chat", response_model=ChatResponse, responses={ 400: {"model": ErrorResponse}, 429: {"model": ErrorResponse}, 500: {"model": ErrorResponse} })async def chat_endpoint( request: ChatRequest, chat_service: ChatService = Depends(get_chat_service)): """处理聊天请求""" try: log.info(f"Processing chat request for conversation: {request.conversation_id}") if request.stream: # 流式响应处理 return StreamingResponse( chat_service.stream_chat(request), media_type="text/event-stream" ) else: # 普通响应 return await chat_service.process_chat(request) except Exception as e: log.error(f"Chat processing error: {str(e)}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Chat processing failed: {str(e)}" ) @router.get("/conversations/{conversation_id}")async def get_conversation(conversation_id: str): """获取会话历史""" # 实现获取会话逻辑 return {"conversation_id": conversation_id, "messages": []} @router.delete("/conversations/{conversation_id}")async def delete_conversation(conversation_id: str): """删除会话""" # 实现删除会话逻辑 return {"message": f"Conversation {conversation_id} deleted"}步骤5:服务层设计app/services/chat_service.py:123456789101112131415161718192021222324252627282930313233343536373839404142434445from typing import AsyncGenerator, Optionalfrom app.models.schemas import ChatRequest, ChatResponsefrom app.services.llm_service import LLMServicefrom app.core.logging import log class ChatService: """聊天 服务""" def __init__(self, llm_service: LLMService): self.llm_service = llm_service async def process_chat(self, request: ChatRequest) -> ChatResponse: """处理聊天请求""" try: # 处理消息逻辑 response = await self.llm_service.generate_response( message=request.message, conversation_id=request.conversation_id, tools=request.tools ) return ChatResponse( message=response["content"], conversation_id=response["conversation_id"], tool_calls=response.get("tool_calls"), usage=response.get("usage") ) except Exception as e: log.error(f"Chat processing error: {str(e)}") raise async def stream_chat(self, request: ChatRequest) -> AsyncGenerator[str, None]: """流式聊天响应""" try: async for chunk in self.llm_service.stream_response( message=request.message, conversation_id=request.conversation_id, tools=request.tools ): yield f"data: {chunk}\n\n" except Exception as e: log.error(f"Stream chat error: {str(e)}") yield f"data: {{'error': '{str(e)}'}}\n\n"app/services/llm_service.py:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091import httpxfrom typing import AsyncGenerator, List, Optional, Dict, Anyfrom app.core.config import settingsfrom app.core.logging import log class LLMService: """LLM服务基类""" async def generate_response( self, message: str, conversation_id: Optional[str] = None, tools: Optional[List[str]] = None ) -> Dict[str, Any]: """生成响应""" raise NotImplementedError async def stream_response( self, message: str, conversation_id: Optional[str] = None, tools: Optional[List[str]] = None ) -> AsyncGenerator[str, None]: """流式生成响应""" raise NotImplementedError class OpenAIService(LLMService): """OpenAI服务实现""" def __init__(self): self.api_key = settings.OPENAI_API_KEY self.base_url = settings.OPENAI_BASE_URL or "https://api.openai.com/v1" self.model = settings.MODEL_NAME self.client = httpx.AsyncClient( base_url=self.base_url, headers={"Authorization": f"Bearer {self.api_key}"}, timeout=30.0 ) async def generate_response(self, message: str, conversation_id: Optional[str] = None, tools: Optional[List[str]] = None) -> Dict[str, Any]: try: messages = [{"role": "user", "content": message}] response = await self.client.post( "/chat/completions", json={ "model": self.model, "messages": messages, "max_tokens": 1000, "temperature": 0.7 } ) if response.status_code != 200: raise Exception(f"OpenAI API error: {response.text}") data = response.json() return { "content": data["choices"][0]["message"]["content"], "conversation_id": conversation_id or f"conv_{hash(message)}", "usage": data.get("usage") } except Exception as e: log.error(f"OpenAI service error: {str(e)}") raise async def stream_response(self, message: str, conversation_id: Optional[str] = None, tools: Optional[List[str]] = None) -> AsyncGenerator[str, None]: try: messages = [{"role": "user", "content": message}] async with self.client.stream( "POST", "/chat/completions", json={ "model": self.model, "messages": messages, "max_tokens": 1000, "temperature": 0.7, "stream": True } ) as response: async for line in response.aiter_lines(): if line.startswith("data: "): data = line[6:] if data != "[DONE]": yield data except Exception as e: log.error(f"OpenAI stream error: {str(e)}") yield f'{{"error": "{str(e)}"}}'步骤6:工具系统设计app/tools/base.py:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566from abc import ABC, abstractmethodfrom typing import Any, Dict, Optionalfrom pydantic import BaseModel, Fieldfrom app.core.logging import log class ToolParameter(BaseModel): """工具参数定义""" name: str = Field(..., description="参数名称") type: str = Field(..., description="参数类型") description: str = Field(..., description="参数描述") required: bool = Field(True, description="是否必需") class BaseTool(ABC): """工具基类""" def __init__(self): self.name = self.__class__.__name__.lower().replace('tool', '') self.description = "A general purpose tool" self.parameters = [] @abstractmethod async def execute(self, **kwargs) -> Any: """执行工具""" pass def get_schema(self) -> Dict[str, Any]: """获取工具定义""" return { "name": self.name, "description": self.description, "parameters": [ param.dict() for param in self.parameters ] } class CalculatorTool(BaseTool): """计算器工具""" def __init__(self): super().__init__() self.name = "calculator" self.description = "Perform mathematical calculations" self.parameters = [ ToolParameter( name="expression", type="string", description="Mathematical expression to evaluate", required=True ) ] async def execute(self, expression: str) -> float: """执行计算""" try: # 安全评估数学表达式 allowed_chars = set('0123456789+-*/.() ') if not all(c in allowed_chars for c in expression): raise ValueError("Invalid characters in expression") result = eval(expression) # 注意:生产环境需要更安全的方式 log.info(f"Calculator tool executed: {expression} = {result}") return result except Exception as e: log.error(f"Calculator error: {str(e)}") raise ValueError(f"Calculation failed: {str(e)}")app/tools/registry.py:1234567891011121314151617181920212223242526272829303132333435363738394041424344from typing import Dict, List, Optionalfrom app.tools.base import BaseToolfrom app.core.logging import log class ToolRegistry: """工具注册表""" def __init__(self): self._tools: Dict[str, BaseTool] = {} def register_tool(self, tool: BaseTool): """注册工具""" self._tools[tool.name] = tool log.info(f"Tool registered: {tool.name}") def get_tool(self, name: str) -> Optional[BaseTool]: """获取工具""" return self._tools.get(name) def list_tools(self) -> List[Dict]: """列出所有工具""" return [tool.get_schema() for tool in self._tools.values()] async def execute_tool(self, name: str, **kwargs) -> Any: """执行工具""" tool = self.get_tool(name) if not tool: raise ValueError(f"Tool not found: {name}") return await tool.execute(**kwargs) # 全局工具注册表实例tool_registry = ToolRegistry() # 注册默认工具def register_default_tools(): """注册默认工具""" from app.tools.base import CalculatorTool calculator = CalculatorTool() tool_registry.register_tool(calculator) # 初始化时注册工具register_default_tools()步骤7:身份认证和授权app/core/security.py:123456789101112131415161718192021222324252627282930313233343536from datetime import datetime, timedeltafrom typing import Optionalfrom jose import JWTError, jwtfrom passlib.context import CryptContextfrom app.core.config import settingsfrom app.core.logging import log pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") def verify_password(plain_password: str, hashed_password: str) -> bool: """验证密码""" return pwd_context.verify(plain_password, hashed_password) def get_password_hash(password: str) -> str: """生成密码哈希""" return pwd_context.hash(password) def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: """创建访问令牌""" to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) return encoded_jwt def verify_token(token: str) -> Optional[dict]: """验证令牌""" try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) return payload except JWTError: return Noneapp/api/dependencies.py:12345678910111213141516171819202122232425262728293031from fastapi import Depends, HTTPException, statusfrom fastapi.security import HTTPBearer, HTTPAuthorizationCredentialsfrom app.core.security import verify_tokenfrom app.core.logging import logfrom app.services.llm_service import LLMService, OpenAIServicefrom app.services.chat_service import ChatService security = HTTPBearer() async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)): """获取当前用户""" token = credentials.credentials payload = verify_token(token) if payload is None: log.warning("Invalid authentication token") raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authentication credentials", headers={"WWW-Authenticate": "Bearer"}, ) # 这里可以添加用户验证逻辑 return payload def get_llm_service() -> LLMService: """获取LLM服务实例""" return OpenAIService() def get_chat_service(llm_service: LLMService = Depends(get_llm_service)) -> ChatService: """获取聊天 服务实例""" return ChatService(llm_service)Docker配置Dockerfile:123456789101112131415161718192021222324252627FROM python:3.11-slim WORKDIR /app # 安装系统依赖RUN apt-get update && apt-get install -y \ gcc \ && rm -rf /var/lib/apt/lists/* # 复制依赖文件COPY requirements.txt . # 安装Python依赖RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码COPY . . # 创建非root用户RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /appUSER appuser # 暴露端口EXPOSE 8000 # 启动命令CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]docker-compose.yml:12345678910111213141516171819202122232425262728293031323334version: ‘3.8' services:ai-agent:build: .ports:- “8000:8000”environment:- DEBUG=true- DATABASE_URL=postgresql://user:pass@db:5432/ai_agent- REDIS_URL=redis://redis:6379depends_on:- db- redisvolumes:- ./logs:/app/logs db:image: postgres:13environment:- POSTGRES_DB=ai_agent- POSTGRES_USER=user- POSTGRES_PASSWORD=passvolumes:- postgres_data:/var/lib/postgresql/data redis:image: redis:7-alpinevolumes:- redis_data:/data volumes:postgres_data:redis_data: 这个脚手架提供了:完整的项目结构配置管理数据模型API路由服务层工具系统身份认证日志系统Docker配置步骤8:数据库模型和配置增强app/models/database.py:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106from sqlalchemy import Column, String, Text, DateTime, Integer, Boolean, JSON, ForeignKeyfrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy.orm import relationship, sessionmakerfrom sqlalchemy import create_enginefrom datetime import datetimeimport uuidfrom app.core.config import settings Base = declarative_base() def generate_uuid(): return str(uuid.uuid4()) class User(Base): """用户模型""" __tablename__ = "users" id = Column(String, primary_key=True, default=generate_uuid) username = Column(String(50), unique=True, index=True, nullable=False) email = Column(String(100), unique=True, index=True, nullable=False) hashed_password = Column(String(255), nullable=False) is_active = Column(Boolean, default=True) is_superuser = Column(Boolean, default=False) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # 关系 conversations = relationship("Conversation", back_populates="user") api_keys = relationship("APIKey", back_populates="user") class Conversation(Base): """会话模型""" __tablename__ = "conversations" id = Column(String, primary_key=True, default=generate_uuid) user_id = Column(String, ForeignKey("users.id"), nullable=False) title = Column(String(200), nullable=False) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) message_count = Column(Integer, default=0) # 关系 user = relationship("User", back_populates="conversations") messages = relationship("Message", back_populates="conversation") class Message(Base): """消息模型""" __tablename__ = "messages" id = Column(String, primary_key=True, default=generate_uuid) conversation_id = Column(String, ForeignKey("conversations.id"), nullable=False) role = Column(String(20), nullable=False) # user, assistant, system, tool content = Column(Text, nullable=False) tool_calls = Column(JSON, nullable=True) tool_results = Column(JSON, nullable=True) token_count = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.utcnow) # 关系 conversation = relationship("Conversation", back_populates="messages") class APIKey(Base): """API密钥模型""" __tablename__ = "api_keys" id = Column(String, primary_key=True, default=generate_uuid) user_id = Column(String, ForeignKey("users.id"), nullable=False) name = Column(String(100), nullable=False) key_hash = Column(String(255), nullable=False, unique=True, index=True) is_active = Column(Boolean, default=True) last_used = Column(DateTime, nullable=True) created_at = Column(DateTime, default=datetime.utcnow) expires_at = Column(DateTime, nullable=True) # 关系 user = relationship("User", back_populates="api_keys") class ToolCallLog(Base): """工具调用日志""" __tablename__ = "tool_call_logs" id = Column(String, primary_key=True, default=generate_uuid) user_id = Column(String, ForeignKey("users.id"), nullable=False) tool_name = Column(String(100), nullable=False) parameters = Column(JSON, nullable=True) result = Column(Text, nullable=True) success = Column(Boolean, default=True) error_message = Column(Text, nullable=True) duration_ms = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.utcnow) # 数据库引擎和会话engine = create_engine(settings.DATABASE_URL)SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) def get_db(): """获取数据库会话""" db = SessionLocal() try: yield db finally: db.close() def create_tables(): """创建数据库表""" Base.metadata.create_all(bind=engine)app/api/endpoints/admin.py:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364from fastapi import APIRouter, Depends, HTTPException, statusfrom sqlalchemy.orm import Sessionfrom typing import List from app.models.database import get_db, User, Conversation, ToolCallLogfrom app.models.schemas import Conversation as ConversationSchemafrom app.api.dependencies import get_current_userfrom app.core.logging import log router = APIRouter() @router.get("/users/{user_id}/conversations", response_model=List[ConversationSchema])async def get_user_conversations( user_id: str, skip: int = 0, limit: int = 100, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user)): """获取用户会话列表""" # 检查权限 if current_user.get("user_id") != user_id and not current_user.get("is_superuser", False): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough permissions" ) conversations = db.query(Conversation).filter( Conversation.user_id == user_id ).offset(skip).limit(limit).all() return conversations @router.get("/metrics/tool-usage")async def get_tool_usage_metrics( days: int = 7, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user)): """获取工具使用统计""" if not current_user.get("is_superuser", False): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Admin access required" ) # 实现工具使用统计查询 return {"message": "Tool usage metrics endpoint"} @router.delete("/conversations/{conversation_id}")async def admin_delete_conversation( conversation_id: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user)): """管理员删除会话""" if not current_user.get("is_superuser", False): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Admin access required" ) # 实现管理员删除会话逻辑 return {"message": f"Conversation {conversation_id} deleted by admin"}步骤9:监控和可观测性app/core/monitoring.py:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687from prometheus_client import Counter, Histogram, Gauge, generate_latestfrom prometheus_client import REGISTRYfrom fastapi import Request, Responseimport timefrom app.core.logging import log # 定义指标REQUEST_COUNT = Counter( 'http_requests_total', 'Total HTTP Requests', ['method', 'endpoint', 'status_code']) REQUEST_DURATION = Histogram( 'http_request_duration_seconds', 'HTTP request duration in seconds', ['method', 'endpoint']) ACTIVE_REQUESTS = Gauge( 'http_requests_active', 'Active HTTP requests') LLM_CALL_COUNT = Counter( 'llm_calls_total', 'Total LLM API calls', ['provider', 'model', 'status']) TOOL_CALL_COUNT = Counter( 'tool_calls_total', 'Total tool calls', ['tool_name', 'status']) class PrometheusMiddleware: """Prometheus监控中间件""" def __init__(self, app): self.app = app async def __call__(self, scope, receive, send): if scope["type"] != "http": return await self.app(scope, receive, send) start_time = time.time() method = scope["method"] path = self._get_path(scope["path"]) ACTIVE_REQUESTS.inc() async def send_wrapper(message): if message["type"] == "http.response.start": status_code = message["status"] REQUEST_COUNT.labels(method=method, endpoint=path, status_code=status_code).inc() REQUEST_DURATION.labels(method=method, endpoint=path).observe(time.time() - start_time) await send(message) try: await self.app(scope, receive, send_wrapper) finally: ACTIVE_REQUESTS.dec() def _get_path(self, path: str) -> str: """规范化路径用于指标""" if path.startswith("/api/v1"): # 提取API版本后的第一部分作为端点 parts = path.split("/") if len(parts) > 3: return f"/api/v1/{parts[3]}" return path def metrics_endpoint(request: Request) -> Response: """提供Prometheus指标""" return Response(generate_latest(REGISTRY), media_type="text/plain") def record_llm_call(provider: str, model: str, success: bool = True): """记录LLM调用""" status = "success" if success else "error" LLM_CALL_COUNT.labels(provider=provider, model=model, status=status).inc() def record_tool_call(tool_name: str, success: bool = True): """记录工具调用""" status = "success" if success else "error" TOOL_CALL_COUNT.labels(tool_name=tool_name, status=status).inc()在main.py中添加监控:12345678910from app.core.monitoring import PrometheusMiddleware, metrics_endpoint # 添加监控中间件(在中间件配置部分)app.add_middleware(PrometheusMiddleware) # 添加指标端点(在路由部分)@app.get("/metrics")async def metrics(): from app.core.monitoring import metrics_endpoint return metrics_endpoint步骤10:缓存和性能优化app/core/cache.py:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768import redisimport jsonimport picklefrom typing import Any, Optionalfrom app.core.config import settingsfrom app.core.logging import log class CacheManager: """Redis缓存管理器""" def __init__(self): self.redis_client = redis.from_url(settings.REDIS_URL, decode_responses=False) self.default_ttl = 3600 # 1小时默认TTL async def get(self, key: str) -> Optional[Any]: """获取缓存值""" try: data = self.redis_client.get(key) if data: return pickle.loads(data) return None except Exception as e: log.error(f"Cache get error for key {key}: {e}") return None async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool: """设置缓存值""" try: serialized_value = pickle.dumps(value) expire_time = ttl if ttl is not None else self.default_ttl self.redis_client.setex(key, expire_time, serialized_value) return True except Exception as e: log.error(f"Cache set error for key {key}: {e}") return False async def delete(self, key: str) -> bool: """删除缓存""" try: result = self.redis_client.delete(key) return result > 0 except Exception as e: log.error(f"Cache delete error for key {key}: {e}") return False async def get_or_set(self, key: str, default_func, ttl: Optional[int] = None) -> Any: """获取或设置缓存""" cached = await self.get(key) if cached is not None: return cached value = default_func() await self.set(key, value, ttl) return value async def clear_pattern(self, pattern: str) -> int: """清除匹配模式的缓存""" try: keys = self.redis_client.keys(pattern) if keys: return self.redis_client.delete(*keys) return 0 except Exception as e: log.error(f"Cache clear pattern error: {e}") return 0 # 全局缓存实例cache = CacheManager()步骤11:速率限制app/core/rate_limiting.py:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869from fastapi import HTTPException, statusfrom app.core.cache import cachefrom app.core.logging import logimport timefrom typing import Optional class RateLimiter: """速率限制器""" def __init__(self, requests_per_minute: int = 60): self.requests_per_minute = requests_per_minute async def check_rate_limit(self, identifier: str, cost: int = 1) -> bool: """检查速率限制""" cache_key = f"rate_limit:{identifier}" # 获取当前窗口数据 window_data = await cache.get(cache_key) or { 'count': 0, 'window_start': time.time() } current_time = time.time() window_duration = 60 # 60秒窗口 # 如果窗口已过期,重置 if current_time - window_data['window_start'] > window_duration: window_data = { 'count': 0, 'window_start': current_time } # 检查是否超过限制 if window_data['count'] + cost > self.requests_per_minute: log.warning(f"Rate limit exceeded for {identifier}") return False # 更新计数 window_data['count'] += cost await cache.set(cache_key, window_data, window_duration) return True async def get_remaining_requests(self, identifier: str) -> int: """获取剩余请求数""" cache_key = f"rate_limit:{identifier}" window_data = await cache.get(cache_key) or { 'count': 0, 'window_start': time.time() } return max(0, self.requests_per_minute - window_data['count']) def rate_limit_middleware(requests_per_minute: int = 60): """速率限制中间件工厂""" limiter = RateLimiter(requests_per_minute) async def middleware(identifier: str, cost: int = 1): if not await limiter.check_rate_limit(identifier, cost): raise HTTPException( status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail=f"Rate limit exceeded. Try again in 60 seconds." ) return True return middleware # 默认速率限制器default_limiter = RateLimiter()步骤12:测试框架tests/conftest.py:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152import pytestimport asynciofrom fastapi.testclient import TestClientfrom sqlalchemy import create_enginefrom sqlalchemy.orm import sessionmakerfrom sqlalchemy.pool import StaticPool from app.main import appfrom app.models.database import Base, get_db # 测试数据库配置SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" engine = create_engine( SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}, poolclass=StaticPool,) TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) @pytest.fixture(scope="function")def db_session(): """创建测试数据库会话""" Base.metadata.create_all(bind=engine) session = TestingSessionLocal() try: yield session finally: session.close() Base.metadata.drop_all(bind=engine) @pytest.fixture(scope="function")def client(db_session): """创建测试客户端""" def override_get_db(): try: yield db_session finally: pass app.dependency_overrides[get_db] = override_get_db with TestClient(app) as test_client: yield test_client app.dependency_overrides.clear() @pytest.fixture(scope="session")def event_loop(): """创建事件循环""" loop = asyncio.get_event_loop_policy().new_event_loop() yield loop loop.close()tests/test_chat.py:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152import pytestfrom app.models.schemas import ChatRequest def test_health_check(client): """测试健康检查端点""" response = client.get("/health") assert response.status_code == 200 data = response.json() assert data["status"] == "healthy" def test_chat_endpoint(client): """测试聊天端点""" # 注意:需要先设置认证或跳过认证 request_data = { "message": "Hello, test message", "stream": False } response = client.post("/api/v1/chat", json=request_data) # 由于认证,这里可能会返回401 assert response.status_code in [200, 401, 403] def test_chat_streaming(client): """测试流式聊天""" request_data = { "message": "Hello, streaming test", "stream": True } response = client.post("/api/v1/chat", json=request_data) assert response.status_code in [200, 401, 403] @pytest.mark.asyncioasync def test_tool_registry(): """测试工具注册表""" from app.tools.registry import tool_registry from app.tools.base import CalculatorTool # 测试工具注册 calculator = CalculatorTool() tool_registry.register_tool(calculator) # 测试工具获取 tool = tool_registry.get_tool("calculator") assert tool is not None assert tool.name == "calculator" def test_metrics_endpoint(client): """测试指标端点""" response = client.get("/metrics") assert response.status_code == 200 assert "http_requests_total" in response.text步骤13:部署配置增强docker-compose.prod.yml:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566version: '3.8' services: ai-agent: build: . ports: - "8000:8000" environment: - DEBUG=false - DATABASE_URL=postgresql://user:pass@db:5432/ai_agent - REDIS_URL=redis://redis:6379 - SECRET_KEY=your-production-secret-key depends_on: - db - redis volumes: - ./logs:/app/logs restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 db: image: postgres:13 environment: - POSTGRES_DB=ai_agent - POSTGRES_USER=user - POSTGRES_PASSWORD=pass volumes: - postgres_data:/var/lib/postgresql/data - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U user -d ai_agent"] interval: 30s timeout: 10s retries: 3 redis: image: redis:7-alpine volumes: - redis_data:/data restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 30s timeout: 10s retries: 3 nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./ssl:/etc/nginx/ssl depends_on: - ai-agent restart: unless-stopped volumes: postgres_data: redis_data:nginx/nginx.conf:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152events {worker_connections 1024;} http {upstream ai_agent {server ai-agent:8000;} server { listen 80; server_name your-domain.com; return 301 https://$server_name$request_uri;} server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; # 安全头 add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; # 速率限制 limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; location / { limit_req zone=api burst=20 nodelay; proxy_pass http://ai_agent; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /metrics { # 内部访问指标 allow 127.0.0.1; deny all; proxy_pass http://ai_agent; } location /health { proxy_pass http://ai_agent; access_log off; }}} 步骤14:环境配置和脚本.env.example:123456789101112131415161718192021# 应用配置DEBUG=falseAPP_NAME="AI Agent Service"VERSION=1.0.0 # 安全配置SECRET_KEY=your-super-secret-key-here-change-in-productionALGORITHM=HS256ACCESS_TOKEN_EXPIRE_MINUTES=30 # 数据库配置DATABASE_URL=postgresql://user:pass@localhost:5432/ai_agentREDIS_URL=redis://localhost:6379 # LLM配置OPENAI_API_KEY=your-openai-api-keyOPENAI_BASE_URL=https://api.openai.com/v1MODEL_NAME=gpt-3.5-turbo # 速率限制RATE_LIMIT_PER_MINUTE=60scripts/start.sh:1234567891011121314151617181920212223242526272829303132333435363738394041#!/bin/bash # AI Agent服务启动脚本 set -e echo "🚀 Starting AI Agent Service..." # 检查环境变量if [ -z "$DATABASE_URL" ]; then echo "❌ DATABASE_URL is not set" exit 1fi if [ -z "$OPENAI_API_KEY" ]; then echo "⚠️ OPENAI_API_KEY is not set, some features may not work"fi # 等待数据库就绪echo "⏳ Waiting for database..."while ! nc -z $(echo $DATABASE_URL | sed 's/.*@//' | cut -d: -f1) $(echo $DATABASE_URL | sed 's/.*://' | cut -d/ -f1); do sleep 1done echo "✅ Database is ready" # 运行数据库迁移echo "📦 Running database migrations..."python -c "from app.models.database import create_tablescreate_tables()print('Database tables created/verified')" # 启动服务echo "🎯 Starting Uvicorn server..."exec uvicorn app.main:app \ --host 0.0.0.0 \ --port 8000 \ --workers 4 \ --log-level infoscripts/deploy.sh:1234567891011121314151617181920212223242526272829#!/bin/bash # 部署脚本 set -e ENV=${1:-staging}IMAGE_TAG="ai-agent-service:latest" echo "🚀 Deploying AI Agent Service to $ENV" # 构建Docker镜像echo "📦 Building Docker image..."docker build -t $IMAGE_TAG . # 根据环境选择配置if [ "$ENV" = "production" ]; then COMPOSE_FILE="docker-compose.prod.yml"else COMPOSE_FILE="docker-compose.yml"fi # 部署服务echo "🎯 Deploying services..."docker-compose -f $COMPOSE_FILE downdocker-compose -f $COMPOSE_FILE up -d echo "✅ Deployment completed!"echo "📊 Health check: curl http://localhost/health"步骤15:完整的使用指南README.md:# AI Agent微服务脚手架企业级AI Agent微服务框架,基于FastAPI构建。## 特性- 🚀 高性能异步架构- 🔐 JWT身份认证和RBAC授权- 🛠️ 可扩展的工具系统- 📊 完整的监控和指标- 🐳 Docker容器化部署- 📝 结构化日志记录- 🧪 完整的测试覆盖- ⚡ 速率限制和缓存- 🔒 安全最佳实践## 快速开始### 环境设置1.复制环境配置cp .env.example .env2.编辑.env文件,配置数据库和API密钥。开发环境1234567# 安装依赖 pip install -r requirements.txt # 启动开发服务器 uvicorn app.main:app --reload --host 0.0.0.0 --port 8000Docker部署1234567# 开发环境 docker-compose up -d # 生产环境 docker-compose -f docker-compose.prod.yml up -dAPI文档启动服务后访问:Swagger UI: http://localhost:8000/docsReDoc: http://localhost:8000/redoc指标: http://localhost:8000/metrics项目结构app/├── api/ # API路由和端点├── core/ # 核心配置和工具├── models/ # 数据模型├── services/ # 业务逻辑├── tools/ # 工具系统└── utils/ # 工具函数## 开发指南### 添加新工具1. 在`app/tools/`中创建新工具类2. 继承`BaseTool`基类3. 在`app/tools/registry.py`中注册工具### 添加新API端点1. 在`app/api/endpoints/`中创建新路由文件2. 在`app/main.py`中注册路由## 监控和运维服务提供完整的监控指标:- HTTP请求统计- LLM调用监控- 工具使用统计- 性能指标## 许可证MIT License完整的启动流程1.环境准备:1234567# 克隆项目git clone <your-repo>cd ai-agent-service # 设置环境cp .env.example .env# 编辑.env文件配置你的设置2. 安装和运行:123456# 方式1: 使用Docker(推荐)docker-compose up -d # 方式2: 本地开发pip install -r requirements.txtuvicorn app.main:app --reload3. 验证部署:curl http://localhost:8000/healthcurl http://localhost:8000/docs
-
大家好,本次主要带来的是Python相关的常见问题处理,以及知识分享,希望可以帮到大家。1.Python实现快捷启动本地应用【转载】https://bbs.huaweicloud.com/forum/thread-02107196584688824047-1-1.html2.python语言中的常用容器(集合)示例详解【转载】https://bbs.huaweicloud.com/forum/thread-0231196584607663063-1-1.html3.python引用.dll文件并调用函数实例代码【转载】https://bbs.huaweicloud.com/forum/thread-02107196584551097046-1-1.html4.Python进行word模板内容替换的实现示例【转载】https://bbs.huaweicloud.com/forum/thread-0254196584486148057-1-1.html5.Python中的鸭子类型实际应用之理解动态类型的力量【转载】https://bbs.huaweicloud.com/forum/thread-0215196584363706051-1-1.html6.Go表达式引擎expr基础用法实战指南【转载】https://bbs.huaweicloud.com/forum/thread-0282196584192126043-1-1.html7.彻底卸载macOS上所有版本Python的详细指南【转载】https://bbs.huaweicloud.com/forum/thread-0254196584145963056-1-1.html8.在macOS下升级Python几种常见方法【转载】https://bbs.huaweicloud.com/forum/thread-0231196584101589062-1-1.html9.Python3 hashlib 模块基本用法详解【转载】https://bbs.huaweicloud.com/forum/thread-0215196584034090050-1-1.html10.Python获取文件大小的三种主流方法【转载】https://bbs.huaweicloud.com/forum/thread-0231196583981882061-1-1.html11.Python获取文件创建时间的三种方法【转载】https://bbs.huaweicloud.com/forum/thread-0215196583895586049-1-1.html12.使用Python轻松实现裁剪PDF并导出为图片【转载】https://bbs.huaweicloud.com/forum/thread-02107196583852193045-1-1.html13.浅谈Go语言中高效并发模式 【转载】https://bbs.huaweicloud.com/forum/thread-0231196583777157060-1-1.html14.使用Python实现桌面便签与待办事项管理工具【转载】https://bbs.huaweicloud.com/forum/thread-0282196584727759044-1-1.html15.Python高效实现PDF批量转Word的示例代码【转载】https://bbs.huaweicloud.com/forum/thread-0263196584765776060-1-1.html16.Python与Java进行相互操作与调用的解决方案大全【转载】https://bbs.huaweicloud.com/forum/thread-0231196584806040065-1-1.html
-
一、Python虚拟环境概述1.1 什么是虚拟环境Python虚拟环境是一个独立的Python运行环境,它包含了Python解释器、标准库以及特定项目所需的第三方包。每个虚拟环境都是相互隔离的,互不影响,这样可以确保项目之间的依赖关系不会产生冲突。1.2 虚拟环境的优势依赖隔离:不同项目可以使用不同版本的包环境纯净:避免全局环境被污染易于管理:可以轻松创建、删除和复制环境版本控制:便于团队协作和部署二、venv模块详解2.1 venv简介venv是Python 3.3版本引入的标准库模块,用于创建轻量级的虚拟环境。与第三方工具如virtualenv相比,venv是官方维护的,更加稳定可靠。2.2 venv与virtualenv的区别三、venv的基本使用 创建虚拟环境创建虚拟环境的基本语法如下:python -m venv <环境名称>例如,创建一个名为myproject的虚拟环境:python -m venv myproject激活虚拟环境 # 命令提示符 myproject\Scripts\activate # PowerShell myproject\Scripts\Activate.ps1windows上还可以用pycharm更直观的操作,在 PyCharm 中virtualenv 和 venv 的基本操作是相似的,因为 PyCharm 提供了统一的界面来管理虚拟环境。详细操作步骤为:(1)打开 PyCharm 并进入项目设置(2)转到 "File" → "Settings" (Windows/Linux) 或 "PyCharm" → "Preferences" (Mac)(3)选择 "Project" → "Python Interpreter"(4)点击齿轮图标,选择 "Add..."(5)选择 "New environment"或者"Virtualenv Environment"选项(6)在 "Base interpreter" 中选择你的 Python 解释器(7)确保选中 "Create virtualenv" 或 "New environment" 选项(8)选择位置并点击 "OK"这样操作不用再去手动激活环境了。 创建成功后,可以见到项目中多出一个venv目录,说明安装激活成功。Linux/macOS系统source myproject/bin/activate激活成功后,命令行前会显示虚拟环境名称:(myproject) $ 退出虚拟环境deactivate删除虚拟环境直接删除虚拟环境文件夹即可:# Windows rmdir /s myproject # Linux/macOS rm -rf myproject四、高级功能与配置# 指定Python版本创建虚拟环境 python3.9 -m venv myproject # 创建不包含pip的环境 python -m venv myproject --without-pip # 复制现有环境 python -m venv myproject --copies # 生成依赖文件 pip freeze > requirements.txt # 安装依赖文件 pip install -r requirements.txt五、最佳实践项目结构建议myproject/ ├── venv/ # 虚拟环境目录 ├── src/ # 源代码目录 ├── tests/ # 测试代码目录 ├── requirements.txt # 依赖文件 └── README.md # 项目说明5.2 环境命名规范建议使用项目名称或功能描述来命名虚拟环境,避免使用通用名称如env、venv等。5.3 依赖管理策略# 开发依赖与生产依赖分离 pip freeze > requirements.txt # 生产依赖 pip freeze > requirements-dev.txt # 开发依赖 # 定期更新依赖 pip list --outdated # 查看过期包 pip install --upgrade package_name # 升级包激活虚拟环境激活环境后,所有 Python 和 pip 命令都会使用虚拟环境中的版本。Windows 系统.venv\Scripts\activate查看已安装的包(.venv) pip list Package Version ---------- ------- Django 3.2.12 pip 21.2.4退出虚拟环境当完成工作后,可以退出虚拟环境:deactivate退出后,命令行提示符会恢复正常,Python 和 pip 命令将使用系统全局版本。 总结Python 虚拟环境是独立隔离的 Python 运行环境,可避免项目间依赖冲突,保障全局环境纯净,同时便于版本控制与团队协作,是 Python 开发的核心工具之一。其核心实现工具 venv 作为 Python 3.3 + 的官方标准库模块,相比第三方工具 virtualenv 更稳定可靠,无需额外安装即可使用。venv 的基础操作覆盖环境全生命周期:创建时通过python -m venv <环境名>指令生成,Windows 系统需用Scripts\activate(CMD)或Scripts\Activate.ps1(PowerShell)激活,Linux/macOS 则用source bin/activate,激活后命令行前缀会显示环境名;退出用deactivate,删除只需直接移除环境文件夹。PyCharm 还提供可视化管理,在 “Python Interpreter” 设置中可一键创建、添加虚拟环境,无需手动执行命令。高级功能上,venv 支持指定 Python 版本(如python3.9 -m venv)、创建无 pip 环境(--without-pip)、复制现有环境(--copies);依赖管理可通过pip freeze > requirements.txt生成依赖清单,再用pip install -r requirements.txt快速复现环境。最佳实践方面,建议项目结构包含 venv(环境目录)、src(源码)、tests(测试)等文件夹,环境命名采用项目或功能名而非 “env” 等通用名;依赖需分离生产(requirements.txt)与开发(requirements-dev.txt)版本,定期用pip list --outdated查看过期包并更新,确保开发环境规范可控。
-
方案1:使用JythonJython是一个运行在JVM上的Python解释器,允许Python代码直接调用Java代码。安装Jython12wget https://www.jython.org/downloads/jython-installer-2.7.2.jarjava -jar jython-installer-2.7.2.jarPython调用Java代码12345678from java.util import ArrayList list_obj = ArrayList()list_obj.add("Hello")list_obj.add("World") for item in list_obj: print(item)Java调用Python代码Jython提供了PythonInterpreter类,可以在Java代码中执行Python脚本。12345678import org.python.util.PythonInterpreter; public class JythonExample { public static void main(String[] args) { PythonInterpreter interpreter = new PythonInterpreter(); interpreter.exec("print('Hello from Python!')"); }}优点:直接运行在JVM上,无需额外的进程通信。能够直接使用Java类。缺点:Jython仅支持Python 2,不支持Python 3。方案2:使用JPypeJPype可以让Python直接调用Java的类方法,并且运行效率较高。安装JPype1pip install jpype1Python调用Java代码12345678910import jpypeimport jpype.imports # 启动JVMjpype.startJVM(classpath=["myjava.jar"]) from java.lang import SystemSystem.out.println("Hello from Java!") jpype.shutdownJVM()优点:运行效率高,直接调用Java方法。支持Python 3。缺点:需要JVM环境。方案3:使用Py4JPy4J提供了一种轻量级的方式,使Python可以调用Java代码,适用于大多数场景。安装Py4J1pip install py4jJava服务器端代码12345678910111213import py4j.GatewayServer; public class JavaApp { public String hello(String name) { return "Hello, " + name; } public static void main(String[] args) { JavaApp app = new JavaApp(); GatewayServer server = new GatewayServer(app); server.start(); }}Python客户端代码12345from py4j.java_gateway import JavaGateway gateway = JavaGateway()java_app = gateway.entry_pointprint(java_app.hello("Python"))优点:轻量级,不依赖JVM。适用于分布式系统。缺点:需要启动Java服务器。方案4:使用Jep(Java Embedded Python)Jep可以让Java嵌入Python代码,适用于Java调用Python的场景。安装Jep1pip install jepJava调用Python代码12345678910import jep.Interpreter;import jep.SharedInterpreter; public class JepExample { public static void main(String[] args) { try (Interpreter interp = new SharedInterpreter()) { interp.exec("print('Hello from Python!')"); } }}优点:运行速度快。支持Python 3。缺点:需要Python和Java的环境兼容。方案5:使用gRPC进行跨语言通信gRPC是一个高效的RPC框架,支持Python和Java的交互。定义gRPC服务(.proto文件)123456789101112syntax = "proto3";service Greeter { rpc SayHello (HelloRequest) returns (HelloReply);} message HelloRequest { string name = 1;} message HelloReply { string message = 1;}Python服务器端实现123456789101112131415import grpcfrom concurrent import futuresimport hello_pb2import hello_pb2_grpc class GreeterServicer(hello_pb2_grpc.GreeterServicer): def SayHello(self, request, context): return hello_pb2.HelloReply(message=f"Hello, {request.name}!") def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) hello_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server) server.add_insecure_port('[::]:50051') server.start() server.wait_for_termination()Java客户端实现1234567891011121314import io.grpc.ManagedChannel;import io.grpc.ManagedChannelBuilder;import hello.GreeterGrpc;import hello.HelloRequest; public class GrpcClient { public static void main(String[] args) { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051).usePlaintext().build(); GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel); HelloRequest request = HelloRequest.newBuilder().setName("Java").build(); System.out.println(stub.sayHello(request).getMessage()); channel.shutdown(); }}优点:高效,支持远程调用。适用于微服务架构。缺点:需要额外的gRPC服务配置。总结方案适用场景主要优点主要缺点JythonJVM环境,Python 2直接运行在JVM,无需额外通信仅支持Python 2JPypePython调用Java运行高效需要JVMPy4J轻量级通信易用需要Java服务器JepJava调用Python高效需要兼容环境gRPC分布式系统高效远程调用需要额外配置选择合适的方案取决于项目需求
-
一、核心技术选型和优化pdf2docx库: 这是你的核心转换引擎。虽然pdf2docx已经很不错,但仍然需要针对你的特定需求进行优化。安装: pip install pdf2docx性能分析: 使用cProfile或line_profiler分析转换过程中的瓶颈。 重点关注CPU密集型操作,例如图像处理、字体渲染和布局分析。参数调优: pdf2docx可能提供一些参数来控制转换质量和速度。 仔细阅读文档,尝试不同的参数组合,找到最佳平衡点。多线程/多进程: 对于批量转换,这是提高效率的关键。 使用threading或multiprocessing模块并行处理多个PDF文件。 multiprocessing通常更适合CPU密集型任务,因为它能绕过Python的全局解释器锁(GIL)。-** 错误处理**: PDF文件格式复杂多样,转换过程中难免会遇到错误。 编写健壮的错误处理代码,例如使用try-except块捕获异常,并记录错误信息。 可以考虑跳过无法转换的文件,或者提供用户手动修复的选项。其他依赖库: 选择一个合适的GUI库,例如Tkinter (Python自带), PyQt, wxPython或Kivy。 Tkinter简单易用,但功能相对有限。 PyQt和wxPython功能更强大,但需要额外安装。 Kivy适合跨平台开发,但学习曲线较陡峭。文件选择对话框:: 使用GUI库提供的文件选择对话框,方便用户选择PDF文件和输出目录。进度条: 使用GUI库提供的进度条控件,实时显示转换进度。日志记录: 使用logging模块记录程序运行日志,方便调试和问题排查。二、批量转换实现参考以下代码实现。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677import osimport threadingfrom pdf2docx import Converterimport timeimport logging # 配置日志logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def convert_pdf_to_docx(pdf_path, docx_path, progress_callback=None): """ 将单个PDF文件转换为Word文件。 Args: pdf_path: PDF文件路径。 docx_path: Word文件路径。 progress_callback: 可选的回调函数,用于更新进度条。 """ try: cv = Converter(pdf_path) cv.convert(docx_path, start=0, end=None) # 可以指定转换的页码范围 cv.close() logging.info(f"Successfully converted {pdf_path} to {docx_path}") if progress_callback: progress_callback(1) # 假设每个文件完成时进度增加1 except Exception as e: logging.error(f"Error converting {pdf_path}: {e}") def batch_convert(pdf_files, output_dir, progress_callback=None): """ 批量将PDF文件转换为Word文件。 Args: pdf_files: PDF文件列表。 output_dir: 输出目录。 progress_callback: 可选的回调函数,用于更新进度条。 """ total_files = len(pdf_files) converted_count = 0 threads = [] for pdf_file in pdf_files: pdf_filename = os.path.basename(pdf_file) docx_filename = os.path.splitext(pdf_filename)[0] + ".docx" docx_path = os.path.join(output_dir, docx_filename) # 创建线程进行转换 thread = threading.Thread(target=convert_pdf_to_docx, args=(pdf_file, docx_path, progress_callback)) threads.append(thread) thread.start() # 等待所有线程完成 for thread in threads: thread.join() logging.info("Batch conversion completed.") # 示例用法 (需要替换为实际的文件列表和目录)if __name__ == '__main__': pdf_files = ["path/to/file1.pdf", "path/to/file2.pdf"] # 替换为你的PDF文件列表 output_dir = "path/to/output" # 替换为你的输出目录 # 创建输出目录 if not os.path.exists(output_dir): os.makedirs(output_dir) # 模拟进度条回调函数 def update_progress(increment): global converted_count converted_count += increment print(f"Progress: {converted_count}/{len(pdf_files)}") start_time = time.time() batch_convert(pdf_files, output_dir, update_progress) end_time = time.time() print(f"Total time taken: {end_time - start_time:.2f} seconds")三、用户界面设计简洁易用:界面应该简洁明了,用户能够轻松找到所需的功能。文件选择:提供文件选择对话框,允许用户选择单个或多个PDF文件。目录选择::提供目录选择对话框,允许用户选择输出目录。进度显示:使用进度条控件实时显示转换进度。状态信息:显示转换状态信息,例如已转换文件数、剩余文件数、错误信息等。取消功能:提供取消转换的功能。设置选项 (可选):可以提供一些设置选项,例如转换质量、是否保留图像、是否合并多个PDF文件等。四、提高效率的策略1、多线程/多进重如前所述,这是提高批量转换效率的关键。2、异步操作在GUI线程中执行耗时操作会导致界面卡顿。使用线程或进程将转换任务放到后台执行,避免阻塞GUI线程。3、优化图像处理PDF文件中的图像可能会影响转换速度。 可以尝试降低图像分辨率或使用更高效的图像处理算法。4、缓存如果需要多次转换相同的文件,可以考虑将转换结果缓存起来,避免重复转换。3、避免不必要的重绘在更新GUI界面时,尽量避免不必要的重绘操作,例如只更新进度条的值,而不是整个界面。四、用户界面流畅性多线程/多进程:如前所述,这是提高批量转换效率的关键。异步操作:在GUI线程中执行耗时操作会导致界面卡顿。使用线程或进程将转换任务放到后台执行,避免阻塞GUI线程。优化图像处理::PDF文件中的图像可能会影响转换速度。可以尝试降低图像分辨率或使用更高效的图像处理算法。缓存:如果需要多次转换相同的文件,可以考虑将转换结果缓存起来,避免重复转换。避免不必要的重绘:在更新GUI界面时,尽量避免不必要的重绘操作,例如只更新进度条的值,而不是整个界面。五、用户界面流畅性避免长时间阻塞GUI线程:这是导致界面卡顿的主要原因。 将耗时操作放到后台线程执行。使用after方法 (Tkinter):Tkinter的after方法允许你延迟执行某个函数,从而避免阻塞GUI线程。 可以使用after方法定期更新进度条。使用QThread (PyQt):PyQt提供了QThread类,用于在后台线程中执行任务。 可以使用信号和槽机制将后台线程的进度信息传递给GUI线程。使用wx.CallAfter (wxPython):wxPython提供了wx.CallAfter函数,用于在GUI线程中执行某个函数。 可以使用wx.CallAfter函数更新GUI界面。避免频繁更新GUI:频繁更新GUI界面会消耗大量资源。尽量减少更新频率,例如只在进度发生变化时才更新进度条。六、100% 离线确保所有依赖库都已安装:重在打包软件时,确保所有依赖库都已包含在内。可以使用PyInstaller、cx_Freeze或Nuitka等工具将Python代码打包成可执行文件。不依赖网络资源:避免使用任何需要网络连接的资源,例如在线字体、在线API等。示例代码 (使用Tkinter和threading):123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139import tkinter as tkfrom tkinter import filedialog, messageboximport osimport threadingfrom pdf2docx import Converterimport timeimport logging # 配置日志logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def convert_pdf_to_docx(pdf_path, docx_path, progress_callback=None): """ 将单个PDF文件转换为Word文件。 Args: pdf_path: PDF文件路径。 docx_path: Word文件路径。 progress_callback: 可选的回调函数,用于更新进度条。 """ try: cv = Converter(pdf_path) cv.convert(docx_path, start=0, end=None) # 可以指定转换的页码范围 cv.close() logging.info(f"Successfully converted {pdf_path} to {docx_path}") if progress_callback: progress_callback(1) # 假设每个文件完成时进度增加1 except Exception as e: logging.error(f"Error converting {pdf_path}: {e}") return False return True def batch_convert(pdf_files, output_dir, progress_callback=None): """ 批量将PDF文件转换为Word文件。 Args: pdf_files: PDF文件列表。 output_dir: 输出目录。 progress_callback: 可选的回调函数,用于更新进度条。 """ total_files = len(pdf_files) converted_count = 0 threads = [] success_count = 0 for pdf_file in pdf_files: pdf_filename = os.path.basename(pdf_file) docx_filename = os.path.splitext(pdf_filename)[0] + ".docx" docx_path = os.path.join(output_dir, docx_filename) # 创建线程进行转换 thread = threading.Thread(target=convert_pdf_to_docx_wrapper, args=(pdf_file, docx_path, progress_callback)) threads.append(thread) thread.start() # 等待所有线程完成 for thread in threads: thread.join() logging.info("Batch conversion completed.") return success_count def convert_pdf_to_docx_wrapper(pdf_path, docx_path, progress_callback): global success_count if convert_pdf_to_docx(pdf_path, docx_path, progress_callback): success_count += 1 def select_pdf_files(): global pdf_files pdf_files = filedialog.askopenfilenames(filetypes=[("PDF files", "*.pdf")]) pdf_listbox.delete(0, tk.END) for file in pdf_files: pdf_listbox.insert(tk.END, os.path.basename(file)) def select_output_dir(): global output_dir output_dir = filedialog.askdirectory() output_dir_label.config(text=f"Output Directory: {output_dir}") def start_conversion(): global pdf_files, output_dir, success_count if not pdf_files: messagebox.showerror("Error", "Please select PDF files.") return if not output_dir: messagebox.showerror("Error", "Please select an output directory.") return total_files = len(pdf_files) progress_var.set(0) progress_bar["maximum"] = total_files success_count = 0 def update_progress(increment): progress_var.set(progress_var.get() + increment) root.update_idletasks() # 强制更新GUI def conversion_thread(): start_time = time.time() successful_conversions = batch_convert(pdf_files, output_dir, update_progress) end_time = time.time() messagebox.showinfo("Info", f"Conversion completed. Successfully converted {successful_conversions} out of {total_files} files. Total time taken: {end_time - start_time:.2f} seconds") # 启动后台线程 threading.Thread(target=conversion_thread).start() # GUI setuproot = tk.Tk()root.title("PDF to Word Converter") pdf_files = []output_dir = ""success_count = 0 # PDF file selectionpdf_button = tk.Button(root, text="Select PDF Files", command=select_pdf_files)pdf_button.pack(pady=10) pdf_listbox = tk.Listbox(root, width=50)pdf_listbox.pack() # Output directory selectionoutput_button = tk.Button(root, text="Select Output Directory", command=select_output_dir)output_button.pack(pady=10) output_dir_label = tk.Label(root, text="Output Directory: ")output_dir_label.pack() # Progress barprogress_var = tk.IntVar()progress_bar = tk.Scale(root, variable=progress_var, orient=tk.HORIZONTAL, length=300, showvalue=False)progress_bar.pack(pady=10) # Start conversion buttonconvert_button = tk.Button(root, text="Start Conversion", command=start_conversion)convert_button.pack(pady=10) root.mainloop()六、关键点总结性能分析和优化是关键:不要盲目地使用多线程,先找到瓶颈,然后针对性地进行优化。错误处理至关重要:PDF文件格式复杂,要做好充分的错误处理准备。用户界面要简洁易用:让用户能够轻松完成转换任务。使用异步操作,避免阻塞GUI线程:保证用户界面的流畅性。充分测试: 在不同的PDF文件上进行测试,确保软件的稳定性和可靠性。
-
核心功能设计1.自动保存与云端同步(可选)2.待办事项任务增删改查优先级标记完成状态追踪3.用户界面多窗口便签布局系统托盘常驻深色/浅色主题切换4.便签管理富文本编辑(支持加粗/斜体/颜色)支持基础的富文本编辑功能,包括文字加粗(Ctrl+B)、斜体(Ctrl+I)、下划线(Ctrl+U)以及字体颜色调整(支持16进制色值或预设色板)示例:高亮重要事项时可用红色标注截止日期,或通过加粗标记关键信息扩展功能:支持字号调整(12pt-24pt)、项目符号列表和多级标题格式本地修改实时自动保存,防丢失机制确保意外关闭时可恢复内容通过账户系统(如Google/微信登录)实现跨设备同步,支持手动触发同步按钮技术说明:采用增量同步策略,冲突时保留最新版本并生成历史备份(保留7天记录)增:通过浮动按钮或快捷键(Ctrl+N)快速创建任务,支持语音输入转文字删:左滑删除或右键移至回收站(保留30天),重要任务需二次确认改:双击任务进入编辑模式,支持拖拽调整事项顺序查:按关键词/日期范围筛选,示例:"显示本周含'会议'的高优先级任务"四级优先级体系:紧急(红色❗)、高(橙色▲)、中(蓝色●)、低(灰色↓)智能排序:优先显示未完成的高优先级事项,已完成任务自动折叠复选框点击标记完成,自动添加完成时间戳统计面板:每日/周任务完成率环形图,支持导出CSV格式周报主界面采用瀑布流布局,支持:分栏模式:左侧任务列表/右侧富文本编辑区自由窗口:拖动便签形成独立悬浮窗口(适合多显示器用户)快捷键:Ctrl+←/→快速切换窗口焦点最小化后保留托盘图标,右键菜单提供:快速新建便签全局快捷键唤醒(如Alt+Space)临时便签贴边隐藏模式两套预设主题:浅色:#FFFFFF背景+#333333文字深色:#1E1E1E背景+#E0E0E0文字自动切换:根据系统主题变化/定时切换(如20:00-8:00自动深色模式)高级设置:自定义强调色(如将深色模式的重点色改为莫兰迪绿)技术栈选择12345# 主要依赖库import tkinter as tk # 基础GUI框架from tkinter import scrolledtext, messageboximport json # 数据存储import sys关键代码实现1. 主窗口与数据初始化123456789101112class NoteApp: def __init__(self): self.root = tk.Tk() self.root.title("PyNote") self.notes = self.load_data() # 加载历史数据 # 创建菜单栏 self.menu = tk.Menu(self.root) self.root.config(menu=self.menu) file_menu = tk.Menu(self.menu, tearoff=0) file_menu.add_command(label="新建便签", command=self.new_note) self.menu.add_cascade(label="文件", menu=file_menu)2. 便签编辑器组件1234567891011def create_note_window(self, note_id): window = tk.Toplevel(self.root) text_area = scrolledtext.ScrolledText(window, wrap=tk.WORD, width=40, height=20) text_area.pack(fill=tk.BOTH, expand=True) # 插入历史内容 if note_id in self.notes: text_area.insert(tk.INSERT, self.notes[note_id]["content"]) # 实时保存机制 text_area.bind("<KeyRelease>", lambda e: self.save_note(note_id, text_area.get("1.0", tk.END)))3. 待办事项管理器123456789101112131415def todo_list(self): todo_window = tk.Toplevel(self.root) frame = tk.Frame(todo_window) frame.pack(pady=10) self.task_entry = tk.Entry(frame, width=30) self.task_entry.pack(side=tk.LEFT) add_btn = tk.Button(frame, text="添加", command=self.add_task) add_btn.pack(side=tk.LEFT, padx=5) # 任务列表 self.task_listbox = tk.Listbox(todo_window, width=50) self.task_listbox.pack(pady=10) self.task_listbox.bind("<Double-Button-1>", self.toggle_task)数据持久化方案1234567891011def load_data(self): try: with open("notes.json", "r") as f: return json.load(f) except FileNotFoundError: return {} # 首次使用返回空字典 def save_note(self, note_id, content): self.notes[note_id] = {"content": content, "timestamp": time.time()} with open("notes.json", "w") as f: json.dump(self.notes, f) # 增量保存高级功能扩展思路云端同步添加Dropbox API实现跨设备同步:1234import dropboxdbx = dropbox.Dropbox("<ACCESS_TOKEN>")with open("notes.json", "rb") as f: dbx.files_upload(f.read(), "/notes.json")语音输入便签集成语音识别库:12345import speech_recognition as srr = sr.Recognizer()with sr.Microphone() as source: audio = r.listen(source)text = r.recognize_google(audio, language="zh-CN")智能提醒用APScheduler定时检测任务:123from apscheduler.schedulers.background import BackgroundSchedulerscheduler = BackgroundScheduler()scheduler.add_job(check_due_tasks, 'interval', minutes=30)总结通过本文实现的智能时间管理工具具有以下核心优势:极简依赖基于Python标准库构建,仅需额外200KB的轻量级组件(如pendulum时间处理库)对比同类工具(如需要GB级运行环境的Electron应用),资源占用降低99%全平台覆盖经测试完美兼容:Windows 10/11(包括WSL)macOS Monterey及以上Linux主流发行版(Ubuntu/Fedora/Arch等)单代码库实现跨平台,无需针对不同系统维护多个版本模块化扩展能力已预留标准化接口,可快速集成:日历同步(Google Calendar/Outlook API)邮件提醒(SMTP/IMAP协议支持)云存储(自动备份至Dropbox/OneDrive)扩展示例:添加Notion API仅需约50行代码进阶建议:Markdown支持实现任务描述的富文本编辑(如表格、代码块)输出周报时可自动转换为PDF/HTML格式任务依赖可视化通过Graphviz生成甘特图关键路径分析功能(CPM算法)
-
核心功能模块解析1. 智能检索与即时启动系统现代高效启动器的检索系统采用多维度匹配算法:模糊匹配:支持拼写容错(如输入"excel"可匹配"excle")语义分析:理解用户意图(如"表格软件"自动关联Excel/WPS)权重记忆:根据使用频率自动排序结果(经常使用的程序优先显示)典型应用场景示例:用户输入"ps" → 显示Photoshop(使用频率最高)输入"photo" → 列出Photoshop、Lightroom等图形软件输入"设计" → 显示所有设计类软件和最近设计文档2. 可扩展的插件生态系统开放架构设计允许深度功能定制:基础插件示例:计算器:直接输入"calc 15*20+30"获取结果单位转换:"convert 5ft to cm"系统命令:休眠/重启/清空回收站服务集成:翻译引擎对接(输入"fy hello"自动翻译)API调用(股票查询、天气获取)云服务快捷操作(快速打开网盘指定文件夹)开发者可通过提供的SDK创建自定义插件,典型开发流程:定义插件元数据(名称/描述/触发词)实现核心逻辑处理函数注册输入输出处理器打包发布到插件市场3. 性能优化引擎为确保"随时待命"的响应能力,采用多层优化策略:内存管理:主进程常驻内存占用控制在15MB以内采用LRU缓存机制管理资源索引闲置时自动释放非必要资源启动加速技术:预加载高频应用图标和元数据建立文件系统变更监听机制使用内存映射文件加速索引查询性能指标示例(在i5-8250U/8GB配置下):操作类型平均响应时间应用启动0.3s文件搜索0.5s插件执行0.8s4. 全平台兼容架构采用"核心+适配层"的设计模式:核心引擎:平台无关的业务逻辑和算法平台适配层:Windows:Win32 API/WPF集成macOS:Cocoa框架封装Linux:GTK/QT接口实现跨平台特性对比表:功能WindowsmacOSLinux全局快捷键√√需配置文件监控实时实时inotify深色模式自动自动手动切换5. 人机交互优化设计输入界面:支持多重触发方式:全局热键(默认Ctrl+Space)鼠标手势触发任务栏图标点击智能输入建议:命令自动补全历史记录联想错误输入校正输出界面:极简布局设计(单行输入+结果列表)动态结果分组(应用/文件/操作分类显示)视觉反馈系统:输入时实时预览结果高亮匹配部分执行状态动画指示主题定制:内置10+精心设计的配色方案支持CSS级样式自定义社区主题市场共享机制技术实现深度解析实现高效启动器涉及多项关键技术:索引引擎:使用改进的倒排索引结构定期增量更新策略(避免全量重建)支持NTFS/APFS/ext4等文件系统特性事件处理模型:graph TDA[热键触发] --> B[创建输入窗口]B --> C[接收用户输入]C --> D[并行处理]D --> E[插件匹配]D --> F[应用搜索]D --> G[文件检索]E & F & G --> H[结果聚合排序]H --> I[交互呈现]安全机制:沙箱环境运行插件敏感操作二次确认自动更新签名验证这套技术架构使得现代快捷启动器既能保持轻量级特性,又能提供强大的功能扩展能力,真正成为用户数字工作流的效率中枢。别名映射系统自定义简写功能:允许用户为常用应用、文件或文件夹创建简短易记的别名示例:将"photoshop"映射为"ps"示例:将"D:\工作文档\季度报告"映射为"report"路径存储机制:使用轻量级数据库或JSON文件存储别名-路径对应关系支持批量导入/导出映射配置提供图形界面和命令行两种配置方式智能检索系统模糊匹配算法:基于编辑距离的相似度计算支持拼音首字母匹配(对中文用户特别有用)示例:输入"vsc"可匹配到"Visual Studio Code"关键词搜索优化:建立本地索引提高响应速度支持多关键词组合搜索搜索结果智能排序(基于使用频率、最近使用等)搜索交互:输入时实时显示匹配结果支持方向键选择和自动补全即时启动引擎极速响应:启动延迟控制在100ms以内采用多线程处理规避界面卡顿多类型支持:可执行程序(.exe等)文档文件(.docx,.pdf等)网页链接系统命令(关机、锁屏等)环境兼容:正确处理带空格和特殊字符的路径支持管理员权限启动选项处理多实例应用场景扩展考量使用统计:记录高频使用项目优化排序插件系统:支持计算器、单位换算等快捷功能多平台支持:Windows/macOS/Linux的适配方案此设计确保启动器在保持轻量级的同时,提供流畅高效的用户体验。配置文件设计使用JSON格式存储别名映射:12345{ "code": "C:\\Program Files\\VSCode\\Code.exe", "doc": "D:\\Documents", "ps": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"}核心代码实现1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768import osimport jsonimport subprocessfrom pathlib import Path CONFIG_PATH = Path.home() / ".quick_launcher.json" def load_config(): """加载配置文件""" if not CONFIG_PATH.exists(): with open(CONFIG_PATH, 'w') as f: json.dump({}, f) return {} with open(CONFIG_PATH) as f: return json.load(f) def save_config(config): """保存配置文件""" with open(CONFIG_PATH, 'w') as f: json.dump(config, f, indent=4) def launch_target(target): """启动目标应用/文件""" if os.name == 'nt': # Windows系统 os.startfile(target) else: # macOS/Linux系统 subprocess.run(['open' if sys.platform == 'darwin' else 'xdg-open', target]) def add_alias(alias, path): """添加新别名""" config = load_config() config[alias] = os.path.abspath(path) save_config(config) print(f"已添加: {alias} -> {path}") def search_aliases(keyword): """搜索匹配的别名""" config = load_config() return [k for k in config.keys() if keyword.lower() in k.lower()] def main_loop(): """主交互循环""" print(" Python快捷启动器 (输入 exit 退出)") while True: command = input("\n输入别名或命令 > ").strip() if command == "exit": break if command.startswith("add "): _, alias, path = command.split(maxsplit=2) add_alias(alias, path) continue config = load_config() if command in config: print(f"正在启动: {command}") launch_target(config[command]) else: matches = search_aliases(command) if matches: print(f"找到匹配项: {', '.join(matches)}") else: print("未找到匹配项,使用 add <别名> <路径> 添加") if __name__ == "__main__": main_loop()使用示例输入别名或命令 > add py C:\Python39\python.exe已添加: py -> C:\Python39\python.exe 输入别名或命令 > py正在启动: py(成功启动Python解释器) 输入别名或命令 > doc正在启动: doc(打开文档目录) 输入别名或命令 > ex找到匹配项: excel功能扩展建议快捷键支持注册全局快捷键触发启动器:支持自定义热键组合(如Ctrl+Alt+Space),在任何界面下都能快速呼出启动器示例配置:支持在config.json中设置hotkey: "Ctrl+Shift+K"使用统计智能排序功能:自动记录命令使用频率,将常用命令置顶显示统计维度包括:调用次数、最近使用时间、使用场景等统计周期:支持按日/周/月查看使用趋势网络扩展URL处理:支持直接输入网址(如https://example.com)调用默认浏览器打开远程资源访问:支持通过SSH协议连接服务器,执行远程命令API集成:可配置常见网络服务(如GitHub、JIRA等)的快捷访问插件系统插件架构:采用模块化设计,通过plugins目录自动加载扩展脚本支持:可用Python/Lua等编写自定义功能插件插件示例:天气查询、货币换算、翻译等实用工具技术优势跨平台兼容性完整支持三大操作系统:Windows (7/10/11)macOS (10.15+)Linux (主流通用发行版)系统特性适配:自动识别平台差异,确保一致体验轻量化设计零外部依赖:仅使用各平台标准库,无需额外运行环境资源占用:内存<50MB,CPU使用率<1%单文件部署:支持打包为独立可执行文件智能配置首次运行自动生成:配置文件(~/.config/launcher/config.json)日志文件(~/logs/launcher.log)配置热加载:修改配置无需重启应用交互优化输入提示:实时显示匹配结果数量和类型智能补全:文件路径补全(支持Tab键)命令参数提示历史记录回溯性能表现响应时间:冷启动:<800ms热启动:<100ms命令执行:<50ms(简单命令)性能优化:预加载机制缓存策略并行处理使用建议效率提升技巧:将常用软件目录加入PATH变量为高频命令设置别名定期清理不再使用的命令典型应用场景:快速启动IDE/编辑器执行系统管理命令访问常用文档/项目日常计算/单位换算进阶配置:12345{ "max_history": 1000, "theme": "dark", "default_search": "google"}
-
1.核心内置容器1. 列表类型名: list可变性: 可变有序性: 有序(元素按插入顺序排列,可通过索引访问)元素要求: 可存放任意类型、可重复的元素。语法: 使用方括号 [] 创建,元素用逗号分隔。主要特性:最通用、最常用的序列类型。支持丰富的操作:索引 (lst[0])、切片 (lst[1:3])、拼接 (+)、重复 (*)、成员检查 (in)。提供多种方法来修改内容:.append(), .insert(), .pop(), .remove(), .sort() 等。123my_list = [1, 2, 'hello', 3.14, 1] # 可重复,不同类型my_list[0] = 100 # 可变,可以修改元素print(my_list) # 输出: [100, 2, 'hello', 3.14, 1]2. 元组类型名: tuple可变性: 不可变有序性: 有序(元素按插入顺序排列,可通过索引访问)元素要求: 可存放任意类型、可重复的元素。语法: 使用圆括号 () 创建,元素用逗号分隔。单元素元组需加逗号(如 (1,))。主要特性:一旦创建,其内容无法修改(但如果元素本身是可变对象,如列表,则该列表的内容可以修改)。因其不可变性,常用于需要数据安全、保证不会被更改的场景,如作为字典的键、函数返回多个值等。性能通常略优于列表。1234my_tuple = (1, 2, 'world', [3, 4])# my_tuple[0] = 100 # 错误!元组不可变my_tuple[3].append(5) # 正确。因为元组中的列表是可变的print(my_tuple) # 输出: (1, 2, 'world', [3, 4, 5])3. 集合类型名: set可变性: 可变有序性: 无序(Python 3.7+ 后,实现细节上保留了插入顺序,但绝不能依赖于此进行编程。从语言定义上讲,它是无序的)。元素要求: 元素必须是可哈希的(如数字、字符串、元组等不可变类型)。元素不可重复。语法: 使用花括号 {} 创建(但空集合必须用 set() 创建),元素用逗号分隔。主要特性:核心功能是去重和成员关系测试(检查元素是否存在),这两项操作效率极高(时间复杂度为 O(1))。支持数学上的集合运算:并集 (|), 交集 (&), 差集 (-), 对称差集 (^)。1234my_set = {1, 2, 3, 2, 'hello'} # 自动去重print(my_set) # 输出可能是 {1, 2, 3, 'hello'} (顺序不确定)my_set.add(4) # 可变,可以添加元素print(2 in my_set) # 成员检查,输出: True4. 冻结集合类型名: frozenset可变性: 不可变有序性: 无序元素要求: 同 set,元素必须是可哈希的且不可重复。语法: 使用 frozenset() 函数创建,可传入一个可迭代对象(如列表、元组)。主要特性:具有 set 的所有特性(去重、成员测试、集合运算),但内容不可变。因其不可变性,它本身是可哈希的,因此可以作为字典的键或另一个集合的元素。123my_frozenset = frozenset([1, 2, 2, 3])print(my_frozenset) # 输出: frozenset({1, 2, 3})# my_frozenset.add(4) # 错误!不可变集合5. 字典类型名: dict可变性: 可变有序性: 有序(自 Python 3.7 起,字典正式保持键的插入顺序)。元素要求: 键必须是可哈希的,值可以是任意对象。键不可重复。语法: 使用花括号 {} 创建,键值对形式 key: value,用逗号分隔。空字典为 {}。主要特性:存储键值对映射关系,通过键来高效地查找、插入和删除对应的值(时间复杂度为 O(1))。是 Python 中极其重要的数据结构。1234my_dict = {'name': 'Alice', 'age': 25, 1: 'number'}my_dict['country'] = 'USA' # 添加新的键值对print(my_dict['name']) # 通过键访问值,输出: Aliceprint(list(my_dict.keys())) # 输出键列表: ['name', 'age', 1, 'country'] (保持插入顺序)2.collections模块中的高级集合 collections 模块提供了多种专门化的容器数据类型,它们是对 Python 通用内置容器(如字典、列表、集合)的强大补充。这些数据结构针对特定用例进行了优化,能够提供更好的性能或更便利的接口。6. 命名元组 namedtuple 是元组的子类,它为元组的每个位置分配一个名称,同时保留元组的特性(不可变、有序、可通过索引访问)。普通元组需要通过数字索引访问元素(如 point[0], point[1]),这使得代码可读性差且容易出错。namedtuple 允许使用有意义的名称访问相同的数据。123456789101112131415from collections import namedtuple # 创建一个名为'Point'的namedtuple类,具有字段'x'和'y'Point = namedtuple('Point', ['x', 'y']) # 创建实例p = Point(11, y=22) # 访问字段print(p.x) # 输出: 11print(p.y) # 输出: 22print(p[0]) # 仍然可以通过索引访问: 11 # 不可变性(继承自元组)# p.x = 33 # 这会报错:AttributeError: can't set attribute7. 双端队列 deque是一个线程安全、可以快速从两端添加或删除元素的序列容器。Python 的列表在尾部操作(追加和弹出)非常高效(O(1)时间复杂度),但在头部操作(插入和删除)效率较低(O(n)时间复杂度)。deque 在两端操作都是 O(1) 时间复杂度。123456789101112131415161718192021from collections import deque # 创建双端队列d = deque(['b', 'c', 'd']) # 从左侧添加元素d.appendleft('a') # deque(['a', 'b', 'c', 'd']) # 从右侧添加元素d.append('e') # deque(['a', 'b', 'c', 'd', 'e']) # 从左侧弹出元素left_item = d.popleft() # 'a', deque变为['b', 'c', 'd', 'e'] # 从右侧弹出元素right_item = d.pop() # 'e', deque变为['b', 'c', 'd'] # 限制最大长度(当队列满时,添加新元素会从另一端自动删除元素)limited_deque = deque(maxlen=3)limited_deque.extend([1, 2, 3]) # deque([1, 2, 3], maxlen=3)limited_deque.append(4) # deque([2, 3, 4], maxlen=3) - 自动删除最左边的18. 计数器 Counter 是 dict 的子类,用于统计可哈希对象的出现次数。它是一个无序集合,其中元素存储为字典键,它们的计数存储为字典值。手动统计元素频率需要编写循环和条件判断,而 Counter 提供了简洁高效的接口来完成这一常见任务。12345678910111213141516171819202122from collections import Counter # 从可迭代对象创建words = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']word_count = Counter(words)print(word_count) # Counter({'apple': 3, 'banana': 2, 'orange': 1}) # 从映射创建c = Counter({'red': 4, 'blue': 2}) # Counter({'red': 4, 'blue': 2}) # 从关键字参数创建c = Counter(cats=4, dogs=8) # Counter({'dogs': 8, 'cats': 4}) # 常用操作print(word_count.most_common(2)) # 出现频率最高的2个元素: [('apple', 3), ('banana', 2)] c = Counter(a=3, b=1)d = Counter(a=1, b=2)print(c + d) # 相加: Counter({'a': 4, 'b': 3})print(c - d) # 相减: Counter({'a': 2})print(c & d) # 交集: Counter({'a': 1, 'b': 1})print(c | d) # 并集: Counter({'a': 3, 'b': 2})9. 默认字典 defaultdict 是 dict 的子类,它重写了一个方法并添加了一个可写的实例变量。当尝试访问不存在的键时,它会自动创建该键并使用提供的工厂函数初始化其值。使用普通字典时,访问不存在的键会引发 KeyError,需要先检查键是否存在或使用 get() 方法。defaultdict 自动处理这种情况,使代码更简洁。1234567891011121314151617from collections import defaultdict # 使用list作为工厂函数,当键不存在时创建空列表dd = defaultdict(list) dd['fruits'].append('apple') # 自动创建'fruits'键并初始化为空列表dd['fruits'].append('banana')print(dd) # defaultdict(<class 'list'>, {'fruits': ['apple', 'banana']}) # 使用int作为工厂函数,默认值为0counts = defaultdict(int)counts['apple'] += 1 # 自动创建'apple'键并初始化为0,然后加1print(counts) # defaultdict(<class 'int'>, {'apple': 1}) # 使用lambda函数提供自定义默认值prices = defaultdict(lambda: 10.0) # 默认价格为10.0print(prices['unknown_item']) # 输出: 10.03.numpy数组NumPy 是 Python 科学计算生态系统的基石和核心库。几乎所有处理数据、进行科学计算或机器学习的 Python 工具(如 Pandas, Scikit-learn, SciPy, TensorFlow, PyTorch)都构建在 NumPy 的基础之上。这也是为什么numpy单独开一章来讲!对比一下list与numpy:123456789101112# 使用 Python list (效率低)a = [1, 2, 3, 4]b = [5, 6, 7, 8]result = []for x, y in zip(a, b): result.append(x**2 + y**2) # 使用 NumPy (高效、简洁)import numpy as npa_np = np.array([1, 2, 3, 4])b_np = np.array([5, 6, 7, 8])result_np = a_np**2 + b_np**2 # 直接对整个数组操作numpy无需编写循环,就可以直接对整个数组进行算术运算、逻辑运算等。这得益于其广播(Broadcasting) 机制,使得不同形状的数组可以进行数学运算。广播规则:从尾部维度开始,向前面维度推进,如果两个数组的维度大小相等或其中一个为1,则它们是兼容的,可以进行广播。123456789# 将一个向量加到矩阵的每一行上a = np.array([[1, 2, 3], [4, 5, 6]]) # Shape: (2, 3)b = np.array([10, 20, 30]) # Shape: (3,)# b 的 shape 会被“广播”成 (1, 3),然后再“广播”成 (2, 3)result = a + bprint(result)# [[11 22 33]# [14 25 36]]除此之外numpy还有更多更强大的优势,例如具有丰富的数学函数库提供了大量标准的数学函数(sin, cos, exp, log...)、线性代数运算(矩阵乘法、求逆、行列式...)、随机数生成、傅里叶变换等,全部针对数组进行优化;强大的索引功能,除了类似列表的基础索引,还支持布尔索引、花式索引等,可以非常灵活地访问和修改数组数据。等等优势下面简要介绍一下numpy的基础用法3.1 导入 NumPy1import numpy as np3.2 创建数组1234567891011121314# 从列表创建arr1 = np.array([1, 2, 3, 4, 5]) # 一维数组arr2 = np.array([[1, 2, 3], [4, 5, 6]]) # 二维数组 # 使用内置函数创建zeros_arr = np.zeros((3, 4)) # 创建 3x4 的全0数组ones_arr = np.ones((2, 3)) # 创建 2x3 的全1数组empty_arr = np.empty((2, 2)) # 创建未初始化的数组(内容随机)range_arr = np.arange(0, 10, 2) # 类似 range(), 创建 [0, 2, 4, 6, 8]linspace_arr = np.linspace(0, 1, 5) # 在0到1之间创建5个等间隔的数 [0., 0.25, 0.5, 0.75, 1.] # 创建随机数组random_arr = np.random.rand(3, 2) # 创建 3x2 的数组,元素来自[0,1)的均匀分布randn_arr = np.random.randn(1000) # 创建1000个符合标准正态分布的随机数3.3数组的属性123456arr = np.array([[1, 2, 3], [4, 5, 6]]) print(arr.ndim) # 数组的维数 (秩): 2print(arr.shape) # 数组的维度 (行数, 列数): (2, 3)print(arr.size) # 数组的元素总数: 6print(arr.dtype) # 数组中元素的数据类型: int64 (取决于系统)3.4切片功能1234567891011121314151617181920212223arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) # 基础索引print(arr[0, 1]) # 获取第0行第1列的元素: 2 # 切片 (支持负索引和步长)print(arr[:2, 1:3]) # 前两行,第1到2列: # [[2, 3], # [6, 7]] # 布尔索引 (非常强大!)mask = arr > 5print(mask) # 布尔数组: [[False False False False], # [False True True True], # [ True True True True]]print(arr[mask]) # 获取所有大于5的元素: [ 6 7 8 9 10 11 12] # 花式索引 (使用整数数组进行索引)rows = np.array([0, 2])cols = np.array([1, 3])print(arr[rows, cols]) # 获取(0,1)和(2,3)位置上的元素: [ 2 12]3.5数组计算123456789101112131415161718192021222324a = np.array([1, 2, 3])b = np.array([4, 5, 6]) # 元素级运算print(a + b) # [5 7 9]print(a * b) # [4 10 18] (逐元素相乘,不是矩阵乘法!)print(a ** 2) # [1 4 9]print(np.sin(a)) # 对每个元素求正弦 # 矩阵乘法 (使用 @ 运算符或 .dot() 方法)x = np.array([[1, 2], [3, 4]])y = np.array([[5, 6], [7, 8]])print(x @ y) # 矩阵乘法: [[19 22], # [43 50]]print(x.dot(y)) # 同上 # 聚合函数 (对整组数据进行计算)arr = np.array([1, 2, 3, 4, 5])print(arr.sum()) # 总和: 15print(arr.mean()) # 平均值: 3.0print(arr.std()) # 标准差print(arr.min()) # 最小值: 1print(arr.max()) # 最大值: 5print(arr.argmax()) # 最大值的索引: 4
-
一. .dll文件生成c++代码 .cpp文件234567891011121314#include <iostream> // 导出函数声明,供外部调用extern "C" __declspec(dllexport) int add(int a, int b);extern "C" __declspec(dllexport) void greet(); // 函数实现int add(int a, int b) { return a + b;} void greet() { std::cout << "Hello from MyDLL!" << std::endl;}windows环境下使用命令生成.dllg++ -shared -o demo.dll demo.cpp -Wl,--out-implib=libdemo.a -static-libstdc++1234567891011命令参数说明:-shared:指定生成动态链接库(.dll)-o mydll.dll:指定输出的 DLL 文件名-Wl,--out-implib=libmydll.a:生成导入库(.a 文件),供其他程序链接时使用 执行成功后,会生成三个文件:mydll.dll:动态链接库本体libmydll.a:MinGW 格式的导入库mydll.exp:导出符号文件(辅助文件) libstdc++-static-libstdc++:静态链接 C++ 标准库,将std::cout等实现打包到你的 DLL 中二. python引用.dll文件123456from ctypes import *pdll = CDLL("E:\\project\\dll_demo\\demo.dll")c = pdll.add(1,2)print(c) pdll.greet() python调用结果3Hello from MyDLL!
-
1.获取你的word模板内容简单粗暴的方式,可以直接帮你看到你的模板每一个内容的数据及占位点(索引),其中当数据为字符串的内容,大多是直接展示,而当你看到某一个数据的为 " "字符串时,此时注意观察你模板中的上下文,该位置可能表示了你模板中的表格或者图形的占位(先记住,后面会用到!!)12345678def run(): text0 = doc.paragraphs[0].text text1 = doc.paragraphs[1].text text2 = doc.paragraphs[2].text ... if __name__ == '__main__': run()2.正常文本内容的替换当我们发现我们需要替换一段文字的时候,首先找到该段文字表示的位置,假如 text0 = doc.paragraphs[0].text 此时是一段文字123456789101112131415161718192021# 省略导包,根据代码缺失的去安装 new_file_path = 'xxx' # 文件路径doc = Document(new_file_path) paragraphs_1_text = '这是我要替换的文字' # 通用替换文本方式def replace_paragraph_text(paragraph, new_text): """可以在该方法下新增对特定段落的额外处理""" # 遍历段落中的所有 runs for run in paragraph.runs: run.text = "" # 清空每个 run 的文本 # 将新文本插入到第一个 run 中,保留样式 paragraph.runs[0].text = new_text if __name__ == '__main__': text0 = "这是原来的文字" # 假设你的text0是这段文字 replace_paragraph_text(doc.paragraphs[0], paragraphs_1_text) # doc.paragraphs[0]为你段落的位置, paragraphs_1_text则是要替换的文本。 """ 使用该方式即可替换所有文字的段落 """3.表格内容的替换当发现我上面说的那种数据为空字符串的时候,而且你在模板中发现其为表格,就可以使用我下面的方式进行替换,一般表格的替换比较特殊,tables0 = doc.tables[xxx]来写表格的索引,可以不用去看段落的索引,而是根据你模板中的表格的数量索引来看,第一个表格索引就是0,以此类推。123456789101112131415161718192021222324252627282930313233343536373839404142tables0 = doc.tables[xxx] # 写你表格索引 def set_font_table(para, font_name="仿宋", font_size=12, char_spacing=None, bold=True): """ 设置段落的字体为指定字体和大小,并可设置字间距,同时支持加粗 """ for run in para.runs: run.font.name = font_name run.font.size = Pt(font_size) run.font.bold = bold # 设置加粗 if char_spacing: run.font.spacing = char_spacing """可选部分,看是否删除表的数据 """#for row_index in range(len(tables0.rows)-1, 0, -1): # 从最后一行开始删除到第二行# if row_index > 0: # 确保不删除表头行(假设表头是第一行)# tables0._element.remove(tables8.rows[row_index]._element) # 根据 table_data 重新添加行和填充数据#for row_index, row_data in enumerate(table_data, start=1): # 从第二行开始# # row = tables0.add_row() # 添加新的一行(根据上面是否删除表选择解注)# for col_index in range(min(column_count, len(row_data))): # 保证不会超出列数范围# cell = row.cells[col_index]# cell.text = str(row_data[col_index])# for para in cell.paragraphs:# set_font_table(para, font_name="仿宋", font_size=12, bold=False)# para.alignment = WD_ALIGN_PARAGRAPH.CENTER # 常用部分new_table_data = [[]] # 通常是这个格式,里面的每个[]存每一行表格数据 for row_index, row_data in enumerate(new_table_data, start=1): # 从第二行开始 for col_index, cell_data in enumerate(row_data, start=0): # 从第一列开始 # 获取每个单元格 cell = tables0.cell(row_index, col_index) cell.text = str(cell_data) for para in cell.paragraphs: set_font_table(para, font_name="仿宋", font_size=12, bold=False) para.alignment = WD_ALIGN_PARAGRAPH.CENTER一般通过上述方式可完成替换表格内容4.图形内容的替换首先需要用python的plt 方法进行生成图型(柱状图、折线图等),生成图形这部分代码省略,这里主要讲下如何进行段落替换,直接上代码:123456789101112131415161718192021chart_image_path = generate_bar_chart(数据内容, 地址) # 通过一个方法获取生成的柱状图地址target_paragraph = doc.paragraphs[xxx] # 通过你的上下文段落来判断这里是否是一个图形,找出其对应的索引 old_inline = Nonefor element in target_paragraph._element.findall('.//wp:inline', namespaces={'wp': 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'}):# for element in target_paragraph._element.iter(): if element.tag.endswith("inline"): # 检查是否是 <wp:inline> 元素 old_inline = element breakfrom docx.shared import Inches# 如果找到旧的 <wp:inline> 对象if old_inline is not None: # 插入新图片并获取其 <wp:inline> 对象 new_run = target_paragraph.add_run() new_inline = new_run.add_picture(chart_image_path, width=Inches(5.5))._inline # 替换旧的 <wp:inline> 对象 parent = old_inline.getparent() parent.replace(old_inline, new_inline) # 删除新插入的 run(因为我们已经替换了旧的 <wp:inline>) target_paragraph._p.remove(new_run._element)通常处理这样的word模板,是为了从某一数据源中,固定时间的获取某些数据来替换模板生成我们想要的报告文档之类的东西,为了实现自动化,该替换代码,通常在完成后,会与定时任务相关的东西相结合来使用。
-
什么是鸭子类型?鸭子类型是一种动态类型机制,其核心思想是:对象的行为决定了它的类型,而不是其声明的类型。在Python中,鸭子类型允许我们在运行时动态地检查对象是否具有所需的方法或属性,而不是在编译时或设计时静态地检查类型。例如,考虑以下代码:123456789101112def quack(object): object.quack()class Duck: def quack(self): print("Quack!")class Goose: def quack(self): print("Honk!")duck = Duck()goose = Goose()quack(duck) # 输出: Quack!quack(goose) # 输出: Honk!在这个例子中,quack函数接受任何具有quack()方法的对象。无论传入的是Duck还是Goose,只要它们具有quack()方法,函数都能正常工作。这就是鸭子类型的典型应用。鸭子类型的特点1. 灵活性鸭子类型允许你在代码中处理各种类型的对象,只要它们的行为符合预期。这种灵活性使得代码更具扩展性和复用性。2. 动态性Python在运行时动态地检查对象的行为,而不是在编译时静态地检查类型。这种动态性使得鸭子类型非常适合处理复杂或不确定的场景。3. 简洁性鸭子类型避免了显式的类型检查(如isinstance()),使得代码更加简洁和易于维护。鸭子类型的实现在Python中,鸭子类型的核心在于EAFP(Easier to Ask for Forgiveness than Permission) 原则。与其在使用对象之前检查其类型,不如直接尝试使用它,如果失败则捕获异常。例如:12345678910111213141516def process_data(data): try: data.read() except AttributeError: print("The object does not have a read() method.")class File: def read(self): print("Reading from file...")class NetworkStream: def read(self): print("Reading from network stream...")file = File()network = NetworkStream()process_data(file) # 输出: Reading from file...process_data(network) # 输出: Reading from network stream...process_data("string") # 输出: The object does not have a read() method.在这个例子中,process_data函数尝试调用data.read(),而无需关心data的具体类型。如果data没有read()方法,则会捕获AttributeError异常。鸭子类型的优缺点优点代码简洁:避免了显式的类型检查,使代码更加简洁和易于阅读。高灵活性:能够处理各种类型的对象,只要它们的行为符合预期。松耦合:减少了代码之间的耦合度,使得系统更加模块化和易于扩展。缺点潜在的错误:如果对象没有预期的方法或属性,可能会导致运行时错误。调试困难:由于动态类型,错误可能在运行时才被发现,增加了调试的难度。可读性问题:对于复杂的代码,鸭子类型可能使代码的意图不够清晰。鸭子类型的实际应用1. 插件系统鸭子类型非常适合实现插件系统。例如,一个图像处理软件可以接受任何具有process_image()方法的插件,而无需关心插件的具体类型。2. 框架开发许多Python框架(如Django和Flask)利用鸭子类型来实现灵活的扩展。例如,Django允许开发者定义自定义模板标签,只要它们遵循特定的行为规范。3. 数据处理在数据处理场景中,鸭子类型允许你处理各种数据源(如文件、数据库、网络流等),只要它们提供统一的接口(如read()方法)。总结鸭子类型是Python动态类型系统的重要特性之一,它通过关注对象的行为而非类型,提供了极大的灵活性和简洁性。然而,鸭子类型也有一些潜在的缺点,如运行时错误和调试困难。因此,在使用鸭子类型时,需要权衡其优缺点,并合理设计代码结构。
-
卸载 macOS 上所有版本的 Python查看已安装的 Python先打开终端,执行:1234which -a pythonwhich -a python3ls -l /Library/Frameworks/Python.framework/Versions/ls -l /usr/local/bin/python*这会显示所有 Python 路径,比如:123/usr/bin/python3 ← 系统自带(不要删)/usr/local/bin/python3.11 ← 用户安装的(可删)/Library/Frameworks/Python.framework/Versions/3.11卸载通过官方安装包(.pkg/.dmg)安装的 Python如果是从 python.org 安装的:执行以下命令(以 3.11 为例):12345sudo rm -rf /Library/Frameworks/Python.framework/Versions/3.11sudo rm -f /Applications/Python\ 3.11sudo rm -f /usr/local/bin/python3.11sudo rm -f /usr/local/bin/pip3.11sudo rm -f /usr/local/bin/idle3.11如果有多个版本,重复执行上面命令替换版本号(3.9、3.10、3.12 等)。卸载 Homebrew 安装的 Python如果曾用 brew install python 安装:12brew uninstall pythonbrew cleanup然后确认是否删除干净:12which python3brew list | grep python删除用户环境中可能残留的配置1234rm -rf ~/Library/Pythonrm -rf ~/.local/lib/python*rm -rf ~/.pyenvrm -rf ~/.virtualenvs如果用过 pyenv 安装 Python:12brew uninstall pyenvrm -rf ~/.pyenv检查系统是否还有 Python(保留系统版本)12python3 --versionwhich python3正常情况下,系统还会有一个 /usr/bin/python3(macOS 自带的安全版本)。(可选)清理 PATH 环境变量编辑 shell 配置文件(根据用的 shell):Bash → ~/.bash_profileZsh → ~/.zshrc删除类似:12export PATH="/usr/local/opt/python@3.11/bin:$PATH"export PATH="/Library/Frameworks/Python.framework/Versions/3.11/bin:$PATH"保存后执行:1source ~/.zshrc验证卸载结果12which -a pythonwhich -a python3输出应只剩下系统路径 /usr/bin/python3。macOS Python 一键卸载脚本自动检测并卸载所有非系统版本的 Python(包括官方安装包、Homebrew、Pyenv 等)不会删除 macOS 自带的系统 Python(安全)删除 pip 缓存、虚拟环境和 PATH 中的无效路径使用方法第一步:复制下面脚本到一个文件在终端执行:1nano ~/uninstall_python.sh然后把下面内容完整复制进去保存退出(Ctrl + O → 回车 → Ctrl + X)。脚本内容:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758#!/bin/bashecho "=============================="echo " 🧹 macOS Python 一键卸载脚本"echo "=============================="echo # 检查权限if [ "$EUID" -ne 0 ]; then echo "⚠️ 请使用 sudo 运行此脚本:sudo bash ~/uninstall_python.sh" exitfi # 卸载 Homebrew 安装的 Pythonif command -v brew &>/dev/null; then echo "🍺 正在卸载 Homebrew Python..." brew uninstall --ignore-dependencies python python@3.9 python@3.10 python@3.11 python@3.12 2>/dev/null brew cleanupfi # 删除 python.org 安装包的 Pythonecho "🧾 正在删除官方安装包版本..."for v in 3.9 3.10 3.11 3.12 3.13; do sudo rm -rf /Library/Frameworks/Python.framework/Versions/$v sudo rm -rf "/Applications/Python ${v}" sudo rm -f /usr/local/bin/python${v} sudo rm -f /usr/local/bin/python${v%.*} sudo rm -f /usr/local/bin/pip${v} sudo rm -f /usr/local/bin/idle${v}done # 删除 pyenvecho "🐍 正在删除 pyenv..."brew uninstall pyenv 2>/dev/nullrm -rf ~/.pyenv # 删除虚拟环境和 pip 缓存echo "🧩 删除虚拟环境和缓存..."rm -rf ~/.local/lib/python*rm -rf ~/Library/Pythonrm -rf ~/.virtualenvsrm -rf ~/Library/Caches/pip # 清理 PATH 中的 Python 相关路径echo "🧠 清理 PATH 配置..."for f in ~/.bash_profile ~/.bashrc ~/.zshrc; do [ -f "$f" ] && sed -i '' '/Python.framework/d' "$f" [ -f "$f" ] && sed -i '' '/pyenv/d' "$f" [ -f "$f" ] && sed -i '' '/python@/d' "$f"done # 验证剩余版本echoecho "✅ 卸载完成!当前系统保留版本:"which -a python3 || echo "未检测到 Python"python3 --version 2>/dev/null || echo "无系统 Python 可用"echoecho "💡 如果仍检测到非系统路径,可手动检查:"echo " ls -l /Library/Frameworks/Python.framework/Versions/"第二步:运行脚本执行:1sudo bash ~/uninstall_python.sh第三步:验证是否干净运行:1which -a python3 输出应只剩下:/usr/bin/python3
-
在 macOS 下升级 Python 有几种常见的方法,具体取决于你最初是如何安装 Python 的。了解你的安装方式是关键。首先,你需要知道你当前 Python 版本以及它的安装路径。检查 Python 版本:12python --version # 可能指向 Python 2.xpython3 --version # 通常指向 Python 3.x检查 Python 路径:12which pythonwhich python3根据你 which 命令的输出,我们可以推断出安装方式。常见的安装方式有:macOS 系统自带 Python: 通常在 /usr/bin/python。不建议直接修改或升级系统自带的 Python,因为它可能被 macOS 的内部工具所依赖,直接操作可能导致系统不稳定。Homebrew 安装: 通常在 /usr/local/bin/python3 或 /opt/homebrew/bin/python3 (M1/M2 Mac)。这是 Mac 用户最推荐和最方便的管理 Python 的方式。pyenv 安装: 通常在 ~/.pyenv/shims/python。pyenv 是一个强大的 Python 版本管理工具。Anaconda/Miniconda 安装: 通常在 ~/anaconda3/bin/python 或 ~/miniconda3/bin/python。Anaconda 是一个全面的数据科学平台。直接从 Python 官网下载安装包 (pkg): 通常安装到 /Library/Frameworks/Python.framework。下面针对不同的安装方式讲解如何升级:最推荐的方式:使用 Homebrew (如果还没有安装,强烈建议安装)Homebrew 是 macOS 上最流行的包管理器,也是管理 Python 版本的最佳方式之一。1. 安装 Homebrew (如果尚未安装):打开终端并运行:1/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"按照屏幕上的指示完成安装。2. 升级 Homebrew 本身:1brew update3. 升级 Python (如果已通过 Homebrew 安装):如果你的 Python 3 是通过 Homebrew 安装的,只需运行:1brew upgrade python这会把 Homebrew 版的 Python 升级到最新稳定版本。4. 如果你尚未通过 Homebrew 安装 Python 3,或者需要安装特定版本:1brew install python # 这会安装最新稳定版 Python 35. 确保你的 PATH 环境变量正确设置:Homebrew 会自动将 /usr/local/bin (或 M1/M2 Mac 上的 /opt/homebrew/bin) 添加到你的 PATH 中,确保 Homebrew 安装的 Python 优先于系统自带的。在你的 ~/.zshrc (macOS Catalina及更高版本默认) 或 ~/.bash_profile (旧版本) 中确认有类似以下的行:12export PATH="/usr/local/opt/python/libexec/bin:$PATH" # 对于 Intel Macexport PATH="/opt/homebrew/opt/python/libexec/bin:$PATH" # 对于 M1/M2 Mac或者更通用的,确保 Homebrew 的 bin 目录在 PATH 前面:12export PATH="/opt/homebrew/bin:$PATH" # For M1/M2 Macexport PATH="/usr/local/bin:$PATH" # For Intel Mac更新后,运行 source ~/.zshrc 或 source ~/.bash_profile 使其生效。6. 验证升级:12python3 --versionwhich python3现在 python3 应该指向 Homebrew 安装的最新版本。使用 pyenv (推荐用于管理多个 Python 版本)如果你需要在同一台机器上管理多个 Python 版本(例如,项目 A 需要 Python 3.8,项目 B 需要 Python 3.10),pyenv 是一个绝佳的选择。1. 安装 pyenv (如果尚未安装):1brew install pyenv然后,你需要将 pyenv 初始化添加到你的 shell 配置文件。编辑你的 ~/.zshrc (或 ~/.bash_profile),添加以下行:1234export PYENV_ROOT="$HOME/.pyenv"export PATH="$PYENV_ROOT/bin:$PATH"eval "$(pyenv init --path)"eval "$(pyenv init -)"保存文件并运行 source ~/.zshrc。2. 列出可用的 Python 版本:1pyenv install --list3. 安装新的 Python 版本 (即升级):选择你想要安装的最新版本,例如 Python 3.11.x:1pyenv install 3.11.x # 将 x 替换为具体的最新补丁版本,如 3.11.44. 设置全局或局部 Python 版本:全局设置 (对所有 shell 会话生效):1pyenv global 3.11.x局部设置 (仅对当前目录及其子目录生效):进入你的项目目录,然后运行:1pyenv local 3.11.x5. 验证升级:1234python --versionpython3 --versionwhich pythonwhich python3pyenv 会通过修改 PATH 来“垫片” (shim) 你选择的 Python 版本。使用 Anaconda/Miniconda如果你使用 Anaconda 或 Miniconda 管理 Python 环境,升级方式如下:1. 更新 conda 本身:1conda update conda2. 升级基础环境中的 Python (不推荐,最好创建新环境):如果你想直接升级 base 环境中的 Python,可以尝试:1conda update python但更推荐的做法是创建新的环境来管理不同的 Python 版本。3. 创建一个新的环境并指定 Python 版本:123conda create -n my_new_env python=3.11conda activate my_new_envpython --version这样你就可以在不同的环境中切换,每个环境有自己独立的 Python 版本和库。从 Python 官网安装包 (pkg) 升级如果你最初是从 Python 官网下载的 .pkg 安装包,你可以:访问 Python 官网: cid:link_0下载最新版本的 macOS 安装程序。运行下载的 .pkg 文件。 它会引导你完成安装,并通常会安装在 /Library/Frameworks/Python.framework 下的一个新版本目录中,并更新你的系统 PATH,使其指向最新的安装。注意: 这种方法可能会安装多个 Python 版本在你的系统上,并且可能需要手动管理 PATH,不如 Homebrew 或 pyenv 灵活。总结和最佳实践:永远不要直接修改 macOS 系统自带的 Python (/usr/bin/python)。对于大多数 Mac 用户,使用 Homebrew 是最简单、最推荐的方式来安装和升级 Python 3。如果你需要管理多个 Python 版本用于不同的项目,使用 pyenv 是理想的选择。如果你进行数据科学或机器学习工作,并且依赖大量的科学计算库,Anaconda/Miniconda 是一个强大的解决方案。在升级 Python 后,记得重新安装或更新你的项目依赖 (pip install -r requirements.txt),因为 Python 版本的变化可能会影响库的兼容性。始终在一个新的终端会话或使用 source 命令来确保 PATH 环境变量的更改生效,然后再检查 Python 版本。
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签