# Go 到 Python 迁移指南 本文档详细说明了从Go项目迁移到Python项目的对应关系。 ## 技术栈对照表 | Go | Python | 说明 | |----|--------|------| | Gin | FastAPI | Web框架 | | Gorilla WebSocket | FastAPI原生WebSocket | WebSocket支持 | | database/sql + pq | SQLAlchemy + psycopg2 | 数据库访问 | | encoding/json | Pydantic + json | JSON序列化 | | os.Getenv | python-dotenv + pydantic-settings | 环境变量 | | log | logging | 日志 | | time | datetime | 时间处理 | | sync.Mutex | threading.Lock/asyncio.Lock | 并发锁 | | context.Context | 直接使用async/await | 上下文 | ## 项目结构对照表 ``` Go Python ├── adapter/ app/adapters/ │ ├── adapter.go base.py │ └── tushare/ │ ├── adapter.go tushare_adapter.py │ └── client.go (集成到adapter) ├── api/ │ ├── types.go app/models/types.py │ ├── router.go app/api/routes.py │ ├── admin_types.go app/models/admin_types.py │ └── admin_router.go app/api/admin_routes.py ├── cmd/ │ ├── server/main.go app/main.py │ └── sync/main.go scripts/sync_data.py ├── internal/ │ ├── handler/ │ │ ├── handler.go (合并到routes) │ │ └── admin.go (合并到admin_routes) │ ├── service/ │ │ ├── service.go (拆分到各service) │ │ ├── stock.go app/services/stock_service.py │ │ ├── futures.go app/services/futures_service.py │ │ ├── admin.go app/services/admin_service.py │ │ ├── config.go app/services/config_service.py │ │ ├── adapter.go app/services/adapter_service.py │ │ └── test.go app/services/test_service.py │ ├── repository/ │ │ ├── repository.go (合并) │ │ ├── stock.go app/repositories/stock_repository.py │ │ └── futures.go app/repositories/futures_repository.py │ ├── model/model.go app/repositories/models.py │ ├── websocket/server.go app/websocket/server.py │ └── monitor/monitor.go app/monitor/monitor.py ├── pkg/ │ ├── config/config.go app/core/config.py │ ├── logger/logger.go app/core/logger.py │ └── errors/errors.go app/core/errors.py └── config.json config.json (相同) ``` ## 类型系统对照表 ### 基础类型 | Go | Python | |----|--------| | `type Frequency string` | `class Frequency(str, Enum)` | | `type AdjustType string` | `class AdjustType(str, Enum)` | | `type AssetClass string` | `class AssetClass(str, Enum)` | | `struct KLineItem` | `class KLineItem(BaseModel)` | | `struct KLineData` | `class KLineData(BaseModel)` | | `interface Handler` | 通过FastAPI依赖注入实现 | ### 类型转换示例 **Go:** ```go type KLineItem struct { Time time.Time `json:"time"` Open float64 `json:"open"` Volume int64 `json:"volume"` } ``` **Python:** ```python class KLineItem(BaseModel): time: datetime = Field(..., description="时间戳") open: float = Field(..., description="开盘价") volume: int = Field(..., description="成交量") class Config: json_encoders = { datetime: lambda v: v.isoformat() } ``` ## 接口路由对照表 ### 股票接口 | Go路由 | Python路由 | 方法 | |--------|------------|------| | `stock.GET("/klines/:symbol", r.queryStockKLines)` | `@router.get("/stock/klines/{symbol}")` | GET | | `stock.GET("/symbols", r.listStockSymbols)` | `@router.get("/stock/symbols")` | GET | | `stock.POST("/klines/batch", r.batchQueryStockKLines)` | `@router.post("/stock/klines/batch")` | POST | | `stock.GET("/trading-dates", r.getStockTradingDates)` | `@router.get("/stock/trading-dates")` | GET | ### 参数绑定对比 **Go (Gin):** ```go func (r *Router) queryStockKLines(c *gin.Context) { var req KLineQueryRequest if err := c.ShouldBindQuery(&req); err != nil { c.JSON(http.StatusBadRequest, ErrorResponse{...}) return } req.Symbol = c.Param("symbol") // ... } ``` **Python (FastAPI):** ```python @router.get("/stock/klines/{symbol}") def query_stock_klines( symbol: str, # 路径参数 start: str = Query(...), # 查询参数 end: str = Query(...), db: Session = Depends(get_db) # 依赖注入 ): service = StockService(db) req = KLineQueryRequest(symbol=symbol, start=start, end=end) data = service.query_klines(req) return Response(code=0, message="success", data=data) ``` ## 数据库访问对照表 ### 查询K线数据 **Go:** ```go query := fmt.Sprintf(` SELECT ts, open, high, low, close, volume, amount FROM %s WHERE symbol_id = $1 AND ts >= $2 AND ts <= $3 ORDER BY ts ASC `, tableName) rows, err := r.db.QueryContext(ctx, query, symbol, start, end) ``` **Python (SQLAlchemy):** ```python query = self.db.query(kline_model).filter( kline_model.symbol_id == symbol, kline_model.ts >= start, kline_model.ts <= end ).order_by(kline_model.ts.asc()) results = query.all() ``` ### 批量插入 **Go:** ```go query := fmt.Sprintf(` INSERT INTO %s (symbol_id, ts, open, ...) VALUES %s ON CONFLICT (symbol_id, ts) DO UPDATE SET... `, tableName, strings.Join(valueStrs, ",")) _, err := r.db.ExecContext(ctx, query, args...) ``` **Python (SQLAlchemy):** ```python for item in items: existing = self.db.query(kline_model).filter(...).first() if existing: # 更新 existing.open = item.open ... else: # 插入 new_record = kline_model(...) self.db.add(new_record) self.db.commit() ``` ## WebSocket对照表 ### Go (Gorilla) ```go type Hub struct { clients map[*Client]bool subscriptions map[string]map[*Client]bool } func (h *Hub) Run() { for { select { case client := <-h.register: h.clients[client] = true // ... } } } ``` ### Python (FastAPI) ```python class WebSocketManager: def __init__(self): self.clients: Dict[str, WSClient] = {} self.subscriptions: Dict[str, Set[str]] = {} self.lock = asyncio.Lock() async def connect(self, websocket: WebSocket, client_id: str): await websocket.accept() async with self.lock: self.clients[client_id] = WSClient(id=client_id, websocket=websocket) ``` ## 配置管理对照表 ### Go ```go type Config struct { Server ServerConfig `json:"server"` Database DatabaseConfig `json:"database"` } func Load(path string) (*Config, error) { data, err := os.ReadFile(path) // ... json.Unmarshal(data, &cfg) return &cfg, nil } ``` ### Python ```python class Config(BaseModel): server: ServerConfig = Field(default_factory=ServerConfig) database: DatabaseConfig = Field(default_factory=DatabaseConfig) def load_config(config_path: str = "./config.json") -> Config: with open(config_path, 'r') as f: data = json.load(f) return Config.model_validate(data) ``` ## 启动方式对照表 ### Go ```bash go run ./cmd/server/main.go ``` ### Python ```bash # 方式1: 直接运行 python -m app.main # 方式2: 使用uvicorn uvicorn app.main:app --reload --port 8080 # 方式3: 生产环境 gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker ``` ## 数据同步工具对照表 ### Go ```bash go run ./cmd/sync -type stocks go run ./cmd/sync -type klines -symbol 000001.SZ -start 20240301 -end 20240307 ``` ### Python ```bash python scripts/sync_data.py --type stocks python scripts/sync_data.py --type klines --symbol 000001.SZ --start 20240301 --end 20240307 ``` ## 依赖管理对照表 ### Go (go.mod) ```go require ( github.com/gin-gonic/gin v1.9.1 github.com/gorilla/websocket v1.5.0 github.com/lib/pq v1.10.9 ) ``` ### Python (requirements.txt) ``` fastapi==0.115.0 uvicorn[standard]==0.32.0 sqlalchemy==2.0.36 psycopg2-binary==2.9.10 ``` ## 测试接口对照表 | 接口 | Go调用 | Python调用 | |------|--------|------------| | 健康检查 | `curl http://localhost:8080/v1/admin/health` | 相同 | | 查询股票K线 | `curl "http://localhost:8080/v1/stock/klines/000001.SZ?start=20250301&end=20250307" -H "X-API-Key: key"` | 相同 | | 批量查询 | `curl -X POST ... -d '{"symbols":["000001.SZ"],...}'` | 相同 | 所有API接口和响应格式与Go版本完全一致,客户端无需任何修改即可切换到Python后端。