在Python中,如何指定协议实现者具有特定的构造函数签名?

huangapple go评论62阅读模式
英文:

In Python, how to specify that a Protocol implementer has a specific constructor signature?

问题

这是您提供的代码的翻译部分:

# Is it possible to define that a class needs a specific constructor?

class Constructible(Protocol):

  def __init__(self, i: int):  # how do I do this?
    raise NotImplementedError

  def get_value(self):
    raise NotImplementedError

def map_is(cs: Iterable[Constructible], i: int):
  mapped = tuple(C(i) for C in cs)
  values = tuple(c.get_value() for c in mapped)
  # both the constructor and a member method are used
  return mapped, values

# implementors (omitting __hash__ and __eq__ for brevity)
class X(Constructible):
  def __init__(self, i):
    self.i=i
  def get_value(self):
    return self.i

class Sq(Constructible):
  def __init__(self, i):
    self.i=i
  def get_value(self):
    return self.i * self.i

cs, values = tuple(map_is((X, Sq), 5))
assert values == (5, 25)

请注意,上述代码是关于如何在Python中定义一个需要特定构造函数的类以及如何使用该类的示例。如果您有其他问题或需要进一步的信息,请随时提问。

英文:

Is it possible to define that a class needs a specific constructor?

class Constructible(Protocol):

  def __init__(self, i: int):  # how do I do this?
    raise NotImplementedError

  def get_value(self):
    raise NotImplementedError

def map_is(cs: Iterable[Constructible], i: int):
  mapped = tuple(C(i) for C in cs)
  values = tuple(c.get_value() for c in mapped)
  # both the constructor and a member method are used
  return mapped, values

# implementors (omitting __hash__ and __eq__ for brevity)
class X(Constructible):
  def __init__(self, i):
    self.i=i
  def get_value(self):
    return self.i

class Sq(Constructible):
  def __init__(self, i):
    self.i=i
  def get_value(self):
    return self.i * self.i

cs, values = tuple(map_is((X, Sq), 5))
assert values == (5, 25)

When specifying it like this, I get

$ mypy constr.py 
constr.py:12: error: "Constructible" not callable
Found 1 error in 1 file (checked 1 source file)

Is this even possible? Or should I revert to a factory function @classmethod def construct(i: int): Self?

答案1

得分: 1

如@jonrsharpe所解释的,你不需要将Constructible实例的可迭代对象传递给map_is,而是需要传递的可迭代对象。这意味着你应该这样定义函数:

def map_is(cs: Iterable[Type[Constructible]], i: int):
  return (C(i) for C in cs)

这对于mypy来验证代码已足够。

但是有一个无关的问题:你从未声明任何__hash____equal__特殊方法。这意味着在assert values == (X(5), Sq(5))中,使用的是object类上定义的相等性(与is相同)。因此,在上述修复之后,代码会成功执行,但仍会引发AssertionError,因为这些对象具有相同的值,但它们是不同的对象...

英文:

As explained by @jonrsharpe, you do not pass an iterable of Constructible instances to map_is but an iterable of classes. That means that you should define the function that way:

def map_is(cs: Iterable[Type[Constructible]], i: int):
  return (C(i) for C in cs)

That is enough for mypy to validate the code.

But there is an unrelated problem: you never declared any __hash__ nor __equal__ special method. That means that in assert values == (X(5), Sq(5)) the equality used is the one defined on the object class (same as is). So after the above fix, the code executes successfully but still raises an AssertionError, because the objects do have same value, yet they are distinct objects...

huangapple
  • 本文由 发表于 2023年2月14日 20:46:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/75448050.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定