【问题标题】:Why I can't inherit map in python?为什么我不能在 python 中继承地图?
【发布时间】:2020-07-28 03:07:45
【问题描述】:

我想写一个继承map类的自定义类。

class mapT(map):
def __init__(self,iii):
    self.obj = iii

但我无法初始化它。

# Example init object
ex = map(None,["","1","2"])

exp1 = mapT(ex)
# TypeError: map() must have at least two arguments.

exp1 = mapT(None,ex)
# TypeError: __init__() takes 2 positional arguments but 3 were given

如何在python中创建一个继承map的类? 或者为什么我不能在 python 中继承 map?

===== 添加=====

我想要实现的是为可迭代对象添加自定义方法

def iterZ(self_obj):
    class iterC(type(self_obj)):
        def __init__(self,self_obj):
            super(iterC, self).__init__(self_obj)
            self.obj = self_obj
        def map(self,func):
            return iterZ(list(map(func,self.obj))) # I want to remove "list" here, but I can't. Otherwise it cause TypeError
        def filter(self,func):
            return iterZ(list(filter(func,self.obj))) # I want to remove "list" here, but I can't. Otherwise it cause TypeError
        def list(self):
            return iterZ(list(self.obj))
        def join(self,Jstr):
            return Jstr.join(self)
return iterC(self_obj)

所以我可以这样做:

a = iterZ([1,3,5,7,9,100])
a.map(lambda x:x+65).filter(lambda x:x<=90).map(lambda x:chr(x)).join("")
# BDFHJ

而不是这个:

"".join(map(lambda x:chr(x),filter(lambda x:x<=90,map(lambda x:x+65,a))))

【问题讨论】:

  • 这没有任何意义。 map 在技术上是 CPython 中的一个类,但这不是一个书面保证,无论哪种方式,__init__map 子类没有意义。
  • 无论你想要实现什么,子类化 map 几乎肯定不是实现它的方法。
  • 为什么你需要为这个映射子类???此外,停止在所有迭代器上使用list,这违背了它们是迭代器的意义。无论如何,您可以继承地图,但由于上述原因,我不会。请注意,__new__ 可能会妨碍您的实现
  • 再一次,为每个函数调用创建一个类并动态继承class iterC(type(self_obj))有什么意义?为什么不只是一个不从任何东西(默认对象除外)继承的函数之外的类?即class iterC: ...
  • 这是一个包装器的工作,而不是一个子类。无论如何,您没有使用原始对象的任何方法 - 地图迭代器拥有的唯一方法是您不太可能直接调用的东西。

标签: python python-3.x python-class


【解决方案1】:

您不应该从要包装的对象继承。那是因为您的 API 与该类型不同,并且没有好的方法可以确保您可以正确构建该类的新实例。您的 map 情况就是一个例子,您的 __init__ 期望的参数数量与 map.__new__ 不同,并且没有很好的方法来合理化它们。

不是从类继承,而是围绕它。这可能会限制可以使用的 API 类型,但您主要关注的是迭代器协议,因此您可能只需要 __iter____next__

class iterZ:
    def __init__(self, iterable):
        self.iterator = iter(iterable)

    def __iter__(self):
        return self

    def __next__(self):
        return next(self.iterator)

    def map(self,func):
        return iterZ(map(func,self.iterator))

    def filter(self,func):
        return iterZ(filter(func,self.iterator))

    def join(self,Jstr):
        return Jstr.join(self.iterator)

【讨论】:

  • 是的,您的解决方案有效。但是我想建立一个更通用的类,这样我就可以iterZ([1,2,3])[1]print(iterZ([1,2,3]))而不定义__getitem__ __str__等,该类可以从父类中自动检索它。
  • @JK-Hu 你不想在这里继承,这完全是错误的工具。对于你想要做的事情,有更直接的方法,在 python 中,编写某种代理或包装器非常简单。继承最好谨慎使用,它会强制分层关系,最终限制您想要完成的代码重用类型。
  • 好的。只是一个问题,你知道任何优雅的方式来做到这一点吗?如果a=iterZ([1,3,2]),我想让a==ba+ba&gt;blen(a)sorted(a)等作为原始对象工作?目前我已经定义了这些运算符需要的所有魔术方法,但我只想将方法添加到现有类。除了继承,有没有办法将所有方法和属性代理到原始对象?
  • 很难成为所有类型的完美代理,但是是的,通常您只需要实现 __dunder__ 方法来实现运算符等,以及 __getattribute__ 方法来查找命名方法和属性(它对运算符没有帮助,因为特殊方法是直接在类上查找的,而不是通过实例)。
猜你喜欢
  • 2010-09-28
  • 1970-01-01
  • 1970-01-01
  • 2010-09-23
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 2014-04-01
  • 2015-02-03
相关资源
最近更新 更多