访问包装值、return 对象、迭代器或 yield?
access wrapped value, return object, iterator or yield?
我有一个 class ADT
,里面有一个列表。我想通过函数访问数据来包装数据。我想出了以下访问数据的方法。 我只想知道这两种方式的区别,我应该选择哪一种。
class ADT(object):
"""The comments is a possible replace in the feture
"""
def __init__(self)
#... other data...
self.adt = [1, 2, 3, 4]
#self.adt = {1:2, 3:4}
#... other logic...
def datas1(self):
return self.adt
#return self.adt.items()
def datas2(self):
return iter(self.adt)
#return iter(self.adt.items())
def datas3(self):
for i in self.adt:
yield i
#for i in self.adt.items():
# yield i
用例
l = ADT()
for i in l.datas(): #use datas1 or datas2 or datas3 as datas
#do something
照原样,您的列表,完整的,已经在内存中,因为您已经设置并定义了它的所有实体。
datas1()
将只是对 self.lst
列表对象的引用
datas2()
将 return 一个迭代器对象
datas3()
将 return 生成器对象
有关每个内容的更多信息,请阅读文档(因为 "Explain what a generator and an iterator are" 与主题无关)。
如果您没有计划任何额外的功能,您就没有理由实施它,因为将来可能会这样。您对未知数进行了过度编程。如果稍后您希望 lst
采取不同的行为,或向其添加功能,您可以选择扩展列表 class 来处理。没有理由重写和重新包装已经存在的功能。
让我尝试改进您的问题然后回答。提供包装器唯一有意义的情况是,如果您有一个潜在的 large and lazy 序列开头:
class ADT(object):
def __init__(self, count):
# Count could be very large. Or maybe you want to perform a function
# on each value before passing it to adt, e.g.,
# self.adt = (expensive_func(x) for x in xrange(count))
self.adt = xrange(count)
self.adt_as_list = list(self.adt)
self.adt_as_iter = iter(self.adt)
@property
def adt_as_gen(self):
for x in self.adt:
y = yield
yield x + y
在这种情况下,您的选择取决于用例。
1.数据可以放入内存。使用列表。
l = ADT(10)
data = l.adt_as_list
data
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2。数据无法放入内存,但您只想循环 。直接使用属性。
l = ADT(10000)
data = l.adt
func = lambda x: x + 1
(func(x) for x in l.adt).next()
>>> 1
2。数据无法放入内存,您只需要下一个值。使用迭代器。
l = ADT(10000)
data = l.adt_as_iter
data.next()
>>> 0
2。你想使用 coroutine。使用发电机。
l = ADT(10000)
data = l.adt_as_gen
data.next()
data.send(2)
>>> 2
我有一个 class ADT
,里面有一个列表。我想通过函数访问数据来包装数据。我想出了以下访问数据的方法。 我只想知道这两种方式的区别,我应该选择哪一种。
class ADT(object):
"""The comments is a possible replace in the feture
"""
def __init__(self)
#... other data...
self.adt = [1, 2, 3, 4]
#self.adt = {1:2, 3:4}
#... other logic...
def datas1(self):
return self.adt
#return self.adt.items()
def datas2(self):
return iter(self.adt)
#return iter(self.adt.items())
def datas3(self):
for i in self.adt:
yield i
#for i in self.adt.items():
# yield i
用例
l = ADT()
for i in l.datas(): #use datas1 or datas2 or datas3 as datas
#do something
照原样,您的列表,完整的,已经在内存中,因为您已经设置并定义了它的所有实体。
datas1()
将只是对self.lst
列表对象的引用datas2()
将 return 一个迭代器对象datas3()
将 return 生成器对象
有关每个内容的更多信息,请阅读文档(因为 "Explain what a generator and an iterator are" 与主题无关)。
如果您没有计划任何额外的功能,您就没有理由实施它,因为将来可能会这样。您对未知数进行了过度编程。如果稍后您希望 lst
采取不同的行为,或向其添加功能,您可以选择扩展列表 class 来处理。没有理由重写和重新包装已经存在的功能。
让我尝试改进您的问题然后回答。提供包装器唯一有意义的情况是,如果您有一个潜在的 large and lazy 序列开头:
class ADT(object):
def __init__(self, count):
# Count could be very large. Or maybe you want to perform a function
# on each value before passing it to adt, e.g.,
# self.adt = (expensive_func(x) for x in xrange(count))
self.adt = xrange(count)
self.adt_as_list = list(self.adt)
self.adt_as_iter = iter(self.adt)
@property
def adt_as_gen(self):
for x in self.adt:
y = yield
yield x + y
在这种情况下,您的选择取决于用例。
1.数据可以放入内存。使用列表。
l = ADT(10)
data = l.adt_as_list
data
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2。数据无法放入内存,但您只想循环 。直接使用属性。
l = ADT(10000)
data = l.adt
func = lambda x: x + 1
(func(x) for x in l.adt).next()
>>> 1
2。数据无法放入内存,您只需要下一个值。使用迭代器。
l = ADT(10000)
data = l.adt_as_iter
data.next()
>>> 0
2。你想使用 coroutine。使用发电机。
l = ADT(10000)
data = l.adt_as_gen
data.next()
data.send(2)
>>> 2