如何按(字符串)名称选择变量?

How can I select a variable by (string) name?

提问人:Ludoloco 提问时间:11/26/2017 最后编辑:Karl KnechtelLudoloco 更新时间:10/15/2022 访问量:9854

问:

我想根据字符串输入从我的函数返回一个预先确定的列表。

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

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

最简单的方法是什么?


有关尝试使用字符串赋值或创建变量的相关问题,请参阅如何创建变量变量?。这个问题是关于查找它们。

有关查找现有对象(而不是在当前局部变量中)的信息,请参阅如何访问给定与该属性名称对应的对象属性

python 字符串 变量

评论

0赞 cs95 11/27/2017
@timgeb 还看到一个非常相似的,我本来可以关闭但没有关闭的 - stackoverflow.com/questions/9437726/......
0赞 cs95 11/27/2017
这与前一个不同,但也以相同的方式关闭。如果目标中的答案解决了这个问题,我认为没问题。
0赞 timgeb 11/27/2017
@c ᴏʟᴅsᴘᴇᴇᴅ 我想这将是一个更好的欺骗目标,它再次被欺骗到你最初提出的目标......不能反驳。(尽管我仍然认为创建动态变量数和按字符串查找变量之间存在差异)
1赞 timgeb 11/27/2017
@c ᴏʟᴅsᴘᴇᴇᴅ 我犹豫要不要用 stackoverflow.com/questions/9437726/......因为我们真的想教人们使用吗?我宁愿让这个问题保持开放,但这完全可能是我的偏见,因为我做出了公认的答案。globals
2赞 Martijn Pieters 11/27/2017
@timgeb:那个副本是正确的,我已经重新关闭了它。但是,我在混合中添加了另一篇文章。不,在这种情况下没有帮助,但构建一个字典来保存命名空间的建议globals()

答:

1赞 ᴀʀᴍᴀɴ 11/26/2017 #1

使用字典:

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

评论

0赞 timgeb 11/26/2017
我猜有人脾气暴躁,因为你错误地缩进了 .只要解决这个问题。+1,因为这是正确的想法。return
1赞 omri_saadon 11/26/2017
实际上,我不喜欢这种方法,因为每次调用新字典都是多余的。最好将 dict 和 getter 的创建分开。get_ext
0赞 Argus Malware 11/26/2017
Wats 缓存人?
0赞 timgeb 11/26/2017
@omri_saadon好吧,你确定吗?
1赞 timgeb 11/26/2017
@omri_saadon您的评论是有效的。我编辑了我的答案。
32赞 timgeb 11/26/2017 #2

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

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

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

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

如果输入未知键,此函数将默认返回:None

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

如果要 代替未知键,请分配给 而不是 。KeyErrorget_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']

评论

4赞 The Nate 11/27/2017
我建议你走得更远,用字典,Ludoloco。为什么要浪费时间和打字呢?字典提供了您正在寻找的功能。(正如这个答案雄辩地证明的那样)
2赞 John Coleman 11/27/2017
@TheNate 你可以把这个答案作为答案(我很惊讶没有一个答案能说明这一点)。将字典包装在函数中似乎是一项非常繁重的工作,只是为了使用圆括号而不是方括号。
0赞 timgeb 11/27/2017
@JohnColeman 我想说这取决于函数/字典在未来的使用方式。例如,如果您打算对可调用对象进行大量 ping 或一般传递,并且对成员资格测试不感兴趣(即),那么该函数对我来说感觉更自然一些。但除此之外,我同意,并且个人可能只是使用一个字典。当值检索应该与更多的计算或副作用相结合时,它会变得更加有趣。然后你可以选择子类化(更好:)或编写你自己的可调用对象。mapkey in mydictdictcollections.UserDict
0赞 timgeb 11/27/2017
另一种不使用“just”字典更优雅的情况是,当您希望每次查找都使用相同的默认返回值 != 时。(例如,一个空列表,如本答案中所示。None
0赞 John Coleman 11/27/2017
@timgeb 我并不是真的不同意,但 OP 给人的印象是一个不熟悉字典的新 Python 程序员。这可能是一个 XY 问题,其中实际问题的解决方案只是一个以简单方式使用的基本字典。
4赞 Jump3r 11/26/2017 #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'))
12赞 Joe Iddon 11/26/2017 #4

如果您不想在 @timgeb 的答案中定义 a,则可以调用 ,这将为您提供局部作用域中可用的变量。dictionarylocals()dict

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

以及一个测试来证明它有效:

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

评论

15赞 alexis 11/27/2017
不,这有效,但这是一种糟糕的方法。它利用了返回字典的事实——使用真正的字典,这就是它们的用途!locals()
2赞 timgeb 11/30/2017
@alexis 我不想说你的评论是无效的,但我不能支持“它利用了 locals() 返回字典的事实”的推理。我们什么时候不“利用”知道调用的返回值可以做什么?
1赞 alexis 12/1/2017
我的观点是,此解决方案依赖于它假装避免的相同数据类型。这是一个黑客,模糊了变量名称和数据之间的区别......有什么好处?它甚至没有从一开始就以一种非常直接的方式避免应该使用的数据类型。
1赞 alexis 12/1/2017
PS.了解它很好/很有趣;这只是完成这项任务的一种可怕方式。locals()
0赞 Karl Knechtel 7/5/2022
@alexis 我同意这一点,但创造者与其他任何创造者一样“真实”。请记住,修改它可能不会像您预期的那样工作explicit is better than implicitdictlocals()
1赞 Turksarama 11/27/2017 #5

根据 @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赞 Arthur Tacca 11/27/2017
与将函数替换为调用者直接访问的字典相比,这是大量的键入。