Modules and Packages – ফ্রি পাইথন কোর্স ২০২০ – ক্লাস ১৩

প্রোগ্রামিংয়ে, একটি মডিউল(Module) সফ্টওয়্যারের একটি অংশ যা একটি নির্দিষ্ট কার্যকারিতা রয়েছে। উদাহরণস্বরূপ, পিং পং গেমটি তৈরি করার সময়, একটি মডিউল গেম যুক্তির(Game logic) জন্য দায়ী এবং গেমটি স্ক্রিনে আঁকার জন্য অন্য একটি মডিউল দায়ী। প্রতিটি মডিউল একটি আলাদা ফাইল, যা আলাদাভাবে সম্পাদনা(edit) করা যেতে পারে।

মডিউল লেখা:

পাইথনের মডিউলগুলি কেবল একটি .py এক্সটেনশন সহ পাইথন ফাইল। মডিউলটির নাম হবে ফাইলের নাম। পাইথন মডিউলে ফাংশন, শ্রেণি বা ভেরিয়েবল সংজ্ঞায়িত এবং প্রয়োগ করা যেতে পারে। নিম্নোক্ত উদাহরণে, আমাদের কাছে দুটি ফাইল থাকবে, আমাদের রয়েছে:

mygame/
mygame/game.py
mygame/draw.py

পাইথন স্ক্রিপ্ট game.py গেমটি বাস্তবায়ন করবে। এটি draw.py ফাইল থেকে ফাংশন draw_game ব্যবহার করবে, বা অন্য কথায়, draw মডিউল, যা স্ক্রিনে গেমটি আঁকার জন্য যুক্তি প্রয়োগ করে।

import কমান্ড ব্যবহার করে মডিউলগুলি অন্য মডিউল থেকে ইমপোর্ট করা হয়। এই উদাহরণে, game.py স্ক্রিপ্টটি নিচের কোডের এর মতো দেখাতে পারে:

# game.py
# import the draw module
import draw

def play_game():
    ...

def main():
    result = play_game()
    draw.draw_game(result)

# this means that if this script is executed, then 
# main() will be executed
if __name__ == '__main__':
    main()

draw মডিউলটি এর মতো দেখতে পারে:

# draw.py

def draw_game():
    ...

def clear_screen(screen):
    ...

এই উদাহরণে, the_game মডিউলটি draw মডিউলটি ইমপোর্ট করে, যা এটি মডিউলটিতে প্রয়োগ করা ফাংশনগুলি ব্যবহার করতে সক্ষম করে। মূল ফাংশনটি গেমটি চালাতে স্থানীয় ফাংশন play_game ব্যবহার করবে এবং তারপরে draw_game নামক draw_module প্রয়োগ করা একটি ফাংশন ব্যবহার করে গেমের ফলাফলটি আঁকবে। draw মডিউল থেকে ফাংশন draw_game ব্যবহার করতে, আমাদের ডট অপারেটর (dot operator) ব্যবহার করে কোন মডিউলে ফাংশনটি প্রয়োগ করা হবে তা নির্দিষ্ট করতে হবে। game মডিউল থেকে draw_game ফাংশনটি উল্লেখ করতে, আমাদের অবশ্যই draw মডিউলটি ইমপোর্ট করতে হবে এবং কেবল তখনই draw.draw_game() কল করতে হবে।

যখন import draw নির্দেশিকাটি চলবে, পাইথন ইন্টারপ্রেটারটি একটি ডিরেক্টরিতে একটি ফাইল সন্ধান করবে যা থেকে স্ক্রিপ্টটি কার্যকর করা হয়েছিল, একটি মডিউলের নাম দ্বারা .py উপসর্গ(prefix) সহ, সুতরাং আমাদের ক্ষেত্রে এটি draw কে খোজার চেষ্টা করবে।এটি যদি একটি সন্ধান করে তবে এটি এটি ইমপোর্ট করবে। যদি তা না হয় তবে এটি বিল্ড-ইন মডিউলগুলি সন্ধান করতে থাকবে।

আপনি লক্ষ্য করেছেন যে কোনও মডিউল ইমপোর্ট করার সময় একটি .pyc ফাইল উপস্থিত হয় যা একটি সংকলিত(compiled) পাইথন ফাইল। পাইথন, পাইথন বাইটকোডে(Python bytecode) ফাইলগুলি সংকলন করে যাতে প্রতিটি সময় মডিউলগুলি লোড হওয়ার পরে ফাইলগুলি পার্স করতে না হয়। যদি একটি .pyc ফাইল বিদ্যমান থাকে তবে এটি .py ফাইলের পরিবর্তে লোড হয়ে যায় তবে এই প্রক্রিয়াটি ব্যবহারকারীর অজান্তে হয়।

ফাইলে সরাসরি মডিউল অবজেক্টগুলি ইমপোর্ট করা

আমরা from কমান্ডটি ব্যবহার করে সরাসরি স্ক্রিপ্টের নেমস্পেসে draw_game ফাংশনটিি ইমপোর্ট করতে পারি।

# game.py
# import the draw module
from draw import draw_game

def main():
    result = play_game()
    draw_game(result)

আপনি লক্ষ করেছেন যে এই উদাহরণে, draw_game যে মডিউলটি থেকে ইমপোর্ট করা হয়েছে তার নামের আগে নেই, কারণ আমরা import কমান্ডে মডিউলটির নামটি নির্দিষ্ট করেছি।

এই নোটেশনটি ব্যবহার করার সুবিধাগুলি হ’ল বর্তমান মডিউলটির ভিতরে ফাংশনগুলি ব্যবহার করা সহজ কারণ ফাংশনটি কোন মডিউল থেকে আসে তা নির্দিষ্ট করার দরকার নেই। এই নোটেশনটি ব্যবহার করার সুবিধাগুলি হ’ল বর্তমান মডিউলটির ভিতরে ফাংশনগুলি ব্যবহার করা সহজ কারণ ফাংশনটি কোন মডিউল থেকে আসে তা নির্দিষ্ট করার দরকার নেই। যাইহোক, যে কোনও নেমস্পেসে একই নামের সাথে দুটি অবজেক্ট থাকতে পারে না, তাই import কমান্ড নামের জায়গায় একটি বিদ্যমান অবজেক্ট প্রতিস্থাপন করতে পারে।

মডিউল থেকে সমস্ত অবজেক্ট ইমপোর্ট করা

নির্দিষ্ট মডিউল থেকে সমস্ত অবজেক্ট ইমপোর্ট করতে আমরা import * কমান্ডটি ব্যবহার করতে পারি:

# game.py
# import the draw module
from draw import *

def main():
    result = play_game()
    draw_game(result)

এটি কিছুটা ঝুঁকিপূর্ণ হতে পারে কারণ মডিউলের পরিবর্তনগুলি, ইমপোর্ট করে এমন মডিউলটিকে প্রভাবিত করতে পারে তবে এটি সংক্ষিপ্ত এবং মডিউল থেকে আপনি কোন জিনিসগুলি ইমপোর্ট করতে চান তা নির্দিষ্ট করার প্রয়োজন নেই।

কাস্টম ইমপোর্ট নাম:

আমরা যে কোনও নামে মডিউলগুলি লোড করতে পারি। যখন আমরা বাকী কোডগুলিতে একই নামটি ব্যবহার করে একটি মডিউল ইমপোর্ট করতে চাই তখন এটি কাজে লাগে।

উদাহরণস্বরূপ, যদি আপনার সামান্য ভিন্ন নামের দুটি draw মডিউল থাকে – আপনি নিম্নলিখিতগুলি করতে পারেন:

# game.py
# import the draw module
if visual_mode:
    # in visual mode, we draw using graphics
    import draw_visual as draw
else:
    # in textual mode, we print out text
    import draw_textual as draw

def main():
    result = play_game()
    # this can either be visual or textual depending on visual_mode
    draw.draw_game(result)

মডিউল সূচনা(initialization):

প্রথমবার কোনও মডিউল একটি চলমান পাইথন স্ক্রিপ্টে লোড করা হয়, এটি একবার মডিউলে কোড সম্পাদন করে আরম্ভ করা হয়। যদি আপনার কোডের অন্য কোনও মডিউল আবার একই মডিউলটি ইমপোর্ট করে, তবে এটি দুটিবার লোড হবে না তবে কেবল একবারই লোড হবে – সুতরাং মডিউলের অভ্যন্তরীণ স্থানীয় ভেরিয়েবলগুলি “সিঙ্গলটন” হিসাবে কাজ করে – সেগুলি কেবল একবারই আরম্ভ করা হয়।

এটি জানা দরকারী, কারণ এর অর্থ আপনি অবজেক্টগুলি আরম্ভ করার জন্য এই আচরণের উপর নির্ভর করতে পারেন। উদাহরণ স্বরূপ:

# draw.py

def draw_game():
    # when clearing the screen we can use the main screen object initialized in this module
    clear_screen(main_screen)
    ...

def clear_screen(screen):
    ...

class Screen():
    ...

# initialize main_screen as a singleton
main_screen = Screen()

মডিউল লোড পাথ প্রসারিত করা:

আমরা পাইথন ইন্টারপ্রেটারকে বলতে পারি যে সেখানে স্থানীয় ডিরেক্টরি এবং বিল্ড-ইন মডিউল এবং ডিফল্ট বাদে মডিউলগুলি কোথায় সন্ধান করতে হবে। আপনি হয় ইনভায়রোমেন্ট ভেরিয়েবল PYTHONPATH ব্যবহার করতে পারেন অতিরিক্ত মডিউল সন্ধান করতে অতিরিক্ত ডিরেক্টরি উল্লেখ করার জন্য, যেমন:

PYTHONPATH=/foo python game.py

এটি game.py কার্যকর করবে এবং স্ক্রিপ্টটিকে স্থানীয় ডিরেক্টরি অথবা foo ডিরেক্টরি থেকে মডিউল লোড করতে সক্ষম করবে।

আর একটি পদ্ধতি হ’ল sys.path.append ফাংশন। আপনি ইমপোর্ট কমান্ড চালানোর আগে এটি সম্পাদন(execute) করতে পারেন:

sys.path.append("/foo")

এটি পাশাপাশি মডিউলগুলির সন্ধানের জন্য পাথের তালিকায় foo ডিরেক্টরি যুক্ত করবে।

বিল্ড-ইন মডিউলগুলি অন্বেষণ(explore) করা:

পাইথন স্ট্যান্ডার্ড লাইব্রেরিতে বিল্ট-ইন মডিউলগুলির সম্পূর্ণ তালিকা এখানে দেখুন

পাইথনের মডিউলগুলি সন্ধান করতে গিয়ে দুটি অত্যন্ত গুরুত্বপূর্ণ ফাংশন কার্যকর হয় – dirhelp ফাংশন।

আমরা যদি মডিউল urllib ইমপোর্ট করতে চাই, যা আমাদের URL থেকে read data তৈরি করতে সক্ষম করে, আমরা কেবল নিম্নোক্ত মডিউলটি ইমপোর্ট করি:

# import the library
import urllib

# use it
urllib.urlopen(...)

আমরা dir ফাংশনটি ব্যবহার করে প্রতিটি মডিউলে কোন ফাংশনগুলি প্রয়োগ করা হয় তা সন্ধান করতে পারি:

>>> import urllib
>>> dir(urllib)
['ContentTooShortError', 'FancyURLopener', 'MAXFTPCACHE', 'URLopener', '__all__', '__builtins__', 
'__doc__', '__file__', '__name__', '__package__', '__version__', '_ftperrors', '_get_proxies', 
'_get_proxy_settings', '_have_ssl', '_hexdig', '_hextochr', '_hostprog', '_is_unicode', '_localhost', 
'_noheaders', '_nportprog', '_passwdprog', '_portprog', '_queryprog', '_safe_map', '_safe_quoters', 
'_tagprog', '_thishost', '_typeprog', '_urlopener', '_userprog', '_valueprog', 'addbase', 'addclosehook', 
'addinfo', 'addinfourl', 'always_safe', 'basejoin', 'c', 'ftpcache', 'ftperrors', 'ftpwrapper', 'getproxies', 
'getproxies_environment', 'getproxies_macosx_sysconf', 'i', 'localhost', 'main', 'noheaders', 'os', 
'pathname2url', 'proxy_bypass', 'proxy_bypass_environment', 'proxy_bypass_macosx_sysconf', 'quote', 
'quote_plus', 'reporthook', 'socket', 'splitattr', 'splithost', 'splitnport', 'splitpasswd', 'splitport', 
'splitquery', 'splittag', 'splittype', 'splituser', 'splitvalue', 'ssl', 'string', 'sys', 'test', 'test1', 
'thishost', 'time', 'toBytes', 'unquote', 'unquote_plus', 'unwrap', 'url2pathname', 'urlcleanup', 'urlencode', 
'urlopen', 'urlretrieve']

আমরা যে ফাংশনটি ব্যবহার করতে চাই তা যখন কোনো মডিউলে পাই তখন পাইথন ইন্টারপ্রেটারের সাহায্যে help ফাংশনটি ব্যবহার করে আমরা এটি সম্পর্কে আরও জানতে পারি:

help(urllib.urlopen)

প্যাকেজ লেখা

প্যাকেজগুলি হ’ল নেমস্পেস যাতে একাধিক প্যাকেজ এবং মডিউল থাকে। এগুলি কেবল ডিরেক্টরি, তবে একটু পেচানো।

পাইথনের প্রতিটি প্যাকেজ একটি ডিরেক্টরি যা init.py নামে একটি বিশেষ ফাইল থাকা আবশ্যক। এই ফাইলটি খালি থাকতে পারে এবং এটি নির্দেশ করে যে এটিতে থাকা ডিরেক্টরিটি পাইথন প্যাকেজ, সুতরাং এটি কোনও মডিউল ইমপোর্ট করার মতো একইভাবে ইমপোর্ট করা যায়।

যদি আমরা foo নামে একটি ডিরেক্টরি তৈরি করি যা প্যাকেজের নাম চিহ্নিত করে, তবে আমরা সেই প্যাকেজের ভিতরে bar নামে একটি মডিউল তৈরি করতে পারি। foo ডিরেক্টরিতে init.py ফাইলটি যুক্ত করতে আমাদের ভুলে যাওয়া উচিত নয়।

মডিউল bar ব্যবহার করতে, আমরা এটি দুটি উপায়ে ইমপোর্ট করতে পারি:

import foo.bar

অথবা:

from foo import bar

প্রথম পদ্ধতিতে, যখনই আমরা মডিউল bar অ্যাক্সেস করি তখন আমাদের অবশ্যই foo উপসর্গ(prefix) ব্যবহার করতে হবে। দ্বিতীয় পদ্ধতিতে আমরা তা করি না, কারণ আমরা মডিউলটি আমাদের মডিউলটির নেমস্পেস ব্যবহার করি।

init.py ফাইলটি সিদ্ধান্ত নিতে পারে যে কোন মডিউলগুলি API হিসাবে প্যাকেজ এক্সপোর্ট করে। __all__ ভেরিয়েবলকে ওভাররাইড করে অন্য মডিউলগুলি অভ্যন্তরীণ রাখার সময়। যেমন:

__init__.py:

__all__ = ["bar"]

Leave a Comment