ಪೈಥಾನ್ ಜನರೇಟರ್ಸ್ ಮತ್ತು ಇಟರೇಟರ್ಸ್: ಸಂದರ್ಶನ ಪ್ರಶ್ನೆಗಳು
1. ಇಟರೇಟರ್ (Iterator) ಮತ್ತು ಇಟರೇಬಲ್ (Iterable) ನಡುವಿನ ವ್ಯತ್ಯಾಸವೇನು?
ಉತ್ತರ:
-
ಇಟರೇಬಲ್ (Iterable):
- ಇದು
forಲೂಪ್ನಲ್ಲಿ ಬಳಸಬಹುದಾದ ಯಾವುದೇ ಆಬ್ಜೆಕ್ಟ್. - ಇದರ ಮೇಲೆ
iter()ಫಂಕ್ಷನ್ ಅನ್ನು ಅನ್ವಯಿಸಿ ಇಟರೇಟರ್ ಅನ್ನು ಪಡೆಯಬಹುದು. - ಉದಾಹರಣೆ: ಲಿಸ್ಟ್ (List), ಟಪಲ್ (Tuple), ಸ್ಟ್ರಿಂಗ್ (String), ಡಿಕ್ಷನರಿ (Dictionary).
- ಇದು
-
ಇಟರೇಟರ್ (Iterator):
- ಇದು
__next__()ಮೆಥಡ್ ಅನ್ನು ಹೊಂದಿರುವ ಆಬ್ಜೆಕ್ಟ್. - ಪ್ರತಿ ಬಾರಿ
next()ಫಂಕ್ಷನ್ ಅನ್ನು ಕಾಲ್ ಮಾಡಿದಾಗ, ಇದು ಸೀಕ್ವೆನ್ಸ್ನ ಮುಂದಿನ ಐಟಂ ಅನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. - ಎಲ್ಲಾ ಐಟಂಗಳು ಮುಗಿದಾಗ,
StopIterationಎಕ್ಸೆಪ್ಶನ್ ಅನ್ನು ರೈಸ್ ಮಾಡುತ್ತದೆ. - ಪ್ರಮುಖ: ಪ್ರತಿಯೊಂದು ಇಟರೇಟರ್ ಕೂಡ ಒಂದು ಇಟರೇಬಲ್, ಆದರೆ ಪ್ರತಿಯೊಂದು ಇಟರೇಬಲ್ ಇಟರೇಟರ್ ಅಲ್ಲ.
- ಇದು
ಉದಾಹರಣೆ:
my_list = [1, 2, 3] # ಇದು ಇಟರೇಬಲ್
my_iterator = iter(my_list) # ಇದು ಇಟರೇಟರ್
print(next(my_iterator)) # 1
print(next(my_iterator)) # 2
print(next(my_iterator)) # 3
# print(next(my_iterator)) # StopIteration
2. ಜನರೇಟರ್ (Generator) ಎಂದರೇನು?
ಉತ್ತರ:
ಜನರೇಟರ್ ಎನ್ನುವುದು ಇಟರೇಟರ್ಗಳನ್ನು ರಚಿಸಲು ಒಂದು ಸರಳ ಮತ್ತು ಮೆಮೊರಿ-ಸಮರ್ಥ ವಿಧಾನ. ಇದು ಒಂದು ವಿಶೇಷ ರೀತಿಯ ಫಂಕ್ಷನ್ ಆಗಿದ್ದು,
return ಬದಲಿಗೆ yield ಕೀವರ್ಡ್ ಅನ್ನು ಬಳಸುತ್ತದೆ.
yieldಕೀವರ್ಡ್ ಅನ್ನು ತಲುಪಿದಾಗ, ಫಂಕ್ಷನ್ ತನ್ನ ಸ್ಟೇಟ್ ಅನ್ನು ಉಳಿಸಿಕೊಂಡು, ಮೌಲ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ ಮತ್ತು ಪಾಸ್ ಆಗುತ್ತದೆ.- ಮುಂದಿನ ಬಾರಿ
next()ಅನ್ನು ಕಾಲ್ ಮಾಡಿದಾಗ, ಅದು ನಿಲ್ಲಿಸಿದ ಸ್ಥಳದಿಂದಲೇ ಮುಂದುವರಿಯುತ್ತದೆ. - ಇದು ಒಂದೇ ಬಾರಿಗೆ ಎಲ್ಲಾ ಮೌಲ್ಯಗಳನ್ನು ಮೆಮೊರಿಯಲ್ಲಿ ಸಂಗ್ರಹಿಸುವುದಿಲ್ಲ, ಬದಲಿಗೆ ಅಗತ್ಯವಿದ್ದಾಗ ಒಂದೊಂದಾಗಿ ಉತ್ಪಾದಿಸುತ್ತದೆ.
3. yield ಮತ್ತು return ನಡುವಿನ ವ್ಯತ್ಯಾಸವೇನು?
ಉತ್ತರ:
| ಲಕ್ಷಣ | return |
yield |
|---|---|---|
| ಕಾರ್ಯ | ಫಂಕ್ಷನ್ ಅನ್ನು ಕೊನೆಗೊಳಿಸುತ್ತದೆ ಮತ್ತು ಒಂದು ಮೌಲ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. | ಫಂಕ್ಷನ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ |
| ನಿಲ್ಲಿಸುತ್ತದೆ, ಮೌಲ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ, ಮತ್ತು ತನ್ನ ಸ್ಟೇಟ್ ಅನ್ನು ಉಳಿಸಿಕೊಳ್ಳುತ್ತದೆ. | ||
| ಬಳಕೆ | ಸಾಮಾನ್ಯ ಫಂಕ್ಷನ್ಗಳಲ್ಲಿ. | ಜನರೇಟರ್ ಫಂಕ್ಷನ್ಗಳಲ್ಲಿ. |
| ಕಾಲ್ | ಫಂಕ್ಷನ್ ಪ್ರತಿ ಬಾರಿ ಕಾಲ್ ಆದಾಗ ಮೊದಲಿನಿಂದ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ. | ಫಂಕ್ಷನ್ ನಿಲ್ಲಿಸಿದ ಸ್ಥಳದಿಂದಲೇ ಮುಂದುವರಿಯುತ್ತದೆ. |
| ಮೌಲ್ಯಗಳು | ಒಂದೇ ಒಂದು ಮೌಲ್ಯವನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ. | ಮೌಲ್ಯಗಳ ಸರಣಿಯನ್ನು (ಸೀಕ್ವೆನ್ಸ್) ಒಂದೊಂದಾಗಿ ಉತ್ಪಾದಿಸುತ್ತದೆ. |
4. ಜನರೇಟರ್ ಎಕ್ಸ್ಪ್ರೆಶನ್ (Generator Expression) ಎಂದರೇನು?
ಉತ್ತರ:
ಜನರೇಟರ್ ಎಕ್ಸ್ಪ್ರೆಶನ್, ಲಿಸ್ಟ್ ಕಾಂಪ್ರಹೆನ್ಷನ್ಗೆ ಹೋಲುತ್ತದೆ, ಆದರೆ ಇದು ಜನರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ರಚಿಸುತ್ತದೆ. ಇದನ್ನು ಸ್ಕ್ವೇರ್
ಬ್ರಾಕೆಟ್ಗಳ ([]) ಬದಲು ಪೇರೆಂಥಿಸಿಸ್ (()) ಬಳಸಿ ಬರೆಯಲಾಗುತ್ತದೆ.
ಇದು ಕೂಡ ಮೆಮೊರಿ-ಸಮರ್ಥವಾಗಿದೆ, ಏಕೆಂದರೆ ಇದು ಎಲ್ಲಾ ಮೌಲ್ಯಗಳನ್ನು ಒಂದೇ ಬಾರಿಗೆ ರಚಿಸುವುದಿಲ್ಲ.
ಉದಾಹರಣೆ:
# ಲಿಸ್ಟ್ ಕಾಂಪ್ರಹೆನ್ಷನ್ (ಮೆಮೊರಿಯಲ್ಲಿ ಪೂರ್ಣ ಲಿಸ್ಟ್ ರಚಿಸುತ್ತದೆ)
my_list = [i * i for i in range(10)]
# ಜನರೇಟರ್ ಎಕ್ಸ್ಪ್ರೆಶನ್ (ಜನರೇಟರ್ ಆಬ್ಜೆಕ್ಟ್ ರಚಿಸುತ್ತದೆ)
my_generator = (i * i for i in range(10))
print(my_list)
print(my_generator) # <generator object <genexpr> at ...>
for num in my_generator:
print(num, end=" ")
5. ಜನರೇಟರ್ಗಳ ಉಪಯೋಗಗಳೇನು?
ಉತ್ತರ:
- ಮೆಮೊರಿ ದಕ್ಷತೆ (Memory Efficiency): ದೊಡ್ಡ ಡೇಟಾಸೆಟ್ಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವಾಗ ಇದು ಅತ್ಯಂತ ಉಪಯುಕ್ತ. ಲಕ್ಷಾಂತರ ಐಟಂಗಳನ್ನು ಹೊಂದಿರುವ ಲಿಸ್ಟ್ ಅನ್ನು ರಚಿಸುವ ಬದಲು, ಜನರೇಟರ್ ಬಳಸಿ ಒಂದೊಂದಾಗಿ ಐಟಂಗಳನ್ನು ಪ್ರೊಸೆಸ್ ಮಾಡಬಹುದು. ಇದು ಮೆಮೊರಿ ಬಳಕೆಯನ್ನು ಗಣನೀಯವಾಗಿ ಕಡಿಮೆ ಮಾಡುತ್ತದೆ.
- ಲೇಜಿ ಇವ್ಯಾಲ್ಯುಯೇಶನ್ (Lazy Evaluation): ಮೌಲ್ಯಗಳು ಅಗತ್ಯವಿದ್ದಾಗ ಮಾತ್ರ ಉತ್ಪಾದಿಸಲ್ಪಡುತ್ತವೆ.
- ಸರಳ ಕೋಡ್: ಕಸ್ಟಮ್ ಇಟರೇಟರ್ ಕ್ಲಾಸ್ಗಳನ್ನು (
__iter__ಮತ್ತು__next__ಮೆಥಡ್ಗಳೊಂದಿಗೆ) ಬರೆಯುವುದಕ್ಕಿಂತ ಜನರೇಟರ್ ಫಂಕ್ಷನ್ಗಳನ್ನು ಬರೆಯುವುದು ಸುಲಭ. - ಪೈಪ್ಲೈನಿಂಗ್ (Pipelining): ಹಲವಾರು ಜನರೇಟರ್ಗಳನ್ನು ಒಟ್ಟಿಗೆ ಜೋಡಿಸಿ ಡೇಟಾ ಪ್ರೊಸೆಸಿಂಗ್ ಪೈಪ್ಲೈನ್ಗಳನ್ನು ರಚಿಸಬಹುದು.