我的reduce getattr问题的python解决方案

2024-04-26 14:31:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我曾经使用reduce and getattr函数以链式方式调用属性,如“这个属性。那个属性。布拉塔" 即:

reduce(getattr, 'xattr.yattr.zattr'.split('.'), myobject)

工作非常好,但是现在我有了一个新的要求,我的字符串可以像这样调用一个特定数量的属性:“这个属性。那个属性[2] “布拉塔”

^{pr2}$

现在它不工作了,我得到xattr object has no attribute 'yattr[2]'错误。在

对于这两种情况,哪种方法都有效,哪一种解决方法都很简单呢?在

问候


Tags: and方法函数字符串reduce数量属性方式
3条回答

你可以试试:

import re
extended_split = re.compile(r'''\[\d+\]|[^\[.]+''').findall

def extended_getattr(obj, comp):
    if comp[0] == '[':
        return obj[int(comp[1:-1])]
    else:
        return getattr(obj, comp)

reduce(extended_getattr, extended_split('xattr.yattr[2].zattr'), myobject)

注意,它假设[…]内的内容是一个非负的十进制数。在


如果您关心性能,在我的测试中,它仍然比eval快:

^{pr2}$

z.py的内容:

import re
import random
from functools import reduce

extended_split = re.compile(r'''\[\d+\]|[^\[.]+''').findall

def extended_getattr(obj, comp):
    if comp[0] == '[':
        return obj[int(comp[1:-1])]
    else:
        return getattr(obj, comp)

class Foo(object):
    def __init__(self):
        self.foo = self

    def __getitem__(self, i):
        return self

def construct_random_string():
    yield 'foo'
    for i in range(2000):
        if random.randrange(2):
            yield '.foo'
        else:
            yield '[0]'


random.seed(0)  # to ensure fair comparison
rs = ''.join(construct_random_string())

f = Foo()

def f1(names, obj):
    return reduce(extended_getattr, extended_split(names), obj)

def f3(attrstring, objname) :
    return eval( '%s.%s' % (objname, attrstring) )

您所要求的似乎相当困难,因为您希望将属性选择与方法调用混合起来(因为索引只是调用的糖分)。通过使用getattr为您提供一个绑定方法,调用函数非常容易,但是您需要将字符串中包含参数的部分转换为实际参数。在

既然您无论如何都需要eval()来计算参数,那么为什么不全部求值呢?在

def proc(objname, attrstring ) :
  return eval( '%s.%s' % (objname,attrstring) )

你的例子是:

^{pr2}$

稍后,您可能希望调用某个方法而不是获取属性。快速地重新实现python方法的某些部分将成为一场噩梦。即使当前的getattr/getitem支持需求也不能作为一个行程序来解决。在

相反,您可以使用python本身来解释python

# Create some object for testing
>>> class A(object):
...     b = None
... 
>>> a = A()
>>> a.b = A()
>>> a.b.b = A()
>>> a.b.b.b = [A(), A(), A(), A()]
>>> a.b.b.b[1].b
>>> a.b.b.b[1].b = "Some result"
>>> 
>>> ctx = {'obj':a, 'val':None}
>>> exec("val = obj.{0}".format('b.b.b[1].b')) in ctx
>>> ctx['val']
'Some result'

相关问题 更多 >