पाइथन के ast मॉड्यूल की शक्ति को एब्स्ट्रैक्ट सिंटैक्स ट्री मैनिपुलेशन के लिए जानें। प्रोग्राम के अनुसार पाइथन कोड का विश्लेषण, संशोधन और जनरेट करना सीखें।
पाइथन Ast मॉड्यूल: एब्स्ट्रैक्ट सिंटैक्स ट्री मैनिपुलेशन डिमिस्टिफाइड
पाइथन ast
मॉड्यूल पाइथन कोड के एब्स्ट्रैक्ट सिंटैक्स ट्री (AST) के साथ इंटरैक्ट करने का एक शक्तिशाली तरीका प्रदान करता है। एक एएसटी स्रोत कोड की सिंटैक्टिक संरचना का एक ट्री प्रतिनिधित्व है, जो प्रोग्राम के अनुसार पाइथन कोड का विश्लेषण, संशोधन और यहां तक कि जनरेट करना संभव बनाता है। यह कोड विश्लेषण उपकरण, स्वचालित रीफैक्टरिंग, स्टैटिक विश्लेषण और यहां तक कि कस्टम भाषा एक्सटेंशन सहित विभिन्न अनुप्रयोगों के लिए द्वार खोलता है। यह लेख आपको ast
मॉड्यूल की मूलभूत बातें बताएगा, इसके क्षमताओं में व्यावहारिक उदाहरण और अंतर्दृष्टि प्रदान करेगा।
एब्स्ट्रैक्ट सिंटैक्स ट्री (AST) क्या है?
ast
मॉड्यूल में गोता लगाने से पहले, आइए समझते हैं कि एब्स्ट्रैक्ट सिंटैक्स ट्री क्या है। जब एक पाइथन इंटरप्रेटर आपके कोड को निष्पादित करता है, तो पहला कदम कोड को एक AST में पार्स करना होता है। यह ट्री संरचना कोड के सिंटैक्टिक तत्वों, जैसे कि फ़ंक्शन, कक्षाएं, लूप, एक्सप्रेशन और ऑपरेटरों को उनके संबंधों के साथ दर्शाती है। AST अप्रासंगिक विवरणों जैसे कि व्हाइटस्पेस और टिप्पणियों को त्याग देता है, जो आवश्यक संरचनात्मक जानकारी पर ध्यान केंद्रित करता है। इस तरह से कोड का प्रतिनिधित्व करके, कार्यक्रमों के लिए कोड का विश्लेषण और हेरफेर करना संभव हो जाता है, जो बहुत सी स्थितियों में बेहद उपयोगी है।
ast
मॉड्यूल के साथ शुरुआत करना
ast
मॉड्यूल पाइथन के मानक पुस्तकालय का हिस्सा है, इसलिए आपको कोई अतिरिक्त पैकेज स्थापित करने की आवश्यकता नहीं है। इसका उपयोग शुरू करने के लिए बस इसे आयात करें:
import ast
ast
मॉड्यूल का मुख्य कार्य ast.parse()
है, जो पाइथन कोड की एक स्ट्रिंग को इनपुट के रूप में लेता है और एक AST ऑब्जेक्ट लौटाता है।
code = """
def add(x, y):
return x + y
"""
ast_tree = ast.parse(code)
print(ast_tree)
यह कुछ इस तरह आउटपुट करेगा: <_ast.Module object at 0x...>
। जबकि यह आउटपुट विशेष रूप से जानकारीपूर्ण नहीं है, यह इंगित करता है कि कोड को सफलतापूर्वक एक AST में पार्स किया गया था। ast_tree
ऑब्जेक्ट में अब पार्स किए गए कोड की पूरी संरचना है।
AST की खोज
AST की संरचना को समझने के लिए, हम ast.dump()
फ़ंक्शन का उपयोग कर सकते हैं। यह फ़ंक्शन रिकर्सिव रूप से ट्री को पार करता है और प्रत्येक नोड का विस्तृत प्रतिनिधित्व प्रिंट करता है।
code = """
def add(x, y):
return x + y
"""
ast_tree = ast.parse(code)
print(ast.dump(ast_tree, indent=4))
आउटपुट होगा:
Module(
body=[
FunctionDef(
name='add',
args=arguments(
posonlyargs=[],
args=[
arg(arg='x', annotation=None, type_comment=None),
arg(arg='y', annotation=None, type_comment=None)
],
kwonlyargs=[],
kw_defaults=[],
defaults=[]
),
body=[
Return(
value=BinOp(
left=Name(id='x', ctx=Load()),
op=Add(),
right=Name(id='y', ctx=Load())
)
)
],
decorator_list=[],
returns=None,
type_comment=None
)
],
type_ignores=[]
)
यह आउटपुट कोड की पदानुक्रमित संरचना को दर्शाता है। आइए इसे तोड़ते हैं:
Module
: पूरे मॉड्यूल का प्रतिनिधित्व करने वाला रूट नोड।body
: मॉड्यूल के भीतर कथनों की एक सूची।FunctionDef
: एक फ़ंक्शन परिभाषा का प्रतिनिधित्व करता है। इसके विशेषताओं में शामिल हैं:name
: फ़ंक्शन का नाम ('add')।args
: फ़ंक्शन के तर्क।arguments
: फ़ंक्शन के तर्कों के बारे में जानकारी शामिल है।arg
: एक एकल तर्क का प्रतिनिधित्व करता है (जैसे, 'x', 'y')।body
: फ़ंक्शन का मुख्य भाग (कथनों की एक सूची)।Return
: एक रिटर्न स्टेटमेंट का प्रतिनिधित्व करता है।value
: वापस किया जा रहा मान।BinOp
: एक बाइनरी ऑपरेशन का प्रतिनिधित्व करता है (जैसे, x + y)।left
: बायाँ ऑपरेंड (जैसे, 'x')।op
: ऑपरेटर (जैसे, 'Add')।right
: दायाँ ऑपरेंड (जैसे, 'y')।
AST को ट्रैवर्स करना
ast
मॉड्यूल AST को ट्रैवर्स करने के लिए ast.NodeVisitor
क्लास प्रदान करता है। ast.NodeVisitor
को सबक्लास करके और इसके तरीकों को ओवरराइड करके, आप विशिष्ट नोड प्रकारों को प्रोसेस कर सकते हैं क्योंकि वे ट्रैवर्सल के दौरान सामना करते हैं। यह कोड संरचना का विश्लेषण करने, विशिष्ट पैटर्न की पहचान करने या जानकारी निकालने के लिए उपयोगी है।
import ast
class FunctionNameExtractor(ast.NodeVisitor):
def __init__(self):
self.function_names = []
def visit_FunctionDef(self, node):
self.function_names.append(node.name)
code = """
def add(x, y):
return x + y
def subtract(x, y):
return x - y
"""
ast_tree = ast.parse(code)
extractor = FunctionNameExtractor()
extractor.visit(ast_tree)
print(extractor.function_names) # Output: ['add', 'subtract']
इस उदाहरण में, FunctionNameExtractor
ast.NodeVisitor
से इनहेरिट होता है और visit_FunctionDef
विधि को ओवरराइड करता है। इस विधि को AST में प्रत्येक फ़ंक्शन परिभाषा नोड के लिए कहा जाता है। विधि function_names
सूची में फ़ंक्शन नाम जोड़ती है। visit()
विधि AST के ट्रैवर्सल को आरंभ करती है।
उदाहरण: सभी चर असाइनमेंट खोजना
import ast
class VariableAssignmentFinder(ast.NodeVisitor):
def __init__(self):
self.assignments = []
def visit_Assign(self, node):
for target in node.targets:
if isinstance(target, ast.Name):
self.assignments.append(target.id)
code = """
x = 10
y = x + 5
message = "hello"
"""
ast_tree = ast.parse(code)
finder = VariableAssignmentFinder()
finder.visit(ast_tree)
print(finder.assignments) # Output: ['x', 'y', 'message']
यह उदाहरण कोड में सभी चर असाइनमेंट ढूंढता है। visit_Assign
विधि को प्रत्येक असाइनमेंट स्टेटमेंट के लिए कहा जाता है। यह असाइनमेंट के लक्ष्यों के माध्यम से पुनरावृति करता है और, यदि कोई लक्ष्य एक सरल नाम (ast.Name
) है, तो यह नाम को assignments
सूची में जोड़ता है।
AST को संशोधित करना
ast
मॉड्यूल आपको AST को संशोधित करने की भी अनुमति देता है। आप मौजूदा नोड्स को बदल सकते हैं, नए नोड्स जोड़ सकते हैं या नोड्स को पूरी तरह से हटा सकते हैं। AST को संशोधित करने के लिए, आप ast.NodeTransformer
क्लास का उपयोग करते हैं। ast.NodeVisitor
के समान, आप विशिष्ट नोड प्रकारों को संशोधित करने के लिए ast.NodeTransformer
को सबक्लास करते हैं और इसके तरीकों को ओवरराइड करते हैं। मुख्य अंतर यह है कि ast.NodeTransformer
विधियों को संशोधित नोड (या इसे बदलने के लिए एक नया नोड) वापस करना चाहिए। यदि कोई विधि None
लौटाती है, तो नोड को AST से हटा दिया जाता है।
AST को संशोधित करने के बाद, आपको compile()
फ़ंक्शन का उपयोग करके इसे वापस निष्पादन योग्य पाइथन कोड में संकलित करने की आवश्यकता है।
import ast
class AddOneTransformer(ast.NodeTransformer):
def visit_Num(self, node):
return ast.Num(n=node.n + 1)
code = """
x = 10
y = 20
"""
ast_tree = ast.parse(code)
transformer = AddOneTransformer()
new_ast_tree = transformer.visit(ast_tree)
new_code = compile(new_ast_tree, '', 'exec')
# Execute the modified code
exec(new_code)
print(x) # Output: 11
print(y) # Output: 21
इस उदाहरण में, AddOneTransformer
ast.NodeTransformer
से इनहेरिट होता है और visit_Num
विधि को ओवरराइड करता है। इस विधि को प्रत्येक संख्यात्मक शाब्दिक नोड (ast.Num
) के लिए कहा जाता है। विधि 1 से वृद्धिशील मान के साथ एक नया ast.Num
नोड बनाती है। visit()
विधि संशोधित AST लौटाती है।
compile()
फ़ंक्शन संशोधित AST, एक फ़ाइल नाम (<string>
इस मामले में, यह दर्शाता है कि कोड एक स्ट्रिंग से आता है) और एक निष्पादन मोड (कोड के एक ब्लॉक को निष्पादित करने के लिए 'exec'
) लेता है। यह एक कोड ऑब्जेक्ट लौटाता है जिसे exec()
फ़ंक्शन का उपयोग करके निष्पादित किया जा सकता है।
उदाहरण: एक चर नाम बदलना
import ast
class VariableNameReplacer(ast.NodeTransformer):
def __init__(self, old_name, new_name):
self.old_name = old_name
self.new_name = new_name
def visit_Name(self, node):
if node.id == self.old_name:
return ast.Name(id=self.new_name, ctx=node.ctx)
return node
code = """
def multiply_by_two(number):
return number * 2
result = multiply_by_two(5)
print(result)
"""
ast_tree = ast.parse(code)
replacer = VariableNameReplacer('number', 'num')
new_ast_tree = replacer.visit(ast_tree)
new_code = compile(new_ast_tree, '', 'exec')
# Execute the modified code
exec(new_code)
यह उदाहरण चर नाम 'number'
के सभी उदाहरणों को 'num'
से बदलता है। VariableNameReplacer
पुराने और नए नामों को तर्कों के रूप में लेता है। visit_Name
विधि को प्रत्येक नाम नोड के लिए कहा जाता है। यदि नोड का पहचानकर्ता पुराने नाम से मेल खाता है, तो यह नए नाम और समान संदर्भ (node.ctx
) के साथ एक नया ast.Name
नोड बनाता है। संदर्भ इंगित करता है कि नाम का उपयोग कैसे किया जा रहा है (उदाहरण के लिए, लोडिंग, स्टोरिंग)।
AST से कोड जनरेट करना
जबकि compile()
आपको एक AST से कोड निष्पादित करने की अनुमति देता है, यह कोड को एक स्ट्रिंग के रूप में प्राप्त करने का कोई तरीका प्रदान नहीं करता है। एक AST से पाइथन कोड जनरेट करने के लिए, आप astunparse
लाइब्रेरी का उपयोग कर सकते हैं। यह लाइब्रेरी मानक लाइब्रेरी का हिस्सा नहीं है, इसलिए आपको इसे पहले स्थापित करने की आवश्यकता है:
pip install astunparse
फिर, आप एक AST से कोड जनरेट करने के लिए astunparse.unparse()
फ़ंक्शन का उपयोग कर सकते हैं।
import ast
import astunparse
code = """
def add(x, y):
return x + y
"""
ast_tree = ast.parse(code)
generated_code = astunparse.unparse(ast_tree)
print(generated_code)
आउटपुट होगा:
def add(x, y):
return (x + y)
नोट: (x + y)
के चारों ओर कोष्ठक astunparse
द्वारा सही ऑपरेटर पूर्वता सुनिश्चित करने के लिए जोड़े जाते हैं। ये कोष्ठक सख्ती से आवश्यक नहीं हो सकते हैं, लेकिन वे कोड की शुद्धता की गारंटी देते हैं।
उदाहरण: एक सरल क्लास जनरेट करना
import ast
import astunparse
class_name = 'MyClass'
method_name = 'my_method'
# Create the class definition node
class_def = ast.ClassDef(
name=class_name,
bases=[],
keywords=[],
body=[
ast.FunctionDef(
name=method_name,
args=ast.arguments(
posonlyargs=[],
args=[],
kwonlyargs=[],
kw_defaults=[],
defaults=[]
),
body=[
ast.Pass()
],
decorator_list=[],
returns=None,
type_comment=None
)
],
decorator_list=[]
)
# Create the module node containing the class definition
module = ast.Module(body=[class_def], type_ignores=[])
# Generate the code
code = astunparse.unparse(module)
print(code)
यह उदाहरण निम्नलिखित पाइथन कोड जनरेट करता है:
class MyClass:
def my_method():
pass
यह दर्शाता है कि खरोंच से एक AST का निर्माण कैसे करें और फिर इससे कोड जनरेट करें। यह दृष्टिकोण कोड जनरेशन टूल और मेटाप्रोग्रामिंग के लिए शक्तिशाली है।
ast
मॉड्यूल के व्यावहारिक अनुप्रयोग
ast
मॉड्यूल के कई व्यावहारिक अनुप्रयोग हैं, जिनमें शामिल हैं:
- कोड विश्लेषण: शैली उल्लंघनों, सुरक्षा कमजोरियों या प्रदर्शन बाधाओं के लिए कोड का विश्लेषण करना। उदाहरण के लिए, आप एक बड़ी परियोजना में कोडिंग मानकों को लागू करने के लिए एक उपकरण लिख सकते हैं।
- स्वचालित रीफैक्टरिंग: चर का नाम बदलना, विधियों को निकालना या नए भाषा सुविधाओं का उपयोग करने के लिए कोड को परिवर्तित करने जैसे कार्यों को स्वचालित करना।
rope
जैसे उपकरण शक्तिशाली रीफैक्टरिंग क्षमताओं के लिए ASTs का लाभ उठाते हैं। - स्थिर विश्लेषण: वास्तव में इसे चलाए बिना कोड में संभावित त्रुटियों या बग की पहचान करना।
pylint
औरflake8
जैसे उपकरण समस्याओं का पता लगाने के लिए AST विश्लेषण का उपयोग करते हैं। - कोड जनरेशन: टेम्पलेट या विशिष्टताओं के आधार पर स्वचालित रूप से कोड जनरेट करना। यह दोहराव वाले कोड बनाने या विभिन्न प्लेटफार्मों के लिए कोड जनरेट करने के लिए उपयोगी है।
- भाषा एक्सटेंशन: पाइथन कोड को विभिन्न प्रतिनिधित्वों में बदलकर कस्टम भाषा एक्सटेंशन या डोमेन-विशिष्ट भाषाएं (DSLs) बनाना।
- सुरक्षा ऑडिटिंग: संभावित रूप से हानिकारक निर्माणों या कमजोरियों के लिए कोड का विश्लेषण करना। इसका उपयोग असुरक्षित कोडिंग प्रथाओं की पहचान करने के लिए किया जा सकता है।
उदाहरण: कोडिंग शैली लागू करना
मान लीजिए कि आप यह लागू करना चाहते हैं कि आपकी परियोजना में सभी फ़ंक्शन नाम snake_case कन्वेंशन का पालन करें (उदाहरण के लिए, my_function
बजाय myFunction
)। आप उल्लंघनों की जांच के लिए ast
मॉड्यूल का उपयोग कर सकते हैं।
import ast
import re
class SnakeCaseChecker(ast.NodeVisitor):
def __init__(self):
self.errors = []
def visit_FunctionDef(self, node):
if not re.match(r'^[a-z]+(_[a-z]+)*$', node.name):
self.errors.append(f"Function name '{node.name}' does not follow snake_case convention")
def check_code(self, code):
ast_tree = ast.parse(code)
self.visit(ast_tree)
return self.errors
# Example usage
code = """
def myFunction(x):
return x * 2
def calculate_area(width, height):
return width * height
"""
checker = SnakeCaseChecker()
errors = checker.check_code(code)
if errors:
for error in errors:
print(error)
else:
print("No style violations found")
यह कोड एक SnakeCaseChecker
क्लास को परिभाषित करता है जो ast.NodeVisitor
से इनहेरिट होता है। visit_FunctionDef
विधि जांचती है कि फ़ंक्शन नाम snake_case रेगुलर एक्सप्रेशन से मेल खाता है या नहीं। यदि नहीं, तो यह errors
सूची में एक त्रुटि संदेश जोड़ता है। check_code
विधि कोड को पार्स करती है, AST को ट्रैवर्स करती है और त्रुटियों की सूची लौटाती है।
ast
मॉड्यूल के साथ काम करते समय सर्वोत्तम अभ्यास
- AST संरचना को समझें: AST में हेरफेर करने का प्रयास करने से पहले,
ast.dump()
का उपयोग करके इसकी संरचना को समझने में समय निकालें। यह आपको उन नोड्स की पहचान करने में मदद करेगा जिनके साथ आपको काम करने की आवश्यकता है। ast.NodeVisitor
औरast.NodeTransformer
का उपयोग करें: ये क्लास मैन्युअल रूप से ट्री को नेविगेट किए बिना AST को ट्रैवर्स और संशोधित करने का एक सुविधाजनक तरीका प्रदान करते हैं।- पूरी तरह से परीक्षण करें: AST को संशोधित करते समय, यह सुनिश्चित करने के लिए अपने कोड का पूरी तरह से परीक्षण करें कि परिवर्तन सही हैं और कोई त्रुटि नहीं करते हैं।
- कोड जनरेशन के लिए
astunparse
पर विचार करें: जबकिcompile()
संशोधित कोड को निष्पादित करने के लिए उपयोगी है,astunparse
एक AST से पठनीय पाइथन कोड जनरेट करने का एक तरीका प्रदान करता है। - टाइप हिंट का उपयोग करें: टाइप हिंट आपके कोड की पठनीयता और रखरखाव में काफी सुधार कर सकते हैं, खासकर जब जटिल AST संरचनाओं के साथ काम करते हैं।
- अपने कोड को डॉक्यूमेंट करें: कस्टम AST विज़िटर या ट्रांसफार्मर बनाते समय, प्रत्येक विधि के उद्देश्य और AST में किए गए परिवर्तनों को समझाने के लिए अपने कोड को स्पष्ट रूप से डॉक्यूमेंट करें।
चुनौतियाँ और विचार
- जटिलता: ASTs के साथ काम करना जटिल हो सकता है, खासकर बड़े कोडबेस के लिए। विभिन्न नोड प्रकारों और उनके संबंधों को समझना चुनौतीपूर्ण हो सकता है।
- रखरखाव: AST संरचनाएं पाइथन संस्करणों के बीच बदल सकती हैं। संगतता सुनिश्चित करने के लिए विभिन्न पाइथन संस्करणों के साथ अपने कोड का परीक्षण करना सुनिश्चित करें।
- प्रदर्शन: बड़े ASTs को ट्रैवर्स और संशोधित करना धीमा हो सकता है। प्रदर्शन को बेहतर बनाने के लिए अपने कोड को अनुकूलित करने पर विचार करें। अक्सर एक्सेस किए गए नोड्स को कैश करना या अधिक कुशल एल्गोरिदम का उपयोग करने से मदद मिल सकती है।
- त्रुटि प्रबंधन: AST को पार्स करते या हेरफेर करते समय त्रुटियों को अनुग्रहपूर्वक संभालें। उपयोगकर्ता को जानकारीपूर्ण त्रुटि संदेश प्रदान करें।
- सुरक्षा: AST से उत्पन्न कोड को निष्पादित करते समय सावधान रहें, खासकर यदि AST उपयोगकर्ता इनपुट पर आधारित है। कोड इंजेक्शन हमलों को रोकने के लिए इनपुट को सैनिटाइज़ करें।
निष्कर्ष
पाइथन ast
मॉड्यूल पाइथन कोड के एब्स्ट्रैक्ट सिंटैक्स ट्री के साथ इंटरैक्ट करने का एक शक्तिशाली और लचीला तरीका प्रदान करता है। AST संरचना को समझकर और ast.NodeVisitor
और ast.NodeTransformer
क्लास का उपयोग करके, आप प्रोग्राम के अनुसार पाइथन कोड का विश्लेषण, संशोधन और जनरेट कर सकते हैं। यह कोड विश्लेषण उपकरण से लेकर स्वचालित रीफैक्टरिंग और यहां तक कि कस्टम भाषा एक्सटेंशन तक अनुप्रयोगों की एक विस्तृत श्रृंखला के लिए द्वार खोलता है। जबकि ASTs के साथ काम करना जटिल हो सकता है, प्रोग्राम के अनुसार कोड में हेरफेर करने में सक्षम होने के लाभ महत्वपूर्ण हैं। अपनी पाइथन परियोजनाओं में नई संभावनाओं को अनलॉक करने के लिए ast
मॉड्यूल की शक्ति को अपनाएं।