2016-12-22 8 views
6

में एक पायथन फ़ंक्शन या चर के सभी उपयोगों को कैसे ढूंढें I फ़ंक्शन स्तर पर एक पायथन पैकेज में फ़ंक्शंस और चर के उपयोग/कारणों को मैप करने का प्रयास कर रहा हूं। वहाँ कई मॉड्यूल जहां कार्य/चर अन्य कार्यों में इस्तेमाल किया जाता है, और मैं एक शब्दकोश है कि तरह दिखता है बनाना चाहते हैं:एक पायथन पैकेज

{'function_name':{'uses': [...functions used in this function...], 
        'causes': [...functions that use this function...]}, 
... 
} 

कार्यों है कि मैं के मॉड्यूल में परिभाषित करने की आवश्यकता की बात कर रहा हूँ पैकेज।

मैं इस पर कैसे शुरू करूं? मुझे पता है कि मैं ऐसा करके पैकेज __dict__ और पैकेज में परिभाषित कार्यों के लिए परीक्षा के माध्यम से पुनरावृति कर सकते हैं:

import package 

import inspect 
import types 

for name, obj in vars(package).items(): 
    if isinstance(obj, types.FunctionType): 
     module, *_ = inspect.getmodule(obj).__name__.split('.') 
     if module == package.__name__: 
      # Now that function is obtained need to find usages or functions used within it 

लेकिन उस के बाद मैं वर्तमान समारोह के भीतर इस्तेमाल कार्यों खोजने की जरूरत है। यह कैसे किया जा सकता है? क्या इस तरह के काम के लिए कुछ पहले से विकसित हुआ है? मुझे लगता है कि प्रोफाइलिंग पुस्तकालयों को ऐसा कुछ करना पड़ सकता है।

+1

यह जांचें https://docs.python.org/2/library/ast.html –

+0

अब तक वादा करता है। जाहिर है ये "गायब" 'ast' दस्तावेज़ हैं: https://greentreesnakes.readthedocs.io/en/latest/index.html – pbreach

+0

@Ni। इस मॉड्यूल का सुझाव देने के लिए धन्यवाद। मैंने वास्तव में काम करने वाले कुछ को लागू करना समाप्त कर दिया। – pbreach

उत्तर

0

ast मॉड्यूल टिप्पणियों में सुझाए गए अनुसार अच्छी तरह से काम कर रहा है। यहां एक वर्ग है जिसे मैंने बनाया है जिसका उपयोग प्रत्येक फ़ंक्शन में उपयोग किए गए पैकेज में परिभाषित कार्यों या चर को निकालने के लिए किया जाता है।

import package 

cb = CausalBuilder(package) 
print(cb.build()) 

कौन बाहर एक शब्दकोश कुंजियों का सेट युक्त प्रिंट होगा:

import ast 
import types 
import inspect 


class CausalBuilder(ast.NodeVisitor): 

    def __init__(self, package): 
     self.forest = [] 
     self.fnames = [] 

     for name, obj in vars(package).items(): 
      if isinstance(obj, types.ModuleType): 
       with open(obj.__file__) as f: 
        text = f.read() 
       tree = ast.parse(text) 
       self.forest.append(tree) 
      elif isinstance(obj, types.FunctionType): 
       mod, *_ = inspect.getmodule(obj).__name__.split('.') 
       if mod == package.__name__: 
        self.fnames.append(name) 

     self.causes = {n: [] for n in self.fnames} 

    def build(self): 
     for tree in self.forest: 
      self.visit(tree) 
     return self.causes 

    def visit_FunctionDef(self, node): 
     self.generic_visit(node) 
     for b in node.body: 
      if node.name in self.fnames: 
       self.causes[node.name] += self.extract_cause(b) 

    def extract_cause(self, node): 
     nodes = [node] 
     cause = [] 
     while nodes: 
      for i, n in enumerate(nodes): 
       ntype = type(n) 
       if ntype == ast.Name: 
        if n.id in self.fnames: 
         cause.append(n.id) 
       elif ntype in (ast.Assign, ast.AugAssign, ast.Attribute, 
           ast.Subscript, ast.Return): 
        nodes.append(n.value) 
       elif ntype in (ast.If, ast.IfExp): 
        nodes.append(n.test) 
        nodes.extend(n.body) 
        nodes.extend(n.orelse) 
       elif ntype == ast.Compare: 
        nodes.append(n.left) 
        nodes.extend(n.comparators) 
       elif ntype == ast.Call: 
        nodes.append(n.func) 
       elif ntype == ast.BinOp: 
        nodes.append(n.left) 
        nodes.append(n.right) 
       elif ntype == ast.UnaryOp: 
        nodes.append(n.operand) 
       elif ntype == ast.BoolOp: 
        nodes.extend(n.values) 
       elif ntype == ast.Num: 
        pass 
       else: 
        raise TypeError("Node type `{}` not accounted for." 
            .format(ntype)) 

       nodes.pop(nodes.index(n)) 

     return cause 

वर्ग पहले एक अजगर पैकेज आयात और निर्माता को पारित करने के लिए, तो बुला build विधि इतनी तरह से इस्तेमाल किया जा सकता फ़ंक्शन के नाम का प्रतिनिधित्व करना, और मान जो सूचियां हैं फ़ंक्शन में उपयोग किए जाने वाले फ़ंक्शंस और वेरिएबल्स को इंगित करते हैं। हर अस्थिर प्रकार के लिए जिम्मेदार नहीं है, लेकिन यह मेरे मामले में काफी अच्छा था।

कार्यान्वयन ast.Name तक पहुंचने तक कार्यान्वयन को सरल प्रकारों में तब तक तोड़ देता है जिसके बाद यह लक्ष्य फ़ंक्शन के भीतर उपयोग किए जा रहे चर, फ़ंक्शन या विधि का नाम निकाल सकता है।

+0

अब के लिए अपना स्वयं का जवाब स्वीकार कर रहा है क्योंकि टिप्पणियों में सुझाए गए 'अस्थ' मॉड्यूल का उपयोग करके मेरी समस्या हल हो गई है। कोई अन्य जवाब या सलाह की सराहना की जाती है। – pbreach

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