python函数的编码风格

时间:2013-02-27 18:48:16

标签: python coding-style

需要一个意见。

我有一个定义一些数据的函数。我的想法是用户可以告诉它从文件中读取数据:

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”吗?有人看到更好的方法来编码吗?感谢。

6 个答案:

答案 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。

原因这是一个更好的设计

  1. 序列,生成器和文件的统一接口
  2. 您无需在函数
  3. 中读取整个数据
  4. 即使发生异常,您也可以控制文件的生命周期
  5. 骨架代码将是

    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_fileacquire_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,甚至是某些您从未参加过的课程听说这适用于openlist功能。这就是鸭子打字的本质。

当然这是对鸭子打字的一些滥用,但这是你的问题所固有的:你正在尝试采用两种不同类型之一的参数,以及任何解决方案这项工作将滥用某些功能。

唯一的担心是有人可能会传递适用于openlist的内容。事实上,对于普通的str来说,情况确实如此。所以你需要一个通用的决定如何处理这种情况 - 它似乎首先尝试作为路径名,然后作为一个序列,比其他方式更好。这肯定是你想要的str,但是你必须考虑一下这两种方式是否都适用。