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

为Python类方法添加__getitem__访问器的实现问题

解决Python类方法添加__getitem__实现方括号类型指定的问题

问题核心

你的实现出错的原因是没有处理Python的描述符协议:类方法在实例上访问时,默认会通过描述符的__get__方法绑定到实例,而你的TypedMethod类没有实现这个逻辑,导致原类实例(比如MyClass()的a)没有被正确传递,反而把TypedMethod自身当成了self传入原方法,所以才会出现'TypedMethod' object has no attribute 'my_other_method'的错误。

修正后的实现

我们需要让TypedMethod实现描述符协议,同时在获取方法时返回一个支持__call__和__getitem__的绑定对象,确保原实例能正确传递:

from functools import partial

class TypedMethod:
    _REQUESTED_TYPE_ATTR = '__requested_type'

    def __init__(self, method):
        self._method = method

    def __get__(self, instance, owner):
        # 实现描述符协议,绑定原实例到方法
        if instance is None:
            return self  # 类层面访问时返回自身
        # 返回一个绑定了实例的包装器,支持__call__和__getitem__
        return _BoundTypedMethod(instance, self._method)

    @classmethod
    def requested_type(cls, kwargs):
        return kwargs.pop(cls._REQUESTED_TYPE_ATTR, None)

class _BoundTypedMethod:
    def __init__(self, instance, method):
        self._instance = instance
        self._method = method

    def __call__(self, *args, **kwargs):
        # 常规调用,直接传递实例和参数
        return self._method(self._instance, *args, **kwargs)

    def __getitem__(self, specified_type):
        if not isinstance(specified_type, type):
            raise TypeError("Only Type Accessors are supported - must be an instance of `type`")
        # 生成partial,把类型存入kwargs
        return partial(
            self._method,
            self._instance,
            **{TypedMethod._REQUESTED_TYPE_ATTR: specified_type}
        )

def typedmethod(method):
    return TypedMethod(method)

测试验证

用你提供的MyClass测试两种调用方式:

class MyClass:
    @typedmethod
    def compute_typed_value(self, value, *args, **kwargs):
        print(f"self is MyClass instance: {isinstance(self, MyClass)}")
        datatype = TypedMethod.requested_type(kwargs) or str  # 默认类型设为str
        result = datatype(value)
        self.my_other_method()
        return result

    def my_other_method(self):
        print('Doing some other things!')
        return 3

# 测试方括号调用
a = MyClass()
result1 = a.compute_typed_value[int]('12345')
print(f"方括号调用结果: {result1}, 类型: {type(result1)}")

# 测试常规调用(默认类型)
result2 = a.compute_typed_value('12345')
print(f"常规调用结果: {result2}, 类型: {type(result2)}")

运行输出:

self is MyClass instance: True
Doing some other things!
方括号调用结果: 12345, 类型: <class 'int'>
self is MyClass instance: True
Doing some other things!
常规调用结果: 12345, 类型: <class 'str'>

API适配器场景适配

把修正后的装饰器用到你的API适配器例子中:

from dataclasses import dataclass
import requests

@dataclass
class MyAPIData:
    property_a: int = 0
    property_b: int = 0

class MyAPIAdapter:
    def __init__(self, token):
        self._session = requests.Session()
        self._session.headers['Authorization'] = f"Bearer {token}"

    @typedmethod
    def request_json(self, url, **kwargs):
        datatype = TypedMethod.requested_type(kwargs)
        response = self._session.get(url)
        response_data = response.json()
        if datatype:
            response_data = datatype(**response_data)
        return response_data

    def fetch_myapidata(self, search):
        # 使用方括号指定返回类型
        return self.request_json[MyAPIData](f"https://example.com/myapi?q={search}")

关键逻辑说明

  1. 描述符协议:TypedMethod的__get__方法在实例访问方法时,返回_BoundTypedMethod对象,该对象持有原实例和原方法,确保后续调用时能正确传递self。
  2. _BoundTypedMethod:同时实现__call__(处理常规调用)和__getitem__(处理方括号语法),其中__getitem__通过partial把类型参数注入到kwargs中,供原方法通过TypedMethod.requested_type获取。
  3. 参数处理:requested_type方法使用pop移除kwargs中的类型标记,避免污染原方法的参数环境。

内容的提问来源于stack exchange,提问作者David Culbreth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:32:55