【问题标题】:Return a variable by name from a function in Python [duplicate]从Python中的函数按名称返回变量[重复]
【发布时间】:2018-05-09 20:02:04
【问题描述】:

我正在尝试使用函数返回给定列表。

def get_ext(file_type):
    text = ['txt', 'doc']
    audio = ['mp3', 'wav']
    video = ['mp4', 'mkv']
    return ?????

get_ext('audio')  #should return de list ['mp3', 'wav']

那我就卡住了。这是一个大扩展列表的简单/简短示例。 最简单的方法是什么?

【问题讨论】:

  • 我已经关闭了这个,因为这两种情况下的解决方案都是使用字典。
  • @cᴏʟᴅsᴘᴇᴇᴅ 我重新打开了,因为这个事实并没有使它成为同一个问题。
  • @timgeb 另见一个我本可以关闭但没有关闭的非常相似的 - stackoverflow.com/questions/9437726/…
  • @cᴏʟᴅsᴘᴇᴇᴅ 我犹豫要不要使用stackoverflow.com/questions/9437726/…,因为我们真的想教人们使用globals吗?我宁愿让问题保持开放,但这可能完全是我的偏见,因为我做出了接受的答案。
  • @timgeb:那个副本是正确的,我已经重新关闭了它。但是,我在组合中添加了另一篇文章。不,在这种情况下globals() 不会有帮助,但是构建字典来保存命名空间的建议

标签: python list function


【解决方案1】:

在大多数情况下,普通字典就可以完成这项工作。

>>> get_ext = {'text': ['txt', 'doc'],
...            'audio': ['mp3', 'wav'],
...            'video': ['mp4', 'mkv']
... }
>>> 
>>> get_ext['video']
['mp4', 'mkv']

如果您真的想要或需要一个功能(可能有正当理由),您有几个选择。最简单的方法之一是分配给字典的get 方法。如果你不用窗帘后面的字典,你甚至可以重新分配名称get_ext

>>> get_ext = get_ext.get
>>> get_ext('video')
['mp4', 'mkv']

如果您输入未知密钥,此函数将默认返回 None

>>> x = get_ext('binary')
>>> x is None
True

如果您想要 KeyError 代替未知键,请分配给 get_ext.__getitem__ 而不是 get_ext.get

如果您想要自定义默认值,一种方法是将字典包装在函数中。此示例使用空列表作为默认值。

def get_ext(file_type):
    types = {'text': ['txt', 'doc'],
             'audio': ['mp3', 'wav'],
             'video': ['mp4', 'mkv']
    }

    return types.get(file_type, [])

但是,@omri_saadon 给出了有效的注释,即每次函数调用都会执行 types = ... 赋值。如果这让您感到困扰,您可以采取以下措施来解决这个问题。

class get_ext(object):
    def __init__(self):
        self.types = {'text': ['txt', 'doc'],
                      'audio': ['mp3', 'wav'],
                      'video': ['mp4', 'mkv']
        }

    def __call__(self, file_type):
        return self.types.get(file_type, [])

get_ext = get_ext()

从这里开始,您可以像使用常规函数一样使用get_ext,因为最终可调用对象是可调用对象。 :)

请注意,这种方法 - 除了 self.types 只创建一次这一事实之外 - 具有相当大的优势,您仍然可以轻松更改函数识别的文件类型。

>>> get_ext.types['binary'] = ['bin', 'exe']
>>> get_ext('binary')
['bin', 'exe']

【讨论】:

  • 我建议你走得更远,只需使用字典,Ludoloco。为什么要浪费时间和打字呢?字典提供了您正在寻找的功能。 (正如这个答案雄辩地证明)
  • @TheNate 您可以将此作为答案(我很惊讶没有一个答案能说明这一点)。在函数中包装字典似乎只是使用圆括号而不是方括号。
  • @JohnColeman 我会说这取决于函数/字典在未来的使用方式。例如,如果您打算做很多 mapping 或对可调用对象的一般传递并且对成员资格测试不感兴趣(即 key in mydict),那么该函数对我来说感觉更自然一些。但除此之外,我同意并且个人可能只会使用字典。当值检索应该与更多的计算或副作用相结合时,它变得更加有趣。然后你可以选择继承dict(更好:collections.UserDict)或编写你自己的可调用对象。
  • 另一种不使用 'just' 字典更优雅的情况是,当您希望每次查找都使用相同的默认返回值 != None 时。 (例如,此答案中建议的空列表。)
  • @timgeb 我并不反对,但 OP 给人的印象是一个不熟悉字典的新 Python 程序员。这可能是一个 XY 问题,他们的实际问题的解决方案只是以简单的方式使用的基本字典。
【解决方案2】:

根据@timgeb 的回答,我会使用字典,但如果您访问很多,请关心速度并且不想定义可以使用缓存的类。

from functools import lru_cache

def get_ext(file_type):
    d = {'text': ['txt', 'doc'],
         'audio': ['mp3', 'wav'],
         'video': ['mp4', 'mkv']}
    return d[file_type]

@lru_cache(maxsize=3, typed=False)
def get_ext_cached(file_type):
    d = {'text': ['txt', 'doc'],
         'audio': ['mp3', 'wav'],
         'video': ['mp4', 'mkv']}
    return d[file_type]

from timeit import timeit

# non cached
print(timeit(stmt='get_ext("text")', globals={'get_ext': get_ext}))
# 0.48447531609922706 on my machine

# cached
print(timeit(stmt='get_ext("text")', globals={'get_ext': get_ext_cached}))
# 0.11434909792297276

尽管对于这种特殊情况,它可能有点矫枉过正,您可以直接在字典上调用 get(缓存只是构建自己的字典并完全做到这一点),您将来可以将它用于任何实际上是计算查找的纯函数。

d = {'text': ['txt', 'doc'],
    'audio': ['mp3', 'wav'],
    'video': ['mp4', 'mkv']}

# 0.05016115184298542
print(timeit(stmt="d['text']",
             globals={'d':d,'c':c}))

【讨论】:

  • 与用调用者直接访问的字典替换函数相比,这需要大量输入。
【解决方案3】:

您可以轻松地将 dict 与元组/列表值一起使用,如下所示:

def get_ext(file_type):
    d = {'text': ['txt', 'doc'],
         'audio': ['mp3', 'wav'],
         'video': ['mp4', 'mkv']}
    return d[file_type]


print(get_ext('audio'))

【讨论】:

    【解决方案4】:

    如果您不想像在@timgeb's answer 中那样定义dictionary,则可以调用local(),它会为您提供当前variablesdictionary 可供使用。

    def get_ext(file_type):
        text = ['txt', 'doc']
        audio = ['mp3', 'wav']
        video = ['mp4', 'mkv']
        return locals()[file_type]
    

    并进行测试以证明其有效:

    >>> get_ext("text")
    ['txt', 'doc']
    

    【讨论】:

    • 不,这可行,但这是一种糟糕的方法。它利用了locals() 返回字典这一事实——使用真正的字典,这就是它们的用途!
    • @alexis 我不想说您的评论无效,但我无法理解“它利用了 locals() 返回字典的事实”的推理。我们什么时候不“利用”知道调用的返回值可以做什么?
    • 我的观点是,这个解决方案依赖于它假装避免的相同数据类型。这是一种掩盖变量名和数据之间区别的技巧......以及有什么好处?它甚至没有避免从一开始就以非常直接的方式应该使用的数据类型。
    • 附言。了解locals() 很好/很有趣;这只是完成这项任务的一种糟糕的方式。
    【解决方案5】:

    使用字典:

    def get_ext(file_type):
        d = {'text' : ['txt', 'doc'],
             'audio' : ['mp3', 'wav'],
             'video' : ['mp4', 'mkv']}
        try:
            return d[file_type]
        except KeyError:
            return []
    
    get_ext('audio') # ['mp3', 'wav']
    

    如果该键不存在,则返回空列表。 这是我想到的最简单的答案,要获得更好的答案,请参阅@timgeb 答案。

    【讨论】:

    • 我猜有人因为你错误地缩进return而投了反对票。解决这个问题。 +1,因为这是正确的想法。
    • 实际上,我不喜欢这种方法,因为每次调用get_ext 都会创建一个新字典,这是多余的。最好将dict和getter的创建分开。
    • 沃茨缓存人?
    • @omri_saadon,你确定吗?
    • @omri_saadon 您的评论有效。我编辑了我的答案。
    猜你喜欢
    • 2021-04-03
    • 2015-08-11
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 2014-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多