2011-03-25 11 views
9

मैं क्रैश पर जानकारी एकत्र करने की कोशिश कर रहा हूं और मुझे यह पता लगाने में परेशानी हो रही है कि क्रैश किए गए फ़ंक्शन में उपयोग किए जा रहे ग्लोबल्स को कैसे प्राप्त किया जाए।पायथन में, मैं फ़ंक्शन में उपयोग किए जाने वाले वैश्विक चर कैसे प्राप्त कर सकता हूं?

import inspect 

fun = 222 
other = "junk" 

def test(): 
    global fun 
    harold = 888 + fun 
    try: 
     harold/0 
    except: 
     frames = inspect.trace() 
     print "Local variables:" 
     print frames[0][0].f_locals 

     print "All global variables, not what I want!" 
     print frames[0][0].f_globals 

test() 

परीक्षण() केवल "मजेदार" का उपयोग करता है लेकिन f_globals सभी उपलब्ध ग्लोबल्स देता है। क्या इस समारोह द्वारा उपयोग किए जा रहे ग्लोबल प्राप्त करने का कोई तरीका है?

+0

यह "उपयोग" की अधिकांश परिभाषाओं के लिए 'निरीक्षण' का भी उपयोग करता है। यदि आपका मतलब "उपयोग" से कुछ और है, तो कृपया विशिष्ट रहें। – delnan

+0

उद्देश्य ग्लोबल्स में सभी अतिरिक्त सामान को बाहर निकालना है। एक कोर लाइब्रेरी है जिसे * के माध्यम से आयात किया जाता है, इसलिए उन सभी की रिपोर्ट करने के लिए बहुत सारे ग्लोबल्स हैं। वास्तव में 'मजेदार' का उपयोग करने के लिए अद्यतन किया गया प्रश्न। –

उत्तर

1

inspect.getsourcelines() का उपयोग करने के लिए एक गंदा तरीका होगा और global <varname> युक्त लाइनों की खोज करें। इसके लिए कोई अच्छी विधि नहीं है, कम से कम inspect मॉड्यूल में नहीं।

0

जैसा कि आप पहले ही पाए गए हैं, संपत्ति f_globals आपको वैश्विक नामस्थान देता है जिसमें फ़ंक्शन परिभाषित किया गया था।

जो मैं देख सकता हूं, उससे पता लगाने का एकमात्र तरीका वास्तव में किस वैश्विक चर का उपयोग किया जाता है, dis के साथ फ़ंक्शन के बाइट कोड को अलग करना है; बाइट कोड STORE_NAME, STORE_GLOBAL, DELETE_GLOBAL, आदि

3

चेक इस बाहर

a = 10 

def test(): 
    global a 
    a = 12 
    b = 12 

print "co_argcount = ",test.__code__.co_argcount 
print "co_cellvars = ",test.__code__.co_cellvars 
print "co_code = ",test.__code__.co_code 
print "co_consts = ",test.__code__.co_consts 
print "co_filename = ",test.__code__.co_filename 
print "co_firstlineno = ",test.__code__.co_firstlineno 
print "co_flags = ",test.__code__.co_flags 
print "co_freevars = ",test.__code__.co_freevars 
print "co_lnotab = ",test.__code__.co_lnotab 
print "co_name = ",test.__code__.co_name 
print "co_names = ",test.__code__.co_names 
print "co_nlocals = ",test.__code__.co_nlocals 
print "co_stacksize = ",test.__code__.co_stacksize 
print "co_varnames = ",test.__code__.co_varnames 
+0

आप उल्लेख करना चाहेंगे कि इसमें Python 2.6 या इससे अधिक की आवश्यकता है। –

+1

धन्यवाद! सौभाग्य से मैं 2.6 का उपयोग कर रहा हूं इसलिए 'test.__ कोड __। Co_names' वही था जो मैं ढूंढ रहा था। इस विशिष्ट मामले में, यदि वे असफल होते हैं तो मैं उन्हें संभालने के लिए सजावटी कार्य कर रहा हूं इसलिए मेरे पास कार्य है। –

1

मुझे लगता है कि भी जरूरत खुद के लिए लग रही है। यह मेरा समाधान है। गैर तेजी से पथ ज्यादातर मामलों आप शायद में रुचि रखते हैं को शामिल किया गया।

def iterGlobalsUsedInFunc(f, fast=False, loadsOnly=True): 
    if hasattr(f, "func_code"): code = f.func_code 
    else: code = f 
    if fast: 
     # co_names is the list of all names which are used. 
     # These are mostly the globals. These are also attrib names, so these are more... 
     for name in code.co_names: 
      yield name 
    else: 
     # Use the disassembly. Note that this will still not 
     # find dynamic lookups to `globals()` 
     # (which is anyway not possible to detect always). 
     import dis 
     ops = ["LOAD_GLOBAL"] 
     if not loadsOnly: 
      ops += ["STORE_GLOBAL", "DELETE_GLOBAL"] 
     ops = map(dis.opmap.__getitem__, ops) 
     i = 0 
     while i < len(code.co_code): 
      op = ord(code.co_code[i]) 
      i += 1 
      if op >= dis.HAVE_ARGUMENT: 
       oparg = ord(code.co_code[i]) + ord(code.co_code[i+1])*256 
       i += 2 
      else: 
       oparg = None 
      if op in ops: 
       name = code.co_names[oparg] 
       yield name 

    # iterate through sub code objects 
    import types 
    for subcode in code.co_consts: 
     if isinstance(subcode, types.CodeType): 
      for g in iterGlobalsUsedInFunc(subcode, fast=fast, loadsOnly=loadsOnly): 
       yield g 

एक अद्यतन संस्करण here हो सकता है।


मेरे उपयोग के मामले:

मैं कुछ मॉड्यूल (songdb) जो कुछ वैश्विक डाटाबेस वस्तुओं है है और मैं एक बार मैं एक समारोह जो वैश्विक डेटाबेस चर का उपयोग करता है कहा जाता है lazily उन्हें लोड करना चाहता था। मैं आलसी लोडर के साथ ऐसे कार्यों को मैन्युअल रूप से सजा सकता था या मैं स्वचालित रूप से पता लगा सकता हूं कि मेरे iterGlobalsUsedInFunc फ़ंक्शन द्वारा कौन से फ़ंक्शंस की आवश्यकता है।

यह मूलतः कोड है,, (full code वास्तव में अब कक्षाओं के लिए बढ़ा दिया गया था) जहां init स्वचालित रूप से इस तरह के कार्यों से सजाया गया:

DBs = { 
    "songDb": "songs.db", 
    "songHashDb": "songHashs.db", 
    "songSearchIndexDb": "songSearchIndex.db", 
    } 
for db in DBs.keys(): globals()[db] = None 

def usedDbsInFunc(f): 
    dbs = [] 
    for name in utils.iterGlobalsUsedInFunc(f, loadsOnly=True): 
     if name in DBs: 
      dbs += [name] 
    return dbs 

def init(): 
    import types 
    for fname in globals().keys(): 
     f = globals()[fname] 
     if not isinstance(f, types.FunctionType): continue 
     dbs = usedDbsInFunc(f) 
     if not dbs: continue 
     globals()[fname] = lazyInitDb(*dbs)(f) 

def initDb(db): 
    if not globals()[db]: 
     globals()[db] = DB(DBs[db]) 

def lazyInitDb(*dbs): 
    def decorator(f): 
     def decorated(*args, **kwargs): 
      for db in dbs: 
       initDb(db) 
      return f(*args, **kwargs) 
     return decorated 
    return decorator 

एक अन्य समाधान एक वस्तु प्रॉक्सी जो lazily डेटाबेस लोड करता है उपयोग करने के लिए हो गया होता। मैंने इस परियोजना में कहीं और इस्तेमाल किया है, इस प्रकार मैंने इस ऑब्जेक्ट प्रॉक्सी को भी लागू किया है; यदि आप रुचि रखते हैं, तो यहां देखें: utils.py: ObjectProxy

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