gpt4 book ai didi

python - 根据访问的位置部分评估 Python Classmethod

转载 作者:太空狗 更新时间:2023-10-30 00:03:58 27 4
gpt4 key购买 nike

我在 python 中基本上有以下内容:

class X(object): pass

class Y(object):
@classmethod
def method(cls, x_inst, *args, **kwargs):
#do some work here that requires an instance of x
pass

我想做的是为 X 的所有实例添加一个动态属性,允许访问 Y 隐式填充 方法的第一个参数 与给定的实例。例如,我希望以下代码能够以相同的方式工作:

# current
x = X()
result = Y.method(x, 1, 2, 3)

# desired
x = X()
x.Y.method(1, 2, 3)

我想为几个子类实现此行为的几个方法。我目前所做的是创建一个 YProxy 类,X 实际返回,然后将一些代码拆分到其中。然而,它看起来相当不优雅且难以维护:

class X(object):
@property
def Y(self):
return YProxy(self)

class Y(object):
@classmethod
def method(cls, x_inst, *args, **kwargs):
#do some work here that requires an instance of x
pass

class YProxy(object):
def __init__(self, x_inst):
self.x_inst = x_inst

def method(self, *args, **kwargs):
return Y.method(self.x_inst, *args, **kwargs)

有没有办法有条件地部分评估对象的类方法?

最佳答案

这可以通过 Descriptor 对象 + 包装类广告来完成,并明确声明您需要以这种方式在目标类上包装的类。

描述符对象是定义 __get__ 的任何对象方法,当描述符是类的一部分时,它允许自定义属性检索。在这种情况下,我们希望当从实例中检索该属性(即“Y”类)时,无论何时从该类中检索方法,都将该实例插入到参数列表中。

这要求检索到的属性本身是具有自定义属性访问权限的“代理”类,以允许动态包装进行记录。

将所有这些翻译成 Python,我们有:

import types
from functools import partial

class APIWrapper(object):
def __init__(self, apicls, instance):
self._apicls = apicls
self._instance = instance
def __getattribute__(self, attr):
apicls = object.__getattribute__(self, "_apicls")
instance = object.__getattribute__(self,"_instance")
obj = getattr(apicls, attr)
if isinstance(obj, types.MethodType):
return partial(obj,instance)
return obj


class APIProperty(object):
def __init__(self, cls):
self.cls = cls
def __get__(self, instance, cls):
return APIWrapper(self.cls, instance)

class Y(object):
@classmethod
def method(cls, x, *args):
print cls, x, args

class X(object):
Y = APIProperty(Y)

#Example usage:
x = X()
x.Y.method(1,2,3)

(运行时打印 <class '__main__.Y'> <__main__.X object at 0x18ad090> (1, 2, 3))

但我想你不想写

Y = APIWrapper(Y) 

对于您要以这种方式包装的每个类。 (并在包装类之后定义这些类,以便在解析 X 主体时已经解析了 Y)。

这可以通过元类、类装饰器来完成,它们必须为您想要应用方法的每个类定义 - 相反,我创建了一个函数,该函数将在模块定义的末尾调用,在您定义“X”类的位置-此函数将为每个定义的类添加所需的类作为属性(在我的示例中,我希望该类标有“auto_api”属性-但适合您自己)-于是,“auto_api”函数,X类和Y类的定义就变成了这样(使用和上面一样的APIProperty和APIWrapper)

def auto_api(api_classes, glob_dict):
for key, value in glob_dict.items():
if isinstance(value, type) and hasattr(value, "auto_api"):
for api_class in api_classes:
setattr(value, api_class.__name__, APIProperty(api_class))


class X(object):
auto_api = True

class Y(object):
@classmethod
def method(cls, x, *args):
print cls, x, args

auto_api((Y,), globals())

#Example

x = X()
x.Y.method(1,2,3)

关于python - 根据访问的位置部分评估 Python Classmethod,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8957408/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com