শ্রেণীর স্কোপ এবং তালিকা, সেট বা অভিধান বোঝার পাশাপাশি জেনারেটরের এক্সপ্রেশনগুলি মিশ্রিত হয় না।
কেন; বা, এটিতে সরকারী শব্দ
পাইথন 3-তে, তালিকা অনুধাবনগুলিকে তাদের স্থানীয় ভেরিয়েবলগুলি আশেপাশের স্কোপ থেকে রক্তপাত রোধ করতে তাদের নিজস্ব একটি যথাযথ সুযোগ (স্থানীয় নেমস্পেস) দেওয়া হয়েছিল (দেখুন পাইথনের তালিকার বোঝাপড়ার পরেও পাইথনের তালিকা বোঝার নামগুলি পুনরায় প্রত্যাবর্তন করুন this এটি ঠিক কি? )? মডিউল বা কোনও ফাংশনে যেমন তালিকা বোধগম্যতা ব্যবহার করার সময় তা দুর্দান্ত তবে ক্লাসে স্কোপিংটি সামান্য, আহ, বিস্ময়কর ।
এটি পিপ 227 তে নথিভুক্ত করা হয়েছে :
শ্রেণীর ক্ষেত্রের নামগুলি অ্যাক্সেসযোগ্য নয়। নামগুলি অভ্যন্তরীণ ঘেরের ফাংশন স্কোপে সমাধান করা হয়। যদি কোনও শ্রেণি সংজ্ঞা নেস্টেড স্কোপগুলির একটি শৃঙ্খলে ঘটে তবে রেজোলিউশন প্রক্রিয়া শ্রেণীর সংজ্ঞাগুলি এড়িয়ে যায়।
এবং class
যৌগিক বিবৃতি নথি :
ক্লাসের স্যুটটি নতুন এক্সিকিউশন ফ্রেমে (বিভাগের নামকরণ এবং বাঁধাই করা বিভাগ দেখুন ) সদ্য নির্মিত স্থানীয় নেমস্পেস এবং আসল গ্লোবাল নেমস্পেস ব্যবহার করে কার্যকর করা হয়। (সাধারণত, স্যুটটিতে কেবলমাত্র ফাংশন সংজ্ঞা থাকে)) যখন শ্রেণীর স্যুটটি কার্যকর করা শেষ করে, তখন তার কার্যকরকরণের ফ্রেমটি বাতিল করা হয় তবে এর স্থানীয় নেমস্পেস সংরক্ষণ করা হয় । [4] বেস শ্রেণীর জন্য উত্তরাধিকার তালিকা এবং বৈশিষ্ট্য অভিধানের জন্য সংরক্ষিত স্থানীয় নেমস্পেস ব্যবহার করে একটি শ্রেণি অবজেক্ট তৈরি করা হয়।
জোর আমার; এক্সিকিউশন ফ্রেম হ'ল অস্থায়ী সুযোগ।
কারণ ক্ষেত্রটি কোনও শ্রেণীর অবজেক্টের বৈশিষ্ট্য হিসাবে পুনরায় প্রকাশ করা হয়েছে, এটি একটি ননলোকাল স্কোপ হিসাবে ব্যবহার করার অনুমতি দেয় এবং এটি অপরিবর্তিত আচরণের দিকে পরিচালিত করে; যদি কোনও শ্রেণি পদ্ধতিতে x
নেস্টেড স্কোপ ভেরিয়েবল হিসাবে উল্লেখ করা হয়, তবে কীভাবে ঘটবে Foo.x
উদাহরণস্বরূপ? আরও গুরুত্বপূর্ণ বিষয়, এর সাবক্লাসগুলির অর্থ কী Foo
? পাইথন হয়েছে একটি বর্গ সুযোগ ভিন্নভাবে চিকিত্সা যেমন একটি ফাংশন সুযোগ থেকে ভিন্ন।
শেষ, তবে অবশ্যই নিখুঁতভাবে নয়, এক্সিকিউশন মডেল ডকুমেন্টেশনের লিঙ্কযুক্ত নামকরণ এবং বাধ্যতামূলক বিভাগে ক্লাস স্কোপগুলি স্পষ্টভাবে উল্লেখ করা হয়েছে:
ক্লাস ব্লকে সংজ্ঞায়িত নামের ক্ষেত্রগুলি ক্লাস ব্লকের মধ্যে সীমাবদ্ধ; এটি পদ্ধতির কোড ব্লকগুলিতে প্রসারিত হয় না - এর মধ্যে বোধগম্যতা এবং জেনারেটর এক্সপ্রেশন রয়েছে যেহেতু তারা কোনও ফাংশন স্কোপ ব্যবহার করে প্রয়োগ করা হয়েছে implemented এর অর্থ হল যে নিম্নলিখিতগুলি ব্যর্থ হবে:
class A:
a = 42
b = list(a + i for i in range(10))
সুতরাং, সংক্ষেপে বলতে গেলে: আপনি এই সুযোগে বদ্ধ ফাংশন, তালিকা বোঝার বা জেনারেটর এক্সপ্রেশন থেকে শ্রেণি সুযোগ অ্যাক্সেস করতে পারবেন না; তারা এমনভাবে কাজ করে যেন সেই সুযোগের অস্তিত্ব নেই। পাইথন 2-এ, শর্টকাট ব্যবহার করে তালিকার উপলব্ধিগুলি প্রয়োগ করা হয়েছিল, তবে পাইথন 3 এ তারা তাদের নিজস্ব ফাংশন সুযোগ পেয়েছিল (যেমন তাদের সমস্তটি হওয়া উচিত ছিল) এবং এইভাবে আপনার উদাহরণটি ব্রেক হয়। পাইথন সংস্করণ নির্বিশেষে অন্যান্য বোধগম্যের ধরণের নিজস্ব সুযোগ রয়েছে, সুতরাং সেট বা ডিক বোঝার সাথে একটি অনুরূপ উদাহরণ পাইথন 2 এ বিভক্ত হবে।
# Same error, in Python 2 or 3
y = {x: x for i in range(1)}
(ছোট) ব্যতিক্রম; বা, কেন একটি অংশ এখনও কাজ করতে পারে
পাইথনের সংস্করণ নির্বিশেষে পার্শ্ববর্তী স্কোপগুলিতে নির্ধারিত একটি বোধগম্যতা বা জেনারেটর এক্সপ্রেশনের একটি অংশ রয়েছে। এটি বহিরাগত পুনরাবৃত্তির জন্য অভিব্যক্তি হবে। আপনার উদাহরণে, এটি range(1)
:
y = [x for i in range(1)]
# ^^^^^^^^
সুতরাং, x
এই অভিব্যক্তিটি ব্যবহার করে কোনও ত্রুটি ঘটবে না:
# Runs fine
y = [i for i in range(x)]
এটি কেবল বহিরাগততম পুনরাবৃত্তীয় ক্ষেত্রে প্রযোজ্য; যদি কোনও for
বোধগমের একাধিক ধারা থাকে তবে অভ্যন্তরীণ for
ধারাগুলির পুনরাবৃত্তিগুলি বোঝার ক্ষেত্রগুলিতে মূল্যায়ন করা হয়:
# NameError
y = [i for i in range(1) for j in range(x)]
জেনারেটর এক্সপ্রেশনটির বহিরাগততম পুনরাবৃত্তকারী তৈরি করার সময় কোনও জেনারপ এক্সপ্রেসেশন সময়ে ত্রুটি নিক্ষেপ করার জন্য এই নকশার সিদ্ধান্ত নেওয়া হয়েছিল, বা যখন বাহ্যতমতম পুনরাবৃত্তীয় পরিণত হয় তখন পুনরাবৃত্তিযোগ্য না হয়। সামঞ্জস্যতা ধারাবাহিকতার জন্য এই আচরণ ভাগ করে।
ফণা নীচে খুঁজছেন; বা, আপনি যা চেয়েছিলেন তার চেয়ে আরও বিশদ উপায়
আপনি dis
মডিউলটি ব্যবহার করে এটি সমস্ত ক্রিয়াকলাপে দেখতে পাবেন । আমি নীচের উদাহরণগুলিতে পাইথন ৩.৩ ব্যবহার করছি, কারণ এতে যোগ্য নাম যুক্ত করা হয়েছে যা আমরা পরিদর্শন করতে চাইলে কোড বস্তুগুলি সুন্দরভাবে চিহ্নিত করে। উত্পাদিত বাইটকোড অন্যথায় কার্যকরীভাবে পাইথন ৩.২ এর মতো ical
ক্লাস তৈরি করতে পাইথন মূলত পুরো স্যুটটি নিয়ে যায় যা শ্রেণিবদ্ধ শরীর তৈরি করে (সুতরাং সবকিছুই এক class <name>:
লাইনের চেয়ে আরও বেশি এক স্তরকে আবদ্ধ করে ) এবং এটি কার্যকর করে যে এটি কোনও ফাংশন:
>>> import dis
>>> def foo():
... class Foo:
... x = 5
... y = [x for i in range(1)]
... return Foo
...
>>> dis.dis(foo)
2 0 LOAD_BUILD_CLASS
1 LOAD_CONST 1 (<code object Foo at 0x10a436030, file "<stdin>", line 2>)
4 LOAD_CONST 2 ('Foo')
7 MAKE_FUNCTION 0
10 LOAD_CONST 2 ('Foo')
13 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
16 STORE_FAST 0 (Foo)
5 19 LOAD_FAST 0 (Foo)
22 RETURN_VALUE
প্রথমে শ্রেণীর বডির LOAD_CONST
জন্য কোনও কোড অবজেক্ট লোড করা হয় Foo
, তারপরে এটিকে একটি ফাংশনে পরিণত করে এবং কল করে। এই কলটির ফলাফলটি তখন শ্রেণীর নাম স্থান তৈরি করতে ব্যবহৃত হয়, এটির __dict__
। এ পর্যন্ত সব ঠিকই.
এখানে লক্ষ্য করার বিষয়টি হ'ল বাইটোকোডে নেস্টেড কোড অবজেক্ট থাকে; পাইথনে, শ্রেণি সংজ্ঞা, ফাংশন, বোধগম্য এবং জেনারেটরগুলি সমস্ত কোড কোড হিসাবে উপস্থাপিত হয় যা কেবল বাইকোডই রাখে না, পাশাপাশি কাঠামোগুলি যে স্থানীয় ভেরিয়েবল, ধ্রুবক, গ্লোবাল থেকে নেওয়া ভেরিয়েবল এবং নেস্টেড স্কোপ থেকে নেওয়া ভেরিয়েবলের প্রতিনিধিত্ব করে। সংকলিত বাইটকোড সেই কাঠামোগুলি বোঝায় এবং পাইথন ইন্টারপ্রেটার উপস্থাপিত বাইটকোডগুলি কীভাবে অ্যাক্সেস করবেন তা জানে।
এখানে মনে রাখা গুরুত্বপূর্ণ বিষয় হ'ল পাইথন সংকলনের সময় এই কাঠামোগুলি তৈরি করে; class
স্যুট একটি কোড বস্তু (হয় <code object Foo at 0x10a436030, file "<stdin>", line 2>
) যে ইতিমধ্যে কম্পাইল করা হয়।
আসুন সেই কোড অবজেক্টটি পরিদর্শন করি যা ক্লাস বডি নিজেই তৈরি করে; কোড অবজেক্টগুলির একটি co_consts
কাঠামো রয়েছে:
>>> foo.__code__.co_consts
(None, <code object Foo at 0x10a436030, file "<stdin>", line 2>, 'Foo')
>>> dis.dis(foo.__code__.co_consts[1])
2 0 LOAD_FAST 0 (__locals__)
3 STORE_LOCALS
4 LOAD_NAME 0 (__name__)
7 STORE_NAME 1 (__module__)
10 LOAD_CONST 0 ('foo.<locals>.Foo')
13 STORE_NAME 2 (__qualname__)
3 16 LOAD_CONST 1 (5)
19 STORE_NAME 3 (x)
4 22 LOAD_CONST 2 (<code object <listcomp> at 0x10a385420, file "<stdin>", line 4>)
25 LOAD_CONST 3 ('foo.<locals>.Foo.<listcomp>')
28 MAKE_FUNCTION 0
31 LOAD_NAME 4 (range)
34 LOAD_CONST 4 (1)
37 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
40 GET_ITER
41 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
44 STORE_NAME 5 (y)
47 LOAD_CONST 5 (None)
50 RETURN_VALUE
উপরের বাইটোকোড শ্রেণিবৃদ্ধি তৈরি করে। ফাংশনটি কার্যকর করা হয় এবং ফলস্বরূপ locals()
নামের স্থানটি ধারণ করে x
এবং y
শ্রেণি তৈরি করতে ব্যবহৃত হয় (এটি x
বিশ্বব্যাপী হিসাবে সংজ্ঞায়িত না হওয়ায় এটি কাজ করে না )। লক্ষ্য করুন সংরক্ষণকারী পর 5
এ x
, এটা অন্য কোড বস্তুর লোড; যে তালিকা অনুধাবন; এটি ক্লাস বডি যেমন ঠিক একটি ফাংশন বস্তুতে আবৃত হয়; তৈরি ফাংশনটি একটি অবস্থানগত আর্গুমেন্ট গ্রহণ করে, range(1)
এর লুপিং কোডের জন্য ব্যবহারযোগ্য পুনরাবৃত্তকারীকে একটি পুনরুক্তকারীর কাছে কাস্ট করে। বাইটকোডে যেমন দেখানো হয়েছে, range(1)
শ্রেণি স্কোপে মূল্যায়ন করা হয়।
এগুলি থেকে আপনি দেখতে পাচ্ছেন যে কোনও ফাংশন বা জেনারেটরের জন্য কোনও কোড অবজেক্ট এবং বোঝার জন্য একটি কোড অবজেক্টের মধ্যে কেবলমাত্র পার্থক্য হ'ল প্যারেন্ট কোড অবজেক্টটি কার্যকর করা হলে পরবর্তীটি তত্ক্ষণাত কার্যকর করা হয়; বাইটকোডটি কেবল ফ্লাইতে একটি ফাংশন তৈরি করে এবং কয়েকটি ছোট পদক্ষেপে এটি সম্পাদন করে।
পাইথন ২.x এর পরিবর্তে সেখানে ইনলাইন বাইকোড ব্যবহার করে, এখানে পাইথন ২.7 থেকে আউটপুট পাওয়া গেছে:
2 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
3 6 LOAD_CONST 0 (5)
9 STORE_NAME 2 (x)
4 12 BUILD_LIST 0
15 LOAD_NAME 3 (range)
18 LOAD_CONST 1 (1)
21 CALL_FUNCTION 1
24 GET_ITER
>> 25 FOR_ITER 12 (to 40)
28 STORE_NAME 4 (i)
31 LOAD_NAME 2 (x)
34 LIST_APPEND 2
37 JUMP_ABSOLUTE 25
>> 40 STORE_NAME 5 (y)
43 LOAD_LOCALS
44 RETURN_VALUE
কোনও কোড অবজেক্ট লোড হয় না, পরিবর্তে একটি FOR_ITER
লুপ ইনলাইন চালানো হয়। পাইথন ৩.x এ, তালিকা জেনারেটরকে তার নিজস্ব একটি যথাযথ কোড অবজেক্ট দেওয়া হয়েছিল যার অর্থ এটির নিজস্ব সুযোগ রয়েছে।
যাইহোক, মডিউল বা স্ক্রিপ্টটি প্রথম দোভাষী দ্বারা লোড করা হয়, এবং সংকলক একটি শ্রেণীর স্যুটকে একটি বৈধ সুযোগ হিসাবে বিবেচনা করে না , তখন অজগরটি বাকি অজগর উত্স কোডের সাথে একত্রিত হয়েছিল । একটি তালিকা বোধগম্যতে যে কোনও রেফারেন্সড ভেরিয়েবলগুলি অবশ্যই পুনরাবৃত্তভাবে ক্লাস সংজ্ঞা ঘিরে থাকা ক্ষেত্রের দিকে নজর দেওয়া উচিত । চলকটি যদি সংকলকটি খুঁজে না পান তবে এটি বিশ্বব্যাপী চিহ্নিত করে। তালিকা বোধগম্য কোড অবজেক্টের ডিসঅ্যাসাব্ল্যাকস দেখায় যে x
সত্যই এটি বিশ্বব্যাপী হিসাবে লোড হয়েছে:
>>> foo.__code__.co_consts[1].co_consts
('foo.<locals>.Foo', 5, <code object <listcomp> at 0x10a385420, file "<stdin>", line 4>, 'foo.<locals>.Foo.<listcomp>', 1, None)
>>> dis.dis(foo.__code__.co_consts[1].co_consts[2])
4 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 12 (to 21)
9 STORE_FAST 1 (i)
12 LOAD_GLOBAL 0 (x)
15 LIST_APPEND 2
18 JUMP_ABSOLUTE 6
>> 21 RETURN_VALUE
বাইটকোডের এই অংশটি প্রথম আর্গুমেন্টকে ( range(1)
পুনরুক্তিকারী) লোড করে এবং পাইথন ২.x সংস্করণের মতো এটি FOR_ITER
লুপ করে এবং এর আউটপুট তৈরি করে।
আমরা সংজ্ঞায়িত ছিল x
মধ্যে foo
ফাংশন পরিবর্তে, x
একটি সেল পরিবর্তনশীল (কোষ নেস্টেড সুযোগ পড়ুন) হতে হবে:
>>> def foo():
... x = 2
... class Foo:
... x = 5
... y = [x for i in range(1)]
... return Foo
...
>>> dis.dis(foo.__code__.co_consts[2].co_consts[2])
5 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 12 (to 21)
9 STORE_FAST 1 (i)
12 LOAD_DEREF 0 (x)
15 LIST_APPEND 2
18 JUMP_ABSOLUTE 6
>> 21 RETURN_VALUE
LOAD_DEREF
পরোক্ষভাবে লোড করা হবে x
কোড বস্তুর সেল বস্তু থেকে:
>>> foo.__code__.co_cellvars # foo function `x`
('x',)
>>> foo.__code__.co_consts[2].co_cellvars # Foo class, no cell variables
()
>>> foo.__code__.co_consts[2].co_consts[2].co_freevars # Refers to `x` in foo
('x',)
>>> foo().y
[2]
প্রকৃত রেফারেন্সিং বর্তমান ফ্রেম ডেটা স্ট্রাকচার থেকে মানটি দেখায় যা কোনও ফাংশন অবজেক্টের .__closure__
বৈশিষ্ট্য থেকে শুরু করা হয়েছিল । যেহেতু বোধগম্য কোড অবজেক্টের জন্য তৈরি ফাংশনটি আবার ফেলে দেওয়া হয়েছে, তাই আমরা সেই ফাংশনটির বন্ধটি পরিদর্শন করতে পারি না। ক্রিয়াকলাপে একটি বন্ধ দেখতে, আমাদের পরিবর্তে একটি নেস্টেড ফাংশনটি পরীক্ষা করতে হবে:
>>> def spam(x):
... def eggs():
... return x
... return eggs
...
>>> spam(1).__code__.co_freevars
('x',)
>>> spam(1)()
1
>>> spam(1).__closure__
>>> spam(1).__closure__[0].cell_contents
1
>>> spam(5).__closure__[0].cell_contents
5
সুতরাং, সংক্ষেপে বলা:
- তালিকার বোধগম্যতা পাইথন 3 এ তাদের নিজস্ব কোড অবজেক্টগুলি পান এবং ফাংশন, জেনারেটর বা বোঝার জন্য কোড অবজেক্টগুলির মধ্যে কোনও পার্থক্য নেই; বোধগম্য কোড অবজেক্টগুলি একটি অস্থায়ী ফাংশন অবজেক্টে আবৃত থাকে এবং সাথে সাথে তাকে ডাকা হয়।
- কোড অবজেক্টগুলি সংকলন সময়ে তৈরি করা হয় এবং কোনও অ-স্থানীয় ভেরিয়েবল কোডের নেস্টেড স্কোপের ভিত্তিতে গ্লোবাল বা ফ্রি ভেরিয়েবল হিসাবে চিহ্নিত করা হয়। শ্রেণীর সংস্থাকে সেই পরিবর্তনশীলগুলি অনুসন্ধান করার সুযোগ হিসাবে বিবেচনা করা হয় না ।
- কোডটি কার্যকর করার সময় পাইথনের কেবলমাত্র গ্লোবালগুলি অনুসন্ধান করা উচিত, বা বর্তমানে সম্পাদনকারী অবজেক্টটির সমাপ্তি। যেহেতু সংকলক ক্লাস বডিটিকে স্কোপ হিসাবে অন্তর্ভুক্ত করেনি তাই অস্থায়ী ফাংশন নেমস্পেস বিবেচনা করা হয় না।
একটি workaround; বা, এটি সম্পর্কে কি করতে হবে
আপনি যদি x
কোনও ফাংশনের মতো ভেরিয়েবলের জন্য একটি সুস্পষ্ট সুযোগ তৈরি করতে থাকেন তবে তালিকা বোধের জন্য আপনি শ্রেণি-স্কোপ ভেরিয়েবলগুলি ব্যবহার করতে পারেন:
>>> class Foo:
... x = 5
... def y(x):
... return [x for i in range(1)]
... y = y(x)
...
>>> Foo.y
[5]
'অস্থায়ী' y
ফাংশনটি সরাসরি বলা যেতে পারে; আমরা যখন এর রিটার্ন মান দিয়ে থাকি তখন আমরা এটিকে প্রতিস্থাপন করি। তার সুযোগ হয় যখন সমাধানে বিবেচিত x
:
>>> foo.__code__.co_consts[1].co_consts[2]
<code object y at 0x10a5df5d0, file "<stdin>", line 4>
>>> foo.__code__.co_consts[1].co_consts[2].co_cellvars
('x',)
অবশ্যই, আপনার কোডটি পড়ার লোকেরা এটিকে কিছুক্ষণের জন্য তাদের মাথাগুলি স্ক্র্যাচ করবে; আপনি কেন এটি করছেন তা ব্যাখ্যা করে আপনি সেখানে একটি বড় ফ্যাট মন্তব্য রাখতে চাইতে পারেন।
সর্বোত্তম কাজটি হ'ল পরিবর্তে কেবলমাত্র __init__
একটি উদাহরণ পরিবর্তনশীল তৈরি করতে ব্যবহার করা:
def __init__(self):
self.y = [self.x for i in range(1)]
এবং নিজেকে ব্যাখ্যা করার জন্য সমস্ত মাথা-ঘাটানো, এবং প্রশ্নগুলি এড়িয়ে চলুন। আপনার নিজের কংক্রিটের উদাহরণের জন্য, আমি এমনকি namedtuple
ক্লাসে স্টোরটি সংরক্ষণ করব না ; হয় আউটপুট সরাসরি ব্যবহার করুন (উত্পন্ন শ্রেণিটি মোটেও সংরক্ষণ করবেন না), অথবা একটি বিশ্বব্যাপী ব্যবহার করুন:
from collections import namedtuple
State = namedtuple('State', ['name', 'capital'])
class StateDatabase:
db = [State(*args) for args in [
('Alabama', 'Montgomery'),
('Alaska', 'Juneau'),
# ...
]]
NameError: global name 'x' is not defined
পাইথন 3.2 এবং 3.3 এ যা যা আমি প্রত্যাশা করতাম।