نحوه استفاده از مولدهای پایتون – با مثال های کد توضیح داده شده است


مولدهای پایتون یک ویژگی قدرتمند هستند که امکان تکرار تنبل را از طریق یک سری مقادیر فراهم میکنند.
آنها آیتمها را در یک زمان و تنها در صورت نیاز تولید میکنند، که آنها را به بهترین انتخاب برای کار با مجموعههای داده یا جریانهای داده بزرگ تبدیل میکند که در آن بارگذاری همه چیز به یکباره در حافظه ناکارآمد و غیرعملی است.
نحوه تعریف و استفاده از ژنراتورها
برای تعریف یک ژنراتور، می توانید از کلمه کلیدی def
مانند یک تابع معمولی استفاده کنید. با این حال، به جای برگرداندن مقداری با return
، از yield
استفاده می کنیم.
در اینجا از کلمه کلیدی yield
برای تولید مقدار و توقف اجرای تابع مولد استفاده می شود. هنگامی که تابع از سر گرفته می شود، بلافاصله پس از بیانیه yield
به اجرای آن ادامه می دهد.
مثال: ژنراتور ساده
در اینجا یک مولد ساده است که n
عدد اول را به دست می دهد:
def simple_generator(n): i = 0 while i < n: yield i i += 1 # Using the generator gen = simple_generator(5) for number in gen: print(number)
خروجی:
0 1 2 3 4
وقتی تابع simple_generator()
فراخوانی می شود، کد خود را اجرا نمی کند. در عوض، یک شی مولد را برمی گرداند که حاوی یک متد داخلی به نام __next__()
است که با فراخوانی تابع مولد ایجاد می شود.
شی مولد به طور ضمنی از این روش به عنوان یک پروتکل تکرار کننده استفاده می کند وقتی که ما روی مولد تکرار می کنیم.
مزایای استفاده از ژنراتورها
مولدهای پایتون چندین مزیت را ارائه می دهند که کارایی و خوانایی کد را به طور قابل توجهی افزایش می دهد. ژنراتورها با تولید کارآمد آیتمها در حین پرواز، استفاده از حافظه را بهینه میکنند و عملکرد را در مقایسه با روشهای تکرارشونده سنتی افزایش میدهند.
بیایید برخی از این مزایا را با جزئیات تحلیل کنیم و نشان دهیم که چگونه ژنراتورها توسعه پایتون را ساده می کنند و کیفیت کد را بهبود می بخشند.
بهینه سازی حافظه
در مقایسه با فهرست هایی که همه عناصر را به یکباره در حافظه بارگذاری می کنند، ژنراتورها بهینه ساز مصرف حافظه هستند. آنها اقلام را یک به یک و فقط در صورت لزوم تولید می کنند.
در اینجا یک مثال است که سناریویی را در نظر می گیرد که در آن باید فهرست بزرگی از اعداد تولید کنیم:
# Using a list numbers = [i for i in range(1000000)] # Using a generator def number_generator(): for i in range(1000000): yield i gen_numbers = number_generator()
با فهرست ، همه 1000000 شماره به طور همزمان در حافظه ذخیره می شوند، اما با مولد، اعداد یک به یک تولید می شوند و مصرف حافظه را کاهش می دهند.
عملکرد پیشرفته
از آنجایی که ژنراتورها در حین پرواز اقلام تولید می کنند، عملکرد را به ویژه از نظر سرعت و کارایی افزایش می دهند. آنها میتوانند بلافاصله بدون انتظار برای پردازش کل مجموعه داده، نتایج را به دست آورند.
در این مثال، فرض می کنیم که باید هر عدد را در یک دنباله پردازش کنیم:
# Using a list numbers = [i for i in range(1000000)] squared_numbers = [x**2 for x in numbers] # Using a generator def number_generator(): for i in range(1000000): yield i def squared_gen(gen): for num in gen: yield num**2 gen_numbers = number_generator() squared_gen_numbers = squared_gen(gen_numbers)
وقتی از فهرست استفاده می کنیم، همه اعداد را تولید کرده و سپس آنها را پردازش می کنیم که زمان بیشتری می برد. با این حال، با ژنراتور، هر عدد به محض تولید پردازش میشود و این فرآیند را کارآمدتر میکند.
سادگی و خوانایی کد
ژنراتورها در نوشتن کدهای تمیز و خوانا کمک می کنند. آنها به ما اجازه می دهند تا یک الگوریتم تکرار شونده را به روشی ساده، بدون نیاز به کد دیگ بخار برای مدیریت وضعیت تکرار تعریف کنیم. بیایید سناریویی را در نظر بگیریم که در آن باید خطوطی را از یک فایل بزرگ بخوانیم:
# Using a list def read_large_file(file_name): with open(file_name, 'r') as file: lines = file.readlines() return lines lines = read_large_file('large_file.txt') # Using a generator def read_large_file(file_name): with open(file_name, 'r') as file: for line in file: yield line lines_gen = read_large_file('large_file.txt')
با رویکرد فهرست ، همه خطوط را به یکباره در حافظه می خوانیم. با ژنراتور، ما هر بار یک خط را میخوانیم و میآوریم، که باعث میشود کد سادهتر و خواناتر شود و در عین حال به صرفهجویی در حافظه کمک میکند.
موارد استفاده عملی
این بخش برخی از موارد کاربرد عملی را تحلیل میکند که در آن ژنراتورهای پایتون برتری مییابند، و کشف میکند که چگونه ژنراتورها وظایف پیچیده را در عین بهینهسازی عملکرد و استفاده از حافظه ساده میکنند.
پردازش جریان
ژنراتورها در مدیریت جریانهای مداوم دادهها، مانند دادههای حسگر بیدرنگ، جریانهای گزارش یا فیدهای زنده از APIها عالی هستند. آنها بدون نیاز به ذخیره مقادیر زیادی داده در حافظه، پردازش کارآمد داده را به محض در دسترس بودن فراهم می کنند.
import time def data_stream(): """Simulate a data stream.""" for i in range(10): time.sleep(1) # Simulate data arriving every second yield 1 def stream_processor(data_stream): """Process data from the stream.""" for data in data_stream: processed_data = data * 2 # Example processing step yield processed_data # Usage stream = data_stream() processed_stream = stream_processor(stream) for data in processed_stream: print(data)
در این مثال، متد data_stream()
دادهها را در فواصل زمانی تولید میکند و یک جریان داده پیوسته را شبیهسازی میکند. stream_processor()
هر قطعه داده را هنگام رسیدن پردازش می کند و نشان می دهد که چگونه مولدها می توانند داده های جریانی را بدون نیاز به بارگذاری همه داده ها در یک بار در حافظه به طور موثر اداره کنند.
الگوریتم های تکراری
ژنراتورها روشی ساده برای تعریف و اجرای الگوریتمهای تکراری که شامل محاسبات و شبیهسازیهای تکراری هستند، ارائه میکنند. آنها به ما اجازه می دهند تا وضعیت تکرار را بدون مدیریت دستی متغیرهای حلقه حفظ کنیم، که می تواند وضوح کد و قابلیت نگهداری را افزایش دهد.
def fibonacci_generator(): a, b = 0, 1 while True: yield a a, b = b, a + b # Usage fib_gen = fibonacci_generator() for i in range(10): print(next(fib_gen))
در مثال بالا، متد fibonacci_generator()
ژنراتوری را تعریف می کند که اعداد فیبوناچی را به طور نامحدود تولید می کند. هر فیبوناچی شماره یک را در یک زمان برمی گرداند که از 0 و 1 شروع می شود.
در اینجا، حلقه for
10 بار تکرار میشود تا 10 عدد اول فیبوناچی را چاپ کند، و نشان میدهد که چگونه ژنراتورها میتوانند به طور موثر توالیها را بدون بارگذاری از قبل در حافظه تولید و مدیریت کنند.
شبیه ساز بلادرنگ
در این مثال، بهروزرسانیهای بیدرنگ قیمت سهام را شبیهسازی میکنیم. ژنراتور در هر مرحله قیمت سهام جدیدی را بر اساس قیمت قبلی و برخی نوسانات تصادفی تولید می کند.
import random import time def stock_price_generator(initial_price, volatility, steps): """Generates stock prices starting from initial_price with given volatility.""" price = initial_price for _ in range(steps): # Simulate price change change_percent = random.uniform(-volatility, volatility) price += price * change_percent yield price time.sleep(1) # Simulate real-time delay # Create the stock price generator initial_price = 100.0 # Starting stock price volatility = 0.02 # Volatility as a percentage steps = 10 # Number of steps (updates) to simulate stock_prices = stock_price_generator(initial_price, volatility, steps) # Simulate recieving and processing real-time stock prices for price in stock_prices: print(f"New stock price: {price:.2f}")
این مثال قیمت هر سهام را در لحظه بر اساس قیمت قبلی تولید می کند و تمام قیمت های تولید شده را در حافظه ذخیره نمی کند و برای شبیه سازی های طولانی مدت کارآمد است.
مولد یک قیمت سهام جدید را در هر مرحله با حداقل محاسبات ارائه می دهد. time.sleep(1)
یک تاخیر بلادرنگ را شبیه سازی می کند و به سیستم اجازه می دهد تا در صورت نیاز سایر وظایف را همزمان انجام دهد.
خلاصه
به طور خلاصه، ژنراتورهای پایتون مدیریت کارآمد حافظه و عملکرد بهبود یافته را ارائه میدهند، کد را ساده میکنند و در عین حال با وظایف مختلفی مانند پردازش جریان، الگوریتمهای تکراری و شبیهسازی بلادرنگ مقابله میکنند.
توانایی آنها در بهینه سازی منابع، آنها را به ابزاری ارزشمند برای توسعه دهندگان پایتون مدرن که به دنبال راه حل های ظریف و مقیاس پذیر هستند تبدیل می کند.
امیدواریم، این کاوش در ژنراتورهای پایتون، بینش های مورد نیاز برای استفاده از پتانسیل کامل آنها را در اختیار شما قرار دهد. اگر سوالی دارید یا می خواهید بیشتر بحث کنید، در لینکدین با من تماس بگیرید. علاوه بر این، میتوانید در کانال یوتیوب من مشترک شوید، جایی که من ویدیوهای مربوط به تکنیکهای کدنویسی و پروژههایی را که روی آنها کار میکنم به اشتراک میگذارم.
ارسال نظر