我正在寻找一个函数f(x,selector)
,当x.get(selector)
是字典时就像x
一样,而当getattr(x, selector)
是一个类实例时,x
就像{{1}}一样。写得容易,但内置了吗?
答案 0 :(得分:3)
不,没有内置功能。</ p>
只是异常处理:
def f(x, selector):
try:
# Assume dictionary and has .get() method
return x.get(selector)
except AttributeError:
# Assumption incorrect, no .get() method present
return getattr(x, selector)
如果要首先检查属性,请或交换两行。
另一种变体,支持默认值:
_sentinel = object()
def f(x, selector, default=_sentinel):
try:
# Assume mapping access is supported
result = x[selector]
except KeyError:
# key missing, fall through to default handling
pass
except TypeError:
# Assumption incorrect, not a mapping, fall back to attributes
result = getattr(x, selector, default)
if result is _sentinel:
raise KeyError(selector)
return default
但您也可以将KeyError
处理方式折叠为第二个TypeError
处理程序,然后再回到getattr()
。
但是考虑到你在尝试混合两个命名空间;键和属性可能会发生冲突,属性文字比键等更受限制。大多数Python代码都没有尝试将两者混合,这是为什么没有内置的任务
答案 1 :(得分:2)
另一种方法是检查对象的类型
def f(x, selector):
if isinstance(x, dict):
return x.get(selector)
return getattr(x, selector)
答案 2 :(得分:0)
In [297]: class Foo:
.....: def __init__(self):
.....: self.bar=5
.....:
In [298]: def f(x, selector):
.....: if hasattr(x, 'get'):
.....: g = operator.itemgetter(selector)
.....: else: # x is an object
.....: g = operator.attrgetter(selector)
.....: return g(x)
.....:
In [299]: x = Foo()
In [300]: f(x, 'bar')
Out[300]: 5
In [301]: d = {char:i for i,char in enumerate('asdf')}
In [302]: f(d, 'a')
Out[302]: 0
In [303]: d
Out[303]: {'a': 0, 's': 1, 'd': 2, 'f': 3}