You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3.8 TypeError: 'type'对象不可订阅错误排查求助

问题修复:Python 3.8类型提示导致的TypeError

错误根源

报错来自三个Python 3.8类型提示的不兼容问题:

  1. 泛型类型下标不支持:Python 3.8中,tuple等内置泛型不能直接用[...]下标,需要从typing模块导入对应泛型类,或启用延后类型解析。
  2. 模块作为类型注解错误:log: logging里的logging是模块而非类型,正确类型应为logging.Logger。
  3. 可选返回值写法不规范:-> tuple[...] or None不符合PEP类型提示规范,需用Optional[...]表示可选类型。

具体修复步骤

1. 修改module.py的类型提示

在文件顶部导入typing模块的Optional,并调整函数注解:

# coding=utf-8
import logging
import re
import unicodedata
from typing import Optional  # 新增导入
from mailbox import MaildirMessage
from bs4 import BeautifulSoup, ResultSet, Tag


def filter_mail(mail: MaildirMessage, log: logging.Logger) -> Optional[tuple[object, MaildirMessage]]:
    """ Filter the mail to only include messages that have need to be sent
    :rtype: Optional[tuple[object, MaildirMessage]]
    :param mail: MaildirMessage
    :param log: logging.Logger
    """
    try:
        parsed_email: BeautifulSoup = BeautifulSoup(mail._payload, 'html.parser')
        original_from_email_id: object = \
            re.findall(r"([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)", mail['From'])[0]

        # 提取原始邮件发送方
        from_element: str = parsed_email.find_all("br")[0].parent.text
        from_element = unicodedata.normalize("NFKD", from_element)
        from_element = from_element.replace("\n", " ")
        from_element = from_element.replace("=2E", ".")
        emails_from: list = re.findall(r"([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)", from_element)

        # 修改邮件头
        email_subject: str = mail['Subject'].replace("Fw: ", "")
        mail.replace_header("From", emails_from[0])
        mail.replace_header("Subject", email_subject)

        # 移除邮件内容中的HTML块
        html_block_to_be_removed_element: ResultSet[Tag] = parsed_email.select('div[style=\'3D"margin:0\']')
        html_block_to_be_removed: str = str(html_block_to_be_removed_element).removeprefix('[').removesuffix(']')
        mail._payload = str(parsed_email).replace(html_block_to_be_removed, '')

        return original_from_email_id, mail

    except Exception as e:
        log.critical(f"Failed to Filter email, Exception Message - " + str(e))
        return None

2. 修复main.py中的类型提示

同样导入Optional,并调整filtered_mail的类型注解,同时修正filter_mail的调用参数:

#!/usr/bin/env python3
# coding=utf-8
import logging
import mailbox
import module
import os
import sys
from typing import Optional  # 新增导入
from mailbox import Maildir, MaildirMessage
from kafka import KafkaProducer
from kafka.errors import KafkaError
from kafka.producer.future import FutureRecordMetadata

# 原有环境变量配置代码不变...

def read_mails() -> None:
    """
    :rtype: None
    """
    mbox: Maildir = mailbox.Maildir(MAILBOX_DIRECTORY)
    if not len(mbox.items()):
        logging.info('no new emails found in mbox')
        return

    processed_email_count: int = 0
    kafka_producer: KafkaProducer = KafkaProducer(
        bootstrap_servers=KAFKA_SERVERS_LIST,
        compression_type='gzip'
    )
    mbox.lock()
    try:
        item_keys_to_remove: list = []
        for key, mail in mbox.iteritems():
            logging.info(f"new mail from {mail['From']} with subject: {mail['Subject']}")

            # 修改类型注解,并传入正确的Logger实例
            filtered_mail: Optional[tuple[object, MaildirMessage]] = module.filter_mail(mail, logging.getLogger(__name__))
            if filtered_mail is not None:
                logging.info(f"Filtered mail from {mail['From']} with subject: {mail['Subject']}")
                if put_mail_in_kafka_topic(filtered_mail[0], filtered_mail[1].as_string(), kafka_producer):
                    item_keys_to_remove.append(key)
                    backup_mail(mail)
                    processed_email_count += 1
            else:
                logging.critical(f"Failed to filter mail or publish mail on kafka topic")

        # 原有邮件处理代码不变...

3. 可选方案:启用延后类型解析

如果不想导入typing模块,可在两个文件的最顶部添加:

from __future__ import annotations

这会让Python延后解析类型提示,允许直接使用tuple[...]写法,但仍需修正log的类型和返回值的Optional写法。

额外优化建议

  • original_from_email_id的类型可从object改为str,因为正则匹配返回的是字符串,类型更精确。
  • emails_from: list可改为emails_from: list[str],提升类型标注精度。

内容的提问来源于stack exchange,提问作者Manav Mehta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 08:36:02