পাইথনে ব্লক স্কোপ


97

আপনি যখন অন্যান্য ভাষায় কোড করেন, আপনি কখনও কখনও এই জাতীয় ব্লক স্কোপ তৈরি করেন:

statement
...
statement
{
    statement
    ...
    statement
}
statement
...
statement

একটি উদ্দেশ্য (অনেকের) কোড পাঠযোগ্যতার উন্নতি করা: নির্দিষ্ট বিবৃতিগুলি একটি লজিকাল ইউনিট গঠন করে বা নির্দিষ্ট স্থানীয় ভেরিয়েবলগুলি কেবলমাত্র সেই ব্লকে ব্যবহৃত হয় তা দেখানো।

পাইথনে একই জিনিস করার কোনও বুদ্ধিমান উপায় আছে?


4
One purpose (of many) is to improve code readability- পাইথন কোড, সঠিকভাবে লেখা (অর্থাত, পাইথনের জেন অনুসরণ করে ) পড়ার জন্য এ জাতীয় গার্নিশের প্রয়োজন হবে না। আসলে, পাইথন সম্পর্কে এটি আমার পছন্দ (অনেকগুলি) বিষয়।
বুরহান খালিদ

আমি এটিকে পরিবর্তন করে বলার চেষ্টা করেছি __exit__এবং ব্যর্থ হয়েছি। withglobals()
রাগ্গেরো তুরা

4
পরিবর্তনশীল আজীবন সংজ্ঞা দেওয়া, রিসোর্স অধিগ্রহণের সাথে সংযুক্ত থাকার জন্য এটি খুব কার্যকর হবে
রাগ্গেরো তুরা

26
@ বুরহানখালিদ: এটি সত্য নয়। পাইথনের জেন আপনাকে এখানে এবং সেখানে অস্থায়ী পরিবর্তনশীল সহ কোনও স্থানীয় সুযোগকে দূষিত করা থেকে বিরত রাখে না। আপনি যদি একক অস্থায়ী পরিবর্তনশীলের প্রতিটি ব্যবহারকে উদাহরণস্বরূপ একটি নেস্টেড ফাংশনটি সংজ্ঞায়িত করে যা তত্ক্ষণাত ডাকা হয় তবে পাইথনের জেনটিও খুশি হবে না। স্পষ্টভাবে একটি পরিবর্তনশীল এর সুযোগ সীমিত হয় পাঠযোগ্যতা উন্নতি করতে টুল, কারণ এটি সরাসরি উত্তর দেন "এই শনাক্তকারী নিচে ব্যবহার করা হয়?" - এমন একটি প্রশ্ন যা এমনকি সবচেয়ে মার্জিত পাইথন কোডটি পড়তে পারে।
bluenote10

18
@ বুরহান খালিদ কোনও বৈশিষ্ট্য না রাখাই ভাল। তবে সেই "জেন" বলা ঠিক জঘন্য কাজ।
ফিল

উত্তর:


85

না, ব্লকের সুযোগ তৈরি করার জন্য কোনও ভাষা সমর্থন নেই।

নিম্নলিখিত নির্মাণগুলি সুযোগ তৈরি করে:

  • মডিউল
  • ক্লাস
  • ফাংশন (ল্যাম্বডা সহ)
  • জেনারেটর এক্সপ্রেশন
  • বোধগম্যতা (ডিক্ট, সেট, তালিকা (পাইথন 3.x এ))

38

পাইথনে অহঙ্কারমূলক উপায় হ'ল আপনার ফাংশনগুলি সংক্ষিপ্ত রাখা। আপনি যদি মনে করেন এটি আপনার প্রয়োজন, আপনার কোডটি রিফ্যাক্টর করুন! :)

পাইথন প্রতিটি মডিউল, শ্রেণি, ফাংশন, জেনারেটর এক্সপ্রেশন, ডিক্স বোধগম্যতা, সেট বোধগম্যতা এবং পাইথন 3.x এ প্রতিটি তালিকা বোঝার জন্য একটি নতুন সুযোগ তৈরি করে। এগুলি ছাড়াও কার্যকারণের অভ্যন্তরে কোনও নেস্টেড স্কোপ নেই।


12
"প্রোগ্রামিংয়ের সর্বাধিক গুরুত্বপূর্ণ বিষয় হ'ল কিছু নাম দেওয়ার ক্ষমতা। দ্বিতীয় সর্বাধিক গুরুত্বপূর্ণ বিষয়টি হল নাম দেওয়ার দরকার নেই।" বেশিরভাগ ক্ষেত্রে পাইথনের জন্য স্কোপগুলি (ভেরিয়েবল ইত্যাদির জন্য) নাম দেওয়া দরকার। এই সম্মানের সাথে, পাইথন দ্বিতীয় দ্বিতীয় গুরুত্বপূর্ণ পরীক্ষায় পরিবর্তনশীল।
ক্রাজি গ্লিউ

19
প্রোগ্রামিংয়ের সর্বাধিক গুরুত্বপূর্ণ বিষয়গুলি হ'ল আপনার প্রয়োগের নির্ভরতা পরিচালনা এবং কোড ব্লকের স্কোপগুলি পরিচালনা করার ক্ষমতা। অজ্ঞাতনামা ব্লকগুলি আপনাকে কলব্যাকগুলির আজীবন সীমাবদ্ধ করতে দেয়, অন্যথায়, আপনার কলব্যাকগুলি কেবল একবার ব্যবহার করা হয়ে থাকে তবে প্রোগ্রামের সময়কালের জন্য বেঁচে থাকে, এটি বৈশ্বিক স্কোপ ক্লাটারের কারণ এবং কোডটির পঠনযোগ্যতার ক্ষতি করে।
দিমিত্রি

আমি সবেমাত্র লক্ষ্য করেছি যে ভেরিয়েবলগুলি ডিক / সেট আপত্তিগুলিও স্থানীয়। আমি পাইথন ২.7 এবং ৩.৩ চেষ্টা করেছি, তবে আমি নিশ্চিত নই যে এটির সংস্করণ নির্ভর।
wjandrea

4
@wjandrea আপনি ঠিক বলেছেন - তালিকায় যুক্ত হয়েছেন। এগুলির জন্য পাইথন সংস্করণগুলির মধ্যে কোনও পার্থক্য থাকা উচিত নয়।
সোভেন মারনাচ

4
আমি শেষ বাক্যটি আবার লিখব, কারণ আপনি খুব ভাল ফাংশনের মধ্যে ফাংশন তৈরি করতে পারেন। সুতরাং ফাংশন ভিতরে নেস্টেড scopes আছে।
থমাস এইচ

19

আপনি আপনার ফাংশনের ভিতরে কোনও ক্রিয়াকলাপ ঘোষণা করে এবং ততক্ষণে এটি কল করে পাইথনের সি ++ ব্লক স্কোপের মতো কিছু করতে পারেন। উদাহরণ স্বরূপ:

def my_func():
    shared_variable = calculate_thing()

    def do_first_thing():
        ... = shared_variable
    do_first_thing()

    def do_second_thing():
        foo(shared_variable)
        ...
    do_second_thing()

আপনি যদি এটি করতে চান তবে আপনি যদি নিশ্চিত না হন তবে এই ভিডিওটি আপনাকে বোঝাতে পারে।

মূল নীতিটি হ'ল যে কোনও 'আবর্জনা' (অতিরিক্ত ধরণের / ফাংশন) একেবারে প্রয়োজনের চেয়ে বিস্তৃত ক্ষেত্রের মধ্যে প্রবর্তন না করে যথাসম্ভব যথাযথভাবে স্কোপ করা - অন্য কোনও কিছুই do_first_thing()উদাহরণ হিসাবে উদাহরণটি ব্যবহার করতে চায় না তাই এটির বাইরে বেরোন না should কলিং ফাংশন।


এটি টেনসরফ্লো টিউটোরিয়ালে গুগল বিকাশকারীরা যেভাবে ব্যবহার করছেন, এটি এখানে
নিনো ফিলিউ

13

আমি একমত যে কোনও ব্লকের সুযোগ নেই। তবে অজগর 3 এর একটি জায়গা এটিকে SEEM করে তোলে যেন এটির অবরুদ্ধ সুযোগ রয়েছে।

কি হয়েছে যা এই চেহারা দিয়েছে? এটি অজগর 2 তে সঠিকভাবে কাজ করছিল তবে অজগর 3-এ পরিবর্তনশীল ফুটো বন্ধ করার জন্য তারা এই কৌশলটি করেছে এবং এই পরিবর্তনটি এটিকে দেখে মনে হচ্ছে যেন এটির এখানে ব্লক স্কোপ রয়েছে।

আমাকে বিস্তারিত বলতে দাও.


সুযোগের ধারণা অনুসারে, যখন আমরা একই স্কোপের ভিতরে একই নামের সাথে ভেরিয়েবলগুলি প্রবর্তন করি, তখন এর মানটি সংশোধন করা উচিত।

অজগর 2 এ এটিই ঘটছে

>>> x = 'OLD'
>>> sample = [x for x in 'NEW']
>>> x
'W'

অজগর 3 তে একই নামের পরিবর্তকটি চালু হলেও এটি ওভাররাইড হয় না, তালিকা বোধগম্য কোনও কারণে স্যান্ডবক্সের মতো কাজ করে এবং মনে হয় এটি একটি নতুন সুযোগ তৈরি করার মতো।

>>> x = 'OLD'
>>> sample = [x for x in 'NEW']
>>> x
'OLD'

এবং এই উত্তর উত্তরদাতাকে @ থমাসের বক্তব্যের বিপরীতে যায় সুযোগ তৈরি করার একমাত্র অর্থ হ'ল ফাংশন, শ্রেণি বা মডিউল কারণ এটি একটি নতুন সুযোগ তৈরি করার অন্য এক জায়গার মতো দেখাচ্ছে।


0

মডিউলগুলি (এবং প্যাকেজগুলি) আপনার প্রোগ্রামকে পৃথক নেমস্পেসে বিভক্ত করার একটি দুর্দান্ত পাইথোনিক উপায়, যা এই প্রশ্নের অন্তর্নিহিত লক্ষ্য বলে মনে হয়। প্রকৃতপক্ষে, আমি পাইথনের বেসিকগুলি শিখতে গিয়ে ব্লক স্কোপের বৈশিষ্ট্যটির অভাব দেখে হতাশ হয়ে পড়েছিলাম। যাইহোক একবার পাইথন মডিউলগুলি বুঝতে পারলে আমি ব্লক স্কোপের প্রয়োজন ছাড়াই আমার পূর্ববর্তী লক্ষ্যগুলি আরও সুন্দরভাবে উপলব্ধি করতে পারি।

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

ক্লাসগুলির সাথে ব্লক স্কোপের চেষ্টা করা

কয়েক মুহুর্তের জন্য আমি ভেবেছিলাম যে আমি একটি শ্রেণীর ঘোষণার অভ্যন্তরে কোড স্টিক করে ব্লক স্কোপ অর্জন করেছি:

x = 5
class BlockScopeAttempt:
    x = 10
    print(x) # Output: 10
print(x) # Output: 5

দুর্ভাগ্যক্রমে যখন এই ফাংশন সংজ্ঞায়িত হয় তখন এটি ভেঙে যায়:

x = 5 
class BlockScopeAttempt: 
    x = 10
    print(x) # Output: 10
    def printx2(): 
        print(x) 
    printx2() # Output: 5!!!

কারণ শ্রেণীর মধ্যে সংজ্ঞায়িত ফাংশনগুলি বিশ্বব্যাপী সুযোগ ব্যবহার করে। এটিকে সংশোধন করার সবচেয়ে সহজ (যদিও একমাত্র নয়) উপায়টি স্পষ্টভাবে শ্রেণি নির্দিষ্ট করা:

x = 5 
class BlockScopeAttempt: 
    x = 10
    print(x) # Output: 10
    def printx2(): 
        print(BlockScopeAttempt.x)  # Added class name
    printx2() # Output: 10

এটি এত মার্জিত নয় কারণ কোনও শ্রেণিতে অন্তর্ভুক্ত রয়েছে কি না তার উপর নির্ভর করে কারও অবশ্যই আলাদা আলাদাভাবে ফাংশন লিখতে হবে।

পাইথন মডিউলগুলির সাথে আরও ভাল ফলাফল

মডিউলগুলি স্ট্যাটিক ক্লাসগুলির সাথে খুব মিল, তবে আমার অভিজ্ঞতায় মডিউলগুলি অনেক ক্লিনার। মডিউলগুলির সাথে এটি করার জন্য, আমি my_module.pyনিম্নোক্ত সামগ্রীগুলি সহ বর্তমান ওয়ার্কিং ডিরেক্টরিতে কল করা একটি ফাইল তৈরি করি :

x = 10
print(x) # (A)

def printx():
    global x
    print(x) # (B)

তারপরে আমার প্রধান ফাইল বা ইন্টারেক্টিভ (উদাহরণস্বরূপ বৃহস্পতি) সেশনে, আমি করি

x = 5
import my_module # Output: 10 from (A)
my_module.printx() # Output: 10 from (B)
print(x) # Output: 5

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

যদি আপনি একটি ইন্টারেক্টিভ সেশনে মডিউলগুলির সাথে কাজ করে থাকেন তবে আপনি শুরুতে এই দুটি লাইনটি কার্যকর করতে পারেন

%load_ext autoreload
%autoreload 2

এবং মডিউলগুলি তাদের সম্পর্কিত ফাইলগুলি সংশোধন করা হলে স্বয়ংক্রিয়ভাবে পুনরায় লোড হবে।

ডেটা লোড এবং ফিল্টার করার জন্য প্যাকেজ

প্যাকেজগুলির ধারণাটি মডিউল ধারণার সামান্য বর্ধন। একটি প্যাকেজ হ'ল একটি ডিরেক্টরি যা একটি (সম্ভবত ফাঁকা) __init__.pyফাইল থাকে, যা আমদানির পরে সম্পাদিত হয়। এই ডিরেক্টরিতে থাকা মডিউল / প্যাকেজগুলি .সিনট্যাক্সের সাহায্যে অ্যাক্সেস করা যায় ।

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

আজকাল পাইথনের সাথে, আমি একটি প্যাকেজ সংজ্ঞায়িত করি my_dataযার নাম loadএবং সাবমডিউল রয়েছে filterfilter.pyআমি ভিতরে একটি আপেক্ষিক আমদানি করতে পারি:

from .load import raw_data

আমি যদি সংশোধন করি filter.py, তবে autoreloadপরিবর্তনগুলি সনাক্ত করব। এটি পুনরায় লোড হয় না load.py, সুতরাং আমার ডেটা পুনরায় লোড করার দরকার নেই। এইভাবে আমি আমার ফিল্টারিং কোডটি একটি বৃহত্তর নোটবুকে প্রোটোটাইপ করতে পারি, এটি একটি ফাংশন হিসাবে মোড়ানো করতে পারি এবং তারপরে আমার নোটবুক থেকে সরাসরি কাট-পেস্ট করতে পারি filter.py। এটি আবিষ্কার করে আমার কর্মপ্রবাহে বিপ্লব ঘটল এবং আমাকে সন্দেহের হাত থেকে "পাইথনের জেন" -তে বিশ্বাসী হিসাবে রূপান্তরিত করলেন।


0

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

statement
statement

# begin block
a = ...
b = ...
statement
statement
del a, b
# end block

statement
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.