2010-07-30 7 views
5

का हल मैं की तरह "thisattr.thatattr.blaattar" आईई एक श्रृंखला तरह से विशेषताओं फोन करने के लिए reduce and getattr कार्यों का उपयोग करने के लिए इस्तेमाल:pythonic मेरी getattr को कम समस्या

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

वर्क्स एक बिल्कुल ठीक, हालांकि अब मेरे पास है नई आवश्यकता है, मेरे तार जैसे एक विशेषता की एक विशिष्ट संख्या के लिए कॉल कर सकते हैं: "thisattr.thatattr [2] .blaattar"

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

अब यह काम नहीं करता, मैं xattr object has no attribute 'yattr[2]' त्रुटि मिलती है।

क्या यह करने के लिए एक elegent समाधान है, जो किसी भी तरह से काम करता है के लिए हो सकता है?

सादर

उत्तर

0

आप

  1. की जरूरत मिल जाएगा xattr.yattr
  2. कि
  3. दूसरे मद से की दूसरे मद जाओ,

आप के रूप में zattr मिल देख सकते हैं, इसमें दो अलग-अलग संचालन शामिल थे। reduce ऐसा नहीं कर सकता (सुंदरता से)। दोनों के लिए काम करने वाले समाधान को यह पता लगाने के लिए स्ट्रिंग को पार्स करना होगा कि अनुक्रमित पहुंच की आवश्यकता है। एक साधारण लेकिन नाजुक (अर्थात, अगर खिलाया बी एस अपरिभाषित व्यवहार करता है) समाधान दिखाई देगा:

def extended_chain_getattr(names, obj): 
    import re 
    result = obj   
    for name in names.split('.'): 
     name_match = re.match(r'([a-zA-Z_][a-zA-Z0-9_]*)(\[\d\])?', name) 
     assert name_match is not None 
     result = getattr(result, name_match.group(1)) 
     if len(name_match.groups()) == 2: 
      index = int(name_match.group(2)) 
      result = result[index] 
    return result 

मेरे सिर के ऊपर बंद, इसलिए अपरीक्षित।

+0

काम करने के लिए प्रतीत नहीं होता। – kennytm

+0

कुछ और जानकारी के बारे में कैसे? – delnan

+0

जब मैं 'expand_chain_getattr ('foo', Foo_obj) प्राप्त करने का प्रयास करता हूं, तो उसने कहा 'विशेषता Err:' Foo 'ऑब्जेक्ट में कोई विशेषता नहीं है' fo''। – kennytm

1

और बाद में आप विशेषता प्राप्त करने के बजाय कुछ विधि कॉल करना चाह सकते हैं। पाइथन दृष्टिकोण के पुन: कार्यान्वयन भागों को जल्दी से एक दुःस्वप्न बन जाएगा। यहां तक ​​कि गेटैटर/गेटिटम समर्थन की वर्तमान आवश्यकता को एक-लाइनर के रूप में हल नहीं किया जा सकता है।

बजाय, आप बस अजगर इस्तेमाल कर सकते हैं अपने आप में अजगर व्याख्या करने के लिए,

# 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' 
0

क्या आप के लिए पूछ रहे हैं काफी मुश्किल लगता है के रूप में आप मिश्रण करने विधि कॉल के साथ विशेषता चयन (के रूप में सूचकांक सिर्फ एक के लिए चीनी है चाहता हूँ कहते हैं)। आपको एक बाध्य विधि देने के लिए गेटिंग फ़ंक्शन का उपयोग करके कॉलिंग फ़ंक्शंस करना काफी आसान है, लेकिन फिर आपको स्ट्रिंग के उस भाग को कन्वर्ट करने की आवश्यकता है जिसमें वास्तविक तर्कों में तर्क शामिल हैं।

यह देखते हुए कि आप एक eval() वैसे भी तर्क गणना करने के लिए की आवश्यकता होगी, क्यों सिर्फ पूरी बात eval नहीं?

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

आपका उदाहरण तो है:

proc("myobject", "xattr.yattr[2].zattr") 
1

आप की कोशिश कर सकते: यह […] अंदर सामान मान लिया गया एक गैर नकारात्मक दशमलव संख्या है

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 से:

~:491$ python -m timeit -s 'from z import f1, f3, f, rs' 'f3(rs, "f")' # eval 
100 loops, best of 3: 5.62 msec per loop 

~:492$ python -m timeit -s 'from z import f1, f3, f, rs' 'f1(rs, f)'  # my method 
100 loops, best of 3: 4.69 msec per loop 

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)) 
0

यहाँ एक छोटे से पार्सर टुकड़ा संभाल करने के लिए है और नेस्टेड सूची नोटेशन:

# define class that we can just add attributes to 
class Bag(object): pass 

z = Bag() 
z.xattr = Bag() 
z.xattr.yattr = [Bag(), Bag(), Bag()] 
z.xattr.yattr[2].zattr = 100 
z.xattr.yattr[1] = [0,1,2,3,4,5] 

from pyparsing import * 

LBRACK,RBRACK = map(Suppress,'[]') 
ident = Word(alphas+"_", alphanums+"_") 
integer = Word(nums+'-',nums).setParseAction(lambda t:int(t[0])) 
NONE = Literal("None").setParseAction(replaceWith(None)) 
indexref = LBRACK + Group(delimitedList((Optional(integer|NONE,None)), delim=':')) + RBRACK 
compoundAttr = delimitedList(Group(ident("name") + ZeroOrMore(indexref)("index")), delim='.') 

def lookup(ob, attr): 
    try: 
     attrParts = compoundAttr.parseString(attr) 
    except ParseException: 
     raise AttributeError("could not resolve compound attribute '%s'" % attr) 

    # remaining code will raise AttributeError or IndexError as appropriate 

    ret = ob 
    for a in attrParts: 
     ret = getattr(ret, a.name) 
     if a.index: 
      for i in a.index: 
       if len(i) == 1: 
        ret = ret[i[0]] 
       else: 
        ret = ret[slice(*i.asList())] 
    return ret 


print len(lookup(z, 'xattr.yattr')) 
print len(lookup(z, 'xattr.yattr[1:3]')) 
print len(lookup(z, 'xattr.yattr[None:3]')) 
print lookup(z, 'xattr.yattr[1][None:4]') 
print sum(lookup(z, 'xattr.yattr[1][:4]')) 
print lookup(z, 'xattr.yattr[2].zattr') 
0

मैं का उपयोग इस

reduce(lambda i, j: getattr(i, j), 'xattr.yattr.zattr'.split('.'), myobject)

+0

कृपया अपना कोड संपादित करने के बारे में और स्पष्टीकरण जोड़ने के लिए अपनी पोस्ट को संपादित करने पर विचार करें और यह समस्या का समाधान क्यों करेगा। एक उत्तर जिसमें ज्यादातर कोड शामिल होते हैं (भले ही यह काम कर रहा हो) आमतौर पर ओपी को उनकी समस्या को समझने में मदद नहीं करेगा। – SuperBiasedMan

+0

आप लैम्ब्डा का उपयोग क्यों कर रहे हैं? आप 'getattr' को' कम करें 'के पहले तर्क के रूप में पास कर सकते हैं। –

संबंधित मुद्दे