[英]What is the Pythonic way to map a sequence of one custom class to another?
(...or, alternatively, what is the Pythonic version of C#'s Select(...)
method? ) (...或者,C#的
Select(...)
方法的Python版本是什么?)
Given a list l
of a custom class A
what is the (most?) Pythonic way to map each element of l
to a different custom class B
? 给定一个列表
l
的自定义类的A
是什么(最?)Python的到的每一个元素映射方式l
,以不同的自定义类B
?
for example, the following code will do it, but is it the most Pythonic way of doing it? 例如,以下代码可以做到这一点,但这是最Python化的方法吗? Note, the real types have many properties.
注意,实类型具有许多属性。
l = [A('Greg', 33), A('John', 39)]
def map_to_type_b(the_list):
new_list = []
for item in the_list:
new_list.append(B(item.name, item.age))
return new_list
l2 = map_to_type_b(l)
I'm coming from a C# background, where I would use LinQ select
or the Select()
extensions method to project from the source sequence to a new sequence of type B
. 我来自C#背景,在这里我将使用LinQ
select
或Select()
扩展方法从源序列投影到B
类型的新序列。
I would say it's part of the job of the B
class to determine how an instance of some arbitrary other class should be transformed to an instance of B
, so I would use the class method alternate constructor approach, eg as follows: 我会说这是对的工作的一部分
B
类,以确定如何一些任意其他类的实例,应转化为实例B
,所以我会用类方法可选的构造方法,例如如下:
class A(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return 'A({0.name!r}, {0.age!r})'.format(self)
class B(A):
def __repr__(self):
return 'B({0.name!r}, {0.age!r})'.format(self)
@classmethod
def from_A(cls, inst):
return cls(inst.name, inst.age)
You can then use a simple list comprehension or even map
to convert a list of one class to another, eg: 然后,您可以使用简单的列表理解甚至
map
将一个类的列表转换为另一个类,例如:
>>> l = [A('Greg', 33), A('John', 39)]
>>> l
[A('Greg', 33), A('John', 39)]
>>> map(B.from_A, l) # will look different, but is more memory-efficient, in 3.x
[B('Greg', 33), B('John', 39)]
>>> [B.from_A(a) for a in l] # works (nearly) identically in 2.x and 3.x
[B('Greg', 33), B('John', 39)]
Writing data-only objects is frowned upon not only in Python but in most OO-based languages. 不仅在Python中,而且在大多数基于OO的语言中,编写纯数据对象的方法都被禁止。 Probably the most Pythonic way would be pass flat data around, lets say, a dict or list of dicts:
也许最Python化的方式是传递一个平面数据或一系列字典:
{'Greg': 33, 'John': 39}
[{'name': 'Greg', 'age': 33}, {'name': 'John', 'age': 39}]
That said, suppose you have classes A and B and you want to instantiate new Bs from existing A instances: 也就是说,假设您具有类A和B,并且要从现有A实例实例化新的B:
class A(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return '<{cls} name={s.name}, age={s.age}>'.format(
cls=self.__class__.__name__,
s=self
)
class B(A):
def __init__(self, name, age, born_as='male'):
super(B, self).__init__(name, age)
self.born_as = born_as
data = {'Greg': 33, 'John': 39}
list_of_a = [A(k, v) for k, v in data.items()]
You can keep it simple and just be explicit: 您可以使其简单明了:
>>> list_of_a
[<A name=Greg, age=33>, <A name=John, age=39>]
>>> [B(a.name, a.age) for a in list_of_a]
[<B name=Greg, age=33>, <B name=John, age=39>]
If there are a lot of attributes involved, this can get a bit verbose. 如果涉及很多属性,则可能会有些冗长。 Lets teach B how to clone an A:
让我们教B如何克隆A:
class B(A):
def __init__(self, name, age, born_as='male'):
super(B, self).__init__(name, age)
self.born_as = born_as
@classmethod
def clone(cls, instance, *args, **kwargs):
return cls(instance.name, instance.age, *args, **kwargs)
Since B now knows how to clone A: 由于B现在知道如何克隆A:
>>> [B.clone(a) for a in list_of_a]
[<B name=Greg, age=33>, <B name=John, age=39>]
It can get tedious to write clone methods for all B-like classes. 为所有类似B的类编写克隆方法可能很麻烦。 Introspection is very Pythonic, so lets not repeat ourselves:
内省是Python风格的,所以不要重复自己:
class CloneFromInstanceMixin(object):
@classmethod
def clone(cls, instance, **kwargs):
constructor_args = inspect.getargspec(instance.__init__).args
for attr_name in constructor_args:
if attr_name in kwargs:
continue # overrides instance attribute
try:
kwargs[attr_name] = getattr(instance, attr_name)
except AttributeError:
pass
return cls(**kwargs)
class B(CloneFromInstanceMixin, A):
def __init__(self, name, age, born_as='male'):
super(B, self).__init__(name, age)
self.born_as = born_as
>>> [B.clone(a) for a in list_of_a]
[<B name=Greg, age=33>, <B name=John, age=39>]
I probably have too much free time. 我可能有太多的空闲时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.