需要一个意见。
我有一个定义一些数据的函数。我的想法是用户可以告诉它从文件中读取数据:
acquire_data('read_from_file',filename)
或用户可以直接提供数据:
acquire_data('use_this_list',datalist)
因此该函数将具有类似
的形式def acquire_data(mode,arg2):
if mode == 'read_from_file':
inputs=open(arg2)
data = #etc.
else:
data = arg2 #or deepcopy(arg2) or whatever
嗯,这很有效,但似乎有些老套。特别是,“arg2”具有非常不同的功能,具体取决于“模式”的值。那么:这个好代码吗?这是“pythonic”吗?有人看到更好的方法来编码吗?感谢。
答案 0 :(得分:5)
def acquire_data(list_or_filename):
# assuming py3 here, for py2 use 'isinstance(list_or_filename, basestring)
if isinstance(list_or_filename, str):
with open(list_or_filename,"r") as f:
return acquire_data_from_file(f)
else:
return acquire_data_from_list(list_or_filename)
答案 1 :(得分:4)
不是让acquire_data
打开并阅读文件的整个内容,而是将fileObj
传递给acquire_data
会更加pythonic。
原因这是一个更好的设计
骨架代码将是
def acquire_data(iterable):
for line in iterable:
# Do what ever you want
with open("whatever") as fin:
acquire_data(fin)
acquire_data(some_seq)
acquire_data(some_gen)
答案 2 :(得分:2)
如何为不同的任务使用不同的功能:acquire_data_from_file
,acquire_data_from_list
等?更清晰,更简单。
答案 3 :(得分:1)
这种工作我会进一步划分并使用dict作为开关案例:
def read_file(arg):
# code
def read_data(arg):
# code
def default_f(arg):
# code
def acquire_data(mode, arg2):
fun = {
'read_from_file': read_file,
'use_this_list': read_data
}.get(mode, default_f)
fun(arg2)
修改强>:
第二种方法:结合我和@möter。
def acquire_data(arg):
fun = {
True: read_file,
False: read_data
}.get(
isinstance(arg, str),
default_f
)
return fun(arg);
打电话给:
acquire_data('read_from_file',filename)
acquire_data('use_this_list',datalist)
答案 4 :(得分:1)
由于Python的duck-typing,函数根据变量或参数的数据类型执行不同的行为,这种做法相对常见。
你可以保留你的功能,不过我会考虑做
if mode == 'read_from_file':
inputs=open(arg2)
data = #etc.
elif mode == 'use_this_list':
data = arg2 #or deepcopy(arg2) or whatever
else:
raise InputError # or something like this
Jut确保您的函数是可扩展的,并且没有任何不正确的参数传递给函数的第二部分。
除了数据本身之外,另一种方法可能只是接受一个打开的文件和/或文件名:
def acquire_data(arg):
if isinstance(arg, file):
data = arg.read() # make sure to parse the data
elif isinstance(arg, basestring):
data = open(arg, 'r').read() # make sure to parse
else:
data = arg
答案 5 :(得分:1)
如果你真的想要一个可以接受文件名或数据列表的单个函数(你可能没有,但你似乎对oseiskar和Abhijit建议的更多pythonic替代品有抵抗力),你绝对不希望这样做。
一般来说,如果你发现自己正在进行类型切换,那么你做错了什么。但是,基于字符串进行伪类型切换,并依赖用户将字符串与类型匹配,则更加错误。
另一种方法是尝试打开文件名,如果失败,则假设它是序列而不是文件名。 (请求宽恕比允许更容易。)例如:
def acquire_data(filename_or_list):
try:
with open(filename_or_list) as f:
data = list(f)
except TypeError:
data = list(filename_or_list)
# ... now the rest of your code uses data
即使用户传递的是unicode
文件名而不是str
,或tuple
而不是list
,甚至是某些您从未参加过的课程听说这适用于open
或list
功能。这就是鸭子打字的本质。
当然这是对鸭子打字的一些滥用,但这是你的问题所固有的:你正在尝试采用两种不同类型之一的参数,以及任何解决方案这项工作将滥用某些功能。
唯一的担心是有人可能会传递适用于open
和list
的内容。事实上,对于普通的str
来说,情况确实如此。所以你需要一个通用的决定如何处理这种情况 - 它似乎首先尝试作为路径名,然后作为一个序列,比其他方式更好。这肯定是你想要的str
,但是你必须考虑一下这两种方式是否都适用。