零基础小白通宵达旦修炼MarsCode的奇技淫巧

1,308 阅读15分钟

豆包 MarsCode 编程助手是豆包旗下的 AI 编程助手,提供以智能代码补全为代表的 AI 功能。它支持主流的编程语言和 IDE,在开发过程中提供单行代码或整个函数的编写建议。此外,它还支持代码解释、单测生成和问题修复等功能,提高了开发效率和质量。

1、下载并安装 Visual Studio Code

下载地址

image.png

2、在VsCode的扩展商店MarsCode

安装 Visual Studio Code 后,左侧导航栏上点击扩展,打开扩展窗口。

在搜索框搜索“豆包”“MarsCode”关键词,找到豆包MarsCode 后单击「install」,完成安装。

3、 登录豆包MarsCode

重启 Visual Studio Code,使用快捷键(Windows: Ctrl + U; macOS: Command + U)打开豆包 MarsCode 编程助手侧边对话框,点击 登录 按钮,登录你的账号。

返回 IDE,插件准备完成,你可以开始体验 AI 能力,和AI助手进行任意对话。主要功能有生成代码、解释代码、注释代码,生成单测。

image.png

4、下载python,选择稳定版

image.png

5、安装Python

image.png

image.png

image.png

6、检查Python环境配置

在运行中输入sysdm.cpl

image.png

在高级——环境变量,选择系统变量中path。

image.png

双击path可以看到没有python变量。

image.png

新建添加下。

C:\Users\Administrator\AppData\Local\Programs\Python\Python312\python.exe

image.png

若在VsCode创建文件无法找到python,那么需要在扩展商店中安装python。

image.png

验证python安装正常。

image.png

7、配置虚拟环境

在VsCode中按住shift+ctrl+p,然后输入select interpreter。

image.png

点击创建虚拟环境。选择Venv创建。

image.png

image.png

也可以在终端里创建。

image.png

激活时发生报错。 image.png

原因是是在计算机上启动 Windows PowerShell 时,执行策略很可能是 Restricted(默认设置)。需要以管理员身份打开PowerShell 输入 set-executionpolicy remotesigned,就可以执行文件了。

image.png

8、依赖库的安装

使用“pip install”命令安装库。若安装速度慢可使用清华源,将库名替换到给定的清华源地址中。

pip install efinance==0.4.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install pandas==1.5.3 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install numpy==1.23.5 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install matplotlib==3.7.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install scikit-learn==1.2.2 -i https://pypi.tuna.tsinghua.edu.cn/simple

image.png

安装pandas==1.5.3有报错。

image.png

需要安装高版本C++。

image.png

安装pandas==1.5.3成功。

image.png

安装numpy==1.23.5有报错

image.png

image.png

尝试把numpy 2.2版本降级,pip install "numpy<2"

image.png

安装matplotlib==3.7.1成功。

image.png

安装scikit-learn==1.2.2报错

image.png

image.png

尝试安装,pip install --verbose scikit-learn。py可以正常运行。

image.png

执行pip list。查看安装结果。不太一样,但可以正常使用。

image.png

image.png

9、安装git

下载Git。

image.png

安装git。 image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

验证安装:git --version

image.png

10、导入课程的代码

点击clone git repository>>输入代码地址即可获取课程源码。

image.png

image.png

11、设置字体,并运行代码
  • Windows用户可以从 C:\Windows\Fonts 复制

image.png

完成所有准备部分后,请确保你的项目包含下面的文件👇

stock-prediction/
├── SimHei.ttf                # 中文字体文件
├── stock_prediction.py                   # 主程序
└── README.md                 # 项目说明文档

点击右上角可以尝试运行代码,检测前面的准备步骤是否出错。如下所示,弹出了股价预测图。

image.png

image.png

12、从0到1写出代码

在当前文件夹右键新建新的文件,

image.png

在豆包中输入如下提示词。

我想要获取股票数据,用 python 代码,从哪里获取股票数据呢?

image.png

和文档里提供的结果差距很大,所以MarsCode每次生成的内容都是不同的。

如何运行这部分代码

image.png

安装

pip install yfinance

image.png

打开终端后将插入代码

image.png

执行报错,提交给MarsCode,重新生成代码。

image.png

应用之后采纳,重新执行。数据是空的。

image.png

修改下时间,重新执行。还是空,继续给MarsCode优化。

image.png

提问

帮我写 Python 代码分析股价的变化趋势

image.png

执行之后下载失败。

image.png

继续把问题给MarsCode来寻找答案。

image.png

尝试很多次,反复报错如下,MarsCode也给不出能用的答案了。

1 Failed download:
['AAPL']: YFRateLimitError('Too Many Requests. Rate limited. Try after a while.')

image.png

尝试下老师的代码,也是没有执行出来。

image.png

文档很丰满,操作很骨感哈。

13、使用MarsCode反复修复代码

复制如下代码,

import efinance as ef

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

import matplotlib

matplotlib.use('TkAgg')  # 使用TkAgg后端

from sklearn.preprocessing import StandardScaler

from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

from sklearn.ensemble import RandomForestRegressor

import os

from matplotlib.font_manager import FontProperties

import time

 
# 设置中文字体

font_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'SimHei.ttf')

custom_font = FontProperties(fname=font_path)

plt.rcParams['axes.unicode_minus'] = False



def get_stock_data(stock_code='GOOGL', start_date='20230101', end_date='20241130'):

    """获取股票数据"""

    file_path = f'results/{stock_code}_{start_date}_{end_date}_history.csv'

   

    if os.path.exists(file_path):

        print(f"从本地加载{stock_code}的历史数据...")

        df = pd.read_csv(file_path)

    else:

        print(f"从网络获取{stock_code}的历史数据...")

        df = ef.stock.get_quote_history(stock_code, beg=start_date, end=end_date)

        df.to_csv(file_path, encoding='utf-8', index=False)

   

    df['日期'] = pd.to_datetime(df['日期'])

    cols_to_keep = ['日期', '开盘', '收盘', '最高', '最低', '成交量', '成交额', '换手率']

    df = df[cols_to_keep]

   

    return df

  

def create_features(df):

    """创建特征"""

    df = df.copy()

   

    # 确保数值类型

    numeric_cols = ['开盘', '收盘', '最高', '最低', '成交量', '成交额', '换手率']

    for col in numeric_cols:

        df[col] = pd.to_numeric(df[col], errors='coerce')

   

    # 成交量相关特征

    df['volume_price_ratio'] = df['成交量'] / df['收盘']

  

    return df.dropna()

  

def prepare_data(df, target_col='收盘', test_size=0.2):

    """准备训练和测试数据"""

    df = create_features(df)
    
    feature_columns = [col for col in df.columns if col != target_col and col != '日期']

    X = df[feature_columns].astype(float)

    y = df[target_col].astype(float)

    split_idx = int(len(df) * (1 - test_size))

    X_train, X_test = X[:split_idx], X[split_idx:-1]

    y_train, y_test = y[1:split_idx+1], y[split_idx+1:]

    # y_test[-1:] = 300

    #import ipdb; ipdb.set_trace()    

    scaler = StandardScaler()

    X_train_scaled = scaler.fit_transform(X_train)

    X_test_scaled = scaler.transform(X_test)

   

    return X_train_scaled, X_test_scaled, y_train, y_test, scaler, feature_columns, df['日期'][split_idx:]

def plot_predictions_dynamic(dates, y_test, y_pred, stock_code='GOOGL', start_from=100):

    """动态绘制预测结果,预测点和实际点交替显示"""

    plt.ion()  # 打开交互模式

   

    # 转换数据为numpy数组,确保可以通过索引访问

    y_test = np.array(y_test)

    y_pred = np.array(y_pred)

   

    # 从指定天数开始的数据

    dates = dates[start_from:]

    y_test = y_test[start_from:]

    y_pred = y_pred[start_from:]

   

    fig, ax = plt.subplots(figsize=(15, 8))

    plt.title('股价预测结果和实际股价对比图', fontproperties=custom_font, fontsize=14, pad=20)

    plt.xlabel('日期', fontproperties=custom_font, fontsize=12)

    plt.ylabel('股价', fontproperties=custom_font, fontsize=12)

    plt.grid(True, alpha=0.3)

   

    # 设置坐标轴范围

    ax.set_xlim(-1, len(dates))

    ax.set_ylim(min(min(y_test), min(y_pred)) * 0.95,

                max(max(y_test), max(y_pred)) * 1.05)

   

    # 处理日期刻度

    date_list = dates.tolist()

    tick_indices = range(0, len(date_list), max(1, len(date_list)//10))

    date_labels = [date_list[i].strftime('%Y-%m-%d') if isinstance(date_list[i], pd.Timestamp)

                  else pd.Timestamp(date_list[i]).strftime('%Y-%m-%d')

                  for i in tick_indices]

    plt.xticks(list(tick_indices), date_labels, rotation=45)

   

    # 初始化线条和散点

    actual_line, = ax.plot([], [], 'black', label='实际值', linewidth=2)

    pred_line, = ax.plot([], [], 'blue', label='预测值', alpha=0.7, linewidth=2)

    actual_scatter = ax.scatter([], [], color='black', s=50, alpha=0.6)

    pred_scatter = ax.scatter([], [], color='blue', s=50, alpha=0.6)

   

    plt.legend(prop=custom_font)

    plt.tight_layout()

   

    # 动态更新数据

    actual_x_data = []

    actual_y_data = []

    pred_x_data = []

    pred_y_data = []

   

    try:

        # 交替显示预测点和实际点

        for i in range(len(y_test)):

            # 先显示预测点

            pred_x_data.append(i)

            pred_y_data.append(y_pred[i])

            pred_line.set_data(pred_x_data, pred_y_data)

            pred_scatter.set_offsets(np.c_[pred_x_data, pred_y_data])

           

            # 更新图形

            fig.canvas.draw()

            fig.canvas.flush_events()

            time.sleep(0.3)  # 暂停一小段时间

           

            # 再显示实际点

            actual_x_data.append(i)

            actual_y_data.append(y_test[i])

            actual_line.set_data(actual_x_data, actual_y_data)

            actual_scatter.set_offsets(np.c_[actual_x_data, actual_y_data])

           

            # 更新图形

            fig.canvas.draw()

            fig.canvas.flush_events()

            time.sleep(0.1)  # 暂停一小段时间

    except Exception as e:

        print(f"绘图过程中发生错误: {str(e)}")

        print(f"当前索引: {i}")

        print(f"数据形状: y_test: {y_test.shape}, y_pred: {y_pred.shape}")

   

    plt.ioff()  # 关闭交互模式

    plt.show()

   

    return fig

  


def plot_feature_importance(feature_columns, importance, top_n=10):

    """绘制特征重要性"""

    importance_dict = dict(zip(feature_columns, importance))

    importance_sorted = dict(sorted(importance_dict.items(), key=lambda x: x[1], reverse=True)[:top_n])

   

    plt.figure(figsize=(12, 6))

    plt.bar(importance_sorted.keys(), importance_sorted.values())

    plt.xticks(rotation=45, ha='right')

    plt.title('特征重要性排序', fontproperties=custom_font, fontsize=14)

    plt.xlabel('特征', fontproperties=custom_font)

    plt.ylabel('重要性', fontproperties=custom_font)

    plt.tight_layout()

   

    # 保存图片

    plt.savefig('results/feature_importance.png', dpi=300, bbox_inches='tight')

   

    return plt.gcf()

  


def main():

    """主函数"""

    try:

        # 设置随机种子

        np.random.seed(42)

       

        # 1. 获取数据

        # 提示用户输入股票代码

        stock_code = input("请输入股票代码(例如:MSFT):")

        # 提示用户输入开始日期

        start_date = input("请输入开始日期(YYYYMMDD):")

        # 提示用户输入结束日期

        end_date = input("请输入结束日期(YYYYMMDD):")

        # 获取股票数据

        df = get_stock_data(stock_code, start_date=start_date, end_date=end_date)

  


        print(f"数据获取完成,共 {len(df)} 条记录")

       

        # 2. 准备数据

        X_train, X_test, y_train, y_test, scaler, feature_columns, test_dates = prepare_data(df)

        print(f"数据预处理完成,训练集大小: {X_train.shape}, 测试集大小: {X_test.shape}")

       

        # 3. 训练随机森林模型

        print("\n开始训练随机森林模型...")

        model = RandomForestRegressor(n_estimators=200,

                                    max_depth=10,

                                    min_samples_split=5,

                                    min_samples_leaf=2,

                                    random_state=42)

        model.fit(X_train, y_train)

       

        # 4. 预测和评估

        y_pred = model.predict(X_test)

       

        mse = mean_squared_error(y_test, y_pred)

        rmse = np.sqrt(mse)

        mae = mean_absolute_error(y_test, y_pred)

        r2 = r2_score(y_test, y_pred)

       

        print("\n模型评估结果:")

        print(f"R2分数: {r2:.4f}")

        print(f"均方误差(MSE): {mse:.4f}")

        print(f"均方根误差(RMSE): {rmse:.4f}")

        print(f"平均绝对误差(MAE): {mae:.4f}")

       

        # 5. 绘制动态预测图

        fig = plot_predictions_dynamic(test_dates, y_test, y_pred, stock_code, start_from=20)

        plt.show()

       

        # 6. 绘制特征重要性

        plot_feature_importance(feature_columns, model.feature_importances_)

       

        return model, scaler, feature_columns

       

    except Exception as e:

        print(f"发生错误: {str(e)}")

        raise

  


if __name__ == "__main__":

    model, scaler, feature_columns = main()

向豆包MarsCode提问:

任务:创建一个完整的股票价格预测分析应用程序,包含数据获取、特征工程、模型训练和预测可视化等功能。

代码组织要求:
1. 使用函数式编程,保持代码结构清晰
2. 所有代码放在一个文件中,约2503. 使用英文注释和输出,避免中文编码问题
4. 每个功能模块间接口统一,确保数据流转顺畅
5. 符合Google Python代码规范

具体功能模块:

1. 数据获取:
- 使用efinance库实现数据获取
- 支持本地数据缓存功能
- 统一中英文列名转换
- 返回标准格式DataFrame

2. 特征工程:
- 计算成交量价格比
- 处理缺失值

3. 数据预处理:
- 特征标准化
- 训练测试集分割,准备训练和测试数据,使用当天的特征预测下一天的目标值
- 保持时间序列顺序
- 数据验证

4. 模型训练:
- 使用RandomForestRegressor
- 设置合适的模型参数
- 提供训练过程日志
- 返回训练好的模型

5. 模型评估:
- 计算R2分数
- 计算MSE和RMSE
- 计算MAE
- 格式化输出结果

6. 可视化展示:
- 预测结果对比图
- 特征重要性分析图
- 使用英文标签
- 支持图片保存

函数接口规范:

1. get_stock_data(stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:
   """获取股票数据"""

2. create_features(df: pd.DataFrame) -> pd.DataFrame:
   """创建技术指标特征,只保留数值列返回新变量"""

3. prepare_data(df: pd.DataFrame, target_col: str, test_size: float) -> tuple:
   """准备训练和测试数据,使用当天的特征预测下一天的目标值"""

4. train_model(X_train: np.ndarray, y_train: np.ndarray) -> RandomForestRegressor:
   """训练模型"""

5. evaluate_predictions(y_true: np.ndarray, y_pred: np.ndarray) -> dict:
   """评估预测结果"""

6. plot_predictions(dates: pd.Series, y_true: np.ndarray, y_pred: np.ndarray, stock_code: str):
   """绘制预测结果"""

7. main() -> tuple:
   """主函数"""

数据示例:
股票名称   股票代码          日期       开盘      收盘      最高       最低       成交量           成交额    振幅   涨跌幅   涨跌额   换手率
0    谷歌-A  GOOGL  2023-01-03   89.185   88.72   90.65   88.120  28131224  2.512678e+09  2.88  1.01  0.89  0.47
1    谷歌-A  GOOGL  2023-01-04   89.950   87.68   90.25   86.871  34854776  3.074915e+09  3.81 -1.17 -1.04  0.58

数据流转说明:
1. get_stock_data获取原始数据
2. create_features处理原始数据生成特征
3. prepare_data准备训练数据
4. train_model训练模型
5. evaluate_predictions评估结果
6. plot_predictions可视化

关键要求:
1. 所有函数都要有完整的文档字符串
2. 包含异常处理机制
3. 提供进度提示信息
4. 保持代码简洁易读
5. 避免复杂的依赖关系

完整示例用法:
```python
if __name__ == "__main__":
    # 设置股票代码和日期范围
    stock_code = 'MSFT'
    start_date = '20230101'
    end_date = '20241030'
    
    # 运行主程序
    model, scaler, feature_cols = main()

image.png

如何运行代码

image.png

运行代码报错,之后选中,然后让MarsCode来修复。

image.png

反复修改各种报错。

image.png

最后生成股票的预测图。

image.png

最终代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error
import efinance as ef

def get_stock_data(stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:
    """
    获取股票数据

    :param stock_code: 股票代码
    :param start_date: 开始日期
    :param end_date: 结束日期
    :return: 包含股票数据的DataFrame
    """
    try:
        # 尝试从本地缓存读取数据
        df = pd.read_csv(f"{stock_code}_{start_date}_{end_date}.csv")
        print("Data loaded from cache.")
    except FileNotFoundError:
        # 如果本地缓存不存在,则从网络获取数据
        print("Fetching data from the web...")
        df = ef.stock.get_quote_history(stock_code, beg=start_date, end=end_date)
        # 将数据保存到本地缓存
        df.to_csv(f"{stock_code}_{start_date}_{end_date}.csv", index=False)
        print("Data fetched and saved to cache.")
    # 将日期列转换为 datetime 类型,并设置为索引
    df['日期'] = pd.to_datetime(df['日期'])
    df.set_index('日期', inplace=True)
    return df

def create_features(df: pd.DataFrame, target_col: str) -> pd.DataFrame:
    """
    创建技术指标特征,保留目标列('收盘')并只返回数值列
    
    :param df: 包含原始数据的DataFrame
    :param target_col: 目标列名
    :return: 包含新特征的DataFrame
    """
    # 计算成交量价格比
    df['volume_price_ratio'] = df['成交量'] / df['成交额']
    # 处理缺失值
    df.fillna(method='ffill', inplace=True)
    # 只保留数值列,并确保目标列被保留
    df = df.select_dtypes(include=[np.number])
    return df

def prepare_data(df: pd.DataFrame, target_col: str, test_size: float) -> tuple:
    """
    准备训练和测试数据,使用当天的特征预测下一天的目标值
    
    :param df: 包含特征和目标值的DataFrame
    :param target_col: 目标值列名
    :param test_size: 测试集占比
    :return: 包含训练集和测试集的元组
    """
    # 特征标准化
    scaler = StandardScaler()
    X = df.drop(target_col, axis=1)  # 删除目标列
    y = df[target_col]  # 目标列
    X_scaled = scaler.fit_transform(X)  # 特征标准化
    # 训练测试集分割,保持时间序列顺序
    X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=test_size, shuffle=False)
    return X_train, X_test, y_train, y_test, scaler

def train_model(X_train: np.ndarray, y_train: np.ndarray) -> RandomForestRegressor:
    """
    训练模型

    :param X_train: 训练集特征
    :param y_train: 训练集目标值
    :return: 训练好的模型
    """
    print("Training the model...")
    model = RandomForestRegressor(n_estimators=100, random_state=42)
    model.fit(X_train, y_train)
    print("Model training completed.")
    return model

def evaluate_predictions(y_true: np.ndarray, y_pred: np.ndarray) -> dict:
    """
    评估预测结果

    :param y_true: 真实目标值
    :param y_pred: 预测目标值
    :return: 包含评估指标的字典
    """
    r2 = r2_score(y_true, y_pred)
    mse = mean_squared_error(y_true, y_pred)
    rmse = np.sqrt(mse)
    mae = mean_absolute_error(y_true, y_pred)
    return {'R2 Score': r2, 'MSE': mse, 'RMSE': rmse, 'MAE': mae}

def plot_predictions(dates: pd.Series, y_true: np.ndarray, y_pred: np.ndarray, stock_code: str):
    """
    绘制预测结果,并智能调整时间横轴的密集程度

    :param dates: 日期序列
    :param y_true: 真实目标值
    :param y_pred: 预测目标值
    :param stock_code: 股票代码
    """
    plt.figure(figsize=(12, 6))

    # 确保 dates 是 pandas 的 datetime 类型,不要转换成字符串
    plt.plot(dates, y_true, label='True Values')
    plt.plot(dates, y_pred, label='Predicted Values')
    plt.title(f"Stock Price Prediction for {stock_code}")
    plt.xlabel('Date')
    plt.ylabel('Price')

    # 获取时间跨度(最大日期 - 最小日期)
    time_span = (dates.max() - dates.min()).days

    # 根据时间跨度智能调整日期的显示
    ax = plt.gca()
    if time_span > 365:  # 超过一年,按月显示日期
        ax.xaxis.set_major_locator(mdates.MonthLocator())
        ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))  # 显示年份和月份
    elif time_span > 31:  # 超过一个月,按周显示日期
        ax.xaxis.set_major_locator(mdates.WeekdayLocator())
        ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))  # 显示年份、月份和日期
    else:  # 小于一个月,按天显示日期
        ax.xaxis.set_major_locator(mdates.DayLocator())
        ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))  # 显示年份、月份和日期

    # 自动旋转 x 轴标签以防止重叠
    plt.xticks(rotation=45)

    # 显示图例
    plt.legend()
    plt.tight_layout()  # 确保布局不被压缩
    plt.savefig(f"{stock_code}_prediction.png")
    plt.show()

def main() -> tuple:
    """
    主函数

    :return: 训练好的模型、标准化器和特征列名
    """
    # 设置股票代码和日期范围
    stock_code = input("请输入股票代码: ")
    start_date = input("请输入开始日期(格式为YYYYMMDD): ")
    end_date = input("请输入结束日期(格式为YYYYMMDD): ")

    # 获取股票数据
    df = get_stock_data(stock_code, start_date, end_date)

    # 创建特征
    target_col = '收盘'
    df = create_features(df, target_col)

    # 准备数据
    X_train, X_test, y_train, y_test, scaler = prepare_data(df, target_col, test_size=0.2)

    # 训练模型
    model = train_model(X_train, y_train)

    # 预测
    y_pred = model.predict(X_test)

    # 评估预测结果
    evaluation = evaluate_predictions(y_test, y_pred)
    print("Model Evaluation:")
    for metric, value in evaluation.items():
        print(f"{metric}: {value}")

    # 可视化预测结果
    plot_predictions(df.index[-len(y_test):], y_test, y_pred, stock_code)

    return model, scaler, df.columns.drop(target_col)

if __name__ == "__main__": 
    main()
14、总结

1)零基础的话,MarsCode可以做一个入门编程指导老师,通过提问可以学习一步步怎么写代码,执行代码等等。

2)对小白来说的话,我认为最大的难点可能在于基础环境的搭建,在安装python依赖的时候花了5个小时,总有各种报错,可能有些报错比较简单,但对小白来说就是看不懂,只能各种MarsCode或者百度来一个个尝试。

3)使用MarsCode来优化代码的时候,实际遇到的情况就是MarsCode给出的一种方式不行的时候,再优化MarsCode会陷入循环,一直提供都是同一种方式,可能它也没有别的方式。对于小白来说,这个问题就不好自己解决了。

4)纸上得来终觉浅,还是要动手多操作。纵然是按着文档或者老师一步步来,也可能是不同的结果。

5)MarsCode还是很强大,一些初级代码它都写的很好,绝对是提升生产力的工具。

感兴趣的小伙伴,可以一起来MarsCodde共学,报名链接