def class_retaining_map(fun, iterable):
if type(iterable) is list: # not using isinstance(), see below for reasoning
return [ fun(x) for x in iterable ]
elif type(iterable) is set:
return { fun(x) for x in iterable }
elif type(iterable) is dict:
return { k: fun(v) for k, v in iterable.items() }
# ^^^ use .iteritems() in python2!
# and depending on your usecase this might be more fitting:
# return { fun(k): v for k, v in iterable.items() }
else:
raise TypeError("type %r not supported" % type(iterable))
def class_retaining_map(fun, iterable):
if isinstance(iterable, (list, set)):
return type(iterable)(fun(x) for x in iterable)
elif isinstance(iterable, dict):
return type(iterable)((k, fun(v)) for k, v in iterable.items())
# ^^^ use .iteritems() in python2!
# and depending on your usecase this might be more fitting:
# return type(iterable)((fun(k), v) for k, v in iterable.items())
else:
raise TypeError("type %r not supported" % type(iterable))
from collections import Iterable
def mymap(f, contener):
if isinstance(contener, Iterable):
return type(contener)(map(f, contener))
return 'Input object is not iterable'
使用输入类型作为转换器并不一定在所有情况下都有效。
map
只是使用其输入的“可编辑性”来生成输出。在Python3中,这就是为什么map
返回生成器而不是列表(这更适合)。在因此,一个更干净、更健壮的版本应该是明确地期望它可以处理的各种可能的输入,并且在所有其他情况下都会引发错误:
您可以在原因的
^{pr2}$else
子句中为所有其他iterable值添加一个case:但这将为
set
的子类返回iterable,这可能不是您想要的。在请注意,我故意使用
isinstance
,因为这会使list
的子类组成一个列表。我想在这种情况下这显然是不需要的。在有人可能会争辩说,任何属于
list
(即list
的子类)都需要遵守构造函数,该构造函数为元素的迭代返回这种类型的东西。同样地,对于set
,dict
(这必须用于对的迭代)等的子类,那么代码可能如下所示:直接实例化,而不是通过
eval
__class__
也可用于实例化新实例:这就消除了对} 而不是魔术方法:
^{pr2}$eval
的需要,它的使用被认为是poor practice。根据@EliKorvigo的评论,您可能更喜欢内置的^{如here和the docs中所述:
对于新样式的类,“一般相同”应被视为“等效”。在
测试iterable
您可以用几种方法检查/测试iterable。使用}:
try
/except
捕获{或使用^{} :
这是因为内置的类通常用作容器,如
list
、set
、tuple
、collections.deque
等,可以通过lazy-iterable来实例化实例。存在异常:例如,str(map(str.upper, 'hello'))
将无法像您预期的那样工作,即使str
实例是可编辑的。在首先,让我们来讨论Haskell的
fmap
来理解它为什么会这样做,尽管我假设您对Haskell考虑这个问题相当熟悉。fmap
是在{a1}中定义的泛型方法:函子遵循几个重要的数学定律,并且有几种从
fmap
导出的方法,尽管后者对于最小完全函子实例来说已经足够了。换句话说,在属于Functor
类型类的Haskell类型中,实现了它们自己的fmap
函数(此外,Haskell类型可以通过newtype
定义拥有多个Functor
实现)。在Python中,我们没有类型类,但是我们有一些类,虽然在本例中不太方便,但允许我们模拟这种行为。不幸的是,对于类,我们不能在没有子类化的情况下向已经定义的类添加功能,这限制了我们为所有内置类型实现泛型fmap
的能力,尽管我们可以通过在fmap
实现中显式检查可接受的iterable类型来克服它。实际上,使用Python的类型系统来表达更高级的类型是不可能的,但是我离题了。在总而言之,我们有几个选择:
Iterable
类型(@jpp的解决方案)。它依赖于构造函数将Python的map
返回的迭代器转换回原始类型。这就是对容器中的值应用函数的职责,它将从容器中取出。这种方法与函子接口有很大的不同:函子应该自己处理映射,并处理对重建容器至关重要的其他元数据。在这是我对第三种解决方案的看法
^{pr2}$这是一个演示
此解决方案允许我们通过子类化为同一类型定义多个函子:
相关问题 更多 >
编程相关推荐