【问题标题】:How to set builtin class methods with python type function?如何使用 python 类型函数设置内置类方法?
【发布时间】:2022-01-24 06:02:15
【问题描述】:

以下代码按预期工作

class Foo: pass
a1 = Foo
a2 = Foo
print(a1 == a2)
# True

现在,如果我动态生成它们并进行比较,它就不起作用了

def eq(a,b):
  return str(a) == str(b)

t1 = type("Foo", (), {"__eq__": eq})
t2 = type("Foo", (), {"__eq__": eq})

print(t1 == t2)
# False

此外,运行此程序时,我收到错误

print(t1.__eq__(t2))

Traceback (most recent call last):
  File "foo.py", line 51, in <module>
    print(t1.__eq__(t2))
TypeError: eq() missing 1 required positional argument: 'b'

使用类型函数设置内置方法的正确方法是什么?

旁注:
我需要这种功能,我可以从类型动态创建类型(在这种情况下,它是一个标识函数,我返回的输出与输入相同)或类型注释不是类型类型,而是类型。别名或类型。通用的。这是获取更大图片的sn-p

from typing import List
class Foo: pass

def build_type(type_):
  '''Build type definition of new user-defined types or annotations.'''

  if isinstance(type_, type):
    return type_
  else:
    origin = type_.__origin__ if hasattr(type_, "__origin__") else None
    args = type_.__args__ if hasattr(type_, "__args__") else None
    type_name = str(type_)
    attrs = {
      "__origin__": origin,
      "__args__": args,
      "__hash__": hash((type_name, origin, args))
    }
    return type(type_name, (), attrs)

t1 = build_type(Foo)
t2 = build_type(Foo)
print(t1 == t2) # True

a1 = build_type(List[Foo])
a2 = build_type(List[Foo])

print(a1 == a2) # False

【问题讨论】:

  • 你不能对类型使用__eq__这样的方法,因为它是一个instance方法。这些类型与 == 的比较不同,因为它们是单独的对象,并且没有规则使它们相等 - 使用默认的 object 比较。在第一个示例中,a1a2 是同一对象的不同名称 - Foo 类本身。
  • 你想达到什么结果?你的意思是测试a1() == a2()
  • "使用类型函数设置内置方法的正确方法是什么?"不清楚你想要什么。您是否尝试设置允许 Python 检测 a1a2 类型“相同”的代码,尽管它们是 type 的单独实例?您是否尝试为每种类型创建一个 __eq__ 实例方法,它会自动执行正确的操作? (什么正确的?)其他的?
  • 有没有办法让 t1 和 t2 像 a1 和 a2 一样?
  • 在这种情况下,我建议您保留以前创建的类型的缓存,这样您就可以避免创建具有相同方法的新类型。

标签: python metaprogramming python-typing typing


【解决方案1】:

正如您在 cmets 中所说的,方法必须是类的成员,而不是实例的成员。

由于您是动态构建类而不是简单对象,因此您应该使用具有特定 __eq__ 方法的自定义元类:

你的例子会变成:

...
class Builder(type):
"""Custom meta-class defining type equality as name equality"""
    def __eq__(self, other):
        return str(self) == str(other)

def build_type(type_):
  '''Build type definition of new user-defined types or annotations.'''

  if isinstance(type_, type):
    return type_
  else:
    origin = type_.__origin__ if hasattr(type_, "__origin__") else None
    args = type_.__args__ if hasattr(type_, "__args__") else None
    type_name = str(type_)
    attrs = {
      "__origin__": origin,
      "__args__": args,
      "__hash__": hash((type_name, origin, args))
    }
    return Builder(type_name, (), attrs)
...

如果你运行它,你应该会得到预期的结果:

True
True

【讨论】:

    【解决方案2】:

    您的代码当前返回:

    id(a1)
    140415204390672
    
    id(a2)
    140415204390672
    
    # a1 and a2 have same object IDs
    
    id(t1)
    140415116432032
    
    id(t2)
    140415116465120
    
    # t1 and t2 have different object ID
    

    但我想你想比较一下:

    a1.__name__ == a2.__name__
    True
    

    其中a1.__name__'Foo'

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-31
      • 1970-01-01
      • 2013-06-15
      • 2011-10-08
      • 2019-09-22
      • 2016-09-28
      • 1970-01-01
      相关资源
      最近更新 更多