Python如何优雅地处理不同数据结构的用法?
我使用Python 3.5,这是我处理目前代码:Python如何优雅地处理不同数据结构的用法?
def is_odd_number(n):
"""states if n is an odd number"""
return n % 2 == 1
def collatz_next(n):
"""returns the successor to n in Collatz sequence"""
return 3*n + 1 if is_odd_number(n) else n//2
def collatz_seq_sum(seq):
"""returns the sum of all elements to a given Collatz sequence"""
return sum(seq)
def collatz_seq(n):
"""returns the Collatz sequence to n"""
l = []
l.append(n)
current = n
while current != 1:
next_one = collatz_next(current)
l.append(next_one)
current = next_one
return l
def collatz_seqs(lower_limit=1, upper_limit=10):
"""returns Collatz sequences from lower_limit to upper_limit"""
return {i: collatz_seq(i) for i in range(lower_limit, upper_limit+1)}
我认为这类型list
是最好的一个在Collatz序列的时候。这就是为什么collatz_seq
返回一个列表。然而,我发现观察连续处理多个参数n
时这个特定序列是如何发展是很有趣的。这就是为什么我创建了collatz_seqs
。
我不喜欢collatz_seq_sum
有一个非常简单的原因:它只有在参数seq
的类型为list
时才能正常工作。在我看来,collatz_seq_sum
不是确保提供适当的实际参数的责任,在这种情况下,list
由自然数组成。在我看来,致电collatz_seq_sum
必须确保它提供了一个正确的参数。
我想要collatz_sum_seq
可以使用单个和多个序列。 collatz_seq
返回list
和collatz_seqs
返回dict
。因此我的问题是:确保collatz_seq_sum
始终为其参数seq
获取正确数据类型的优雅方法是什么?关于collatz_seq_sum
的正确工作,我可以做些什么?collatz_seq_sum
关心其参数seq
的数据类型?我的第一个想法是更改collatz_seq
以使其返回dict
而不是list
并更改collatz_seq_sum
以处理dict
。但是,我不喜欢这种方法,因为我不想在处理单个序列时使用dict
。
您有任何解决方案吗?非常感谢你提前。
是检查给出的参数的类型:
from collections.abc import Mapping, Iterable
def collatz_seq_sum(seq):
"""returns the sum of all elements to a given Collatz sequence"""
if isinstance(seq, Mapping):
ret = {key: sum(values) for key, values in seq.items()}
elif isinstance(seq, Iterable):
ret = sum(seq)
else:
msg = "collatz_seq_sum got unexpected type: '{}'".format(type(seq))
raise TypeError(msg)
return ret
如果你想要一个功能不同的行为取决于输入这种类型
是要走的路。
感谢您的输入。这是一个很好的论据,我理解它。我只是想知道:这是唯一的方法吗?假设您使用的脚本使用了数百个(如果不是数千个)函数。我的意思是它总是一遍又一遍:每个函数检查其参数的类型并相应地执行操作。一遍又一遍地做同样的事情变得非常乏味,我认为很难阅读和维护。 – 6q9nqBjo
这是什么类(和鸭子打字)。这是Python的哲学。 –
如果我理解正确,那么您希望collatz_seq_sum
可以同时使用collatz序列或单个collatz序列。在字典的情况下,您希望函数返回单个拼贴序列总和的字典。
您可以使用isinstance
来检查输入seq
是字典还是列表,并针对每种情况运行不同的代码。下面的代码将工作。
def collatz_seq_sum(seq):
"""returns the sum of all elements to a given Collatz sequence"""
if isinstance(seq, dict):
return {i: sum(seqi) for i, seqi in seq.items()}
else:
return sum(seq)
但是,如果你想要的是什么字典的所有序列的总和,你可以使用,而不是做多态的功能在Python的唯一途径以下,
def collatz_seq_sum(seq):
"""returns the sum of all elements to a given Collatz sequence"""
if isinstance(seq, dict):
return sum([sum(seqi) for i, seqi in seq.items()])
else:
return sum(seq)
Python 3.4+ - functools.singledispatch让你过载基于参数类型的函数定义。
from functools import singledispatch
@singledispatch
def collatz_seq_sum(seq):
'''returns the sum of all elements to a given Collatz sequence'''
raise NotImplementedError("I can't handle that data type")
@collatz_seq_sum.register(list)
def _(seq):
return sum(seq)
@collatz_seq_sum.register(dict)
def _(seq):
return {key: sum(values) for key, values in seq.items()}
>>> collatz_seq_sum([1,2,3,4,5])
15
>>> collatz_seq_sum({'a': [1,1,1,1], 'b': [2,2,2,2]})
{'a': 4, 'b': 8}
调用collatz_seq_sum
比列表或字典其他东西将引发NotImplementedError
。
[mypy](https://github.com/python/mypy)静态类型检查库提供了[装饰器](https://jeffknupp.com/blog/2013/11/29/improve-your- python-decorators-explained /)命名为“重载”,它似乎允许你想要的那种多态:http://mypy.readthedocs.io/en/latest/function_overloading.html。看起来很有希望给我。 –
会[functools.singledispatch](https://docs.python.org/3/library/functools.html#functools.singledispatch)有帮助吗? – wwii