অন্য মডিউল থেকে একটি মডিউল পরিবর্তনশীল কীভাবে পরিবর্তন করবেন?


110

ধরুন আমার একটি প্যাকেজ নাম barরয়েছে এবং এতে রয়েছে bar.py:

a = None

def foobar():
    print a

এবং __init__.py:

from bar import a, foobar

তারপরে আমি এই স্ক্রিপ্টটি কার্যকর করি:

import bar

print bar.a
bar.a = 1
print bar.a
bar.foobar()

আমি যা প্রত্যাশা করি তা এখানে:

None
1
1

আমি যা পাই তা এখানে:

None
1
None

আমার ভুল ধারণাটি কি কেউ ব্যাখ্যা করতে পারেন?

উত্তর:


108

আপনি ব্যবহার করছেন from bar import aaআমদানি করা মডিউলটির বিশ্বব্যাপী একটি প্রতীক হয়ে ওঠে (বা আমদানির বিবরণীতে যে পরিমাণ সুযোগ আসে)।

আপনি যখন একটি নতুন মান নির্ধারণ করেন a, আপনি ঠিক কোন মান aপয়েন্ট পরিবর্তন করছেন, আসল মানটি নয়। আমদানি করার চেষ্টা bar.pyসাথে সরাসরি import barমধ্যে __init__.pyএবং সেটিংস এর দ্বারা সেখানে আপনার পরীক্ষা আচার bar.a = 1। এইভাবে, আপনি আসলে সংশোধন করবেন bar.__dict__['a']যা aএই প্রসঙ্গে 'আসল' মান '

একটু তিনটি স্তর সঙ্গে সংবর্ত কিন্তু bar.a = 1এর মান পরিবর্তন aমডিউল নামক barযে আসলে থেকে প্রাপ্ত করা হয় __init__.py। এটা তোলে মান পরিবর্তন নেই aযে foobarকারণ দেখেন foobarপ্রকৃত ফাইলের মধ্যে জীবন bar.py। আপনি bar.bar.aযদি এটি পরিবর্তন করতে চান তবে আপনি সেট করতে পারেন।

এটি বিবৃতিটির from foo import barফর্মটি ব্যবহার করার একটি বিপদ import: এটি barদুটি চিহ্নের মধ্যে বিভক্ত হয়ে যায়, একটি বিশ্বব্যাপী দৃশ্যমান fooযার মধ্যে থেকে মূল মানটির দিকে ইশারা করা শুরু হয় এবং যেখানে importবিবৃতি কার্যকর করা হয় সেই ক্ষেত্রটিতে একটি পৃথক চিহ্ন দেখা যায় । প্রতীক পয়েন্ট যেখানে পরিবর্তন করা হয় সেখানে এটির মানও যে পরিবর্তন করে তা পরিবর্তন করে না।

reloadইন্টারেক্টিভ ইন্টারপ্রেটার থেকে মডিউল চেষ্টা করার সময় এই ধরণের জিনিস হত্যাকারী ।


ধন্যবাদ! আপনার উত্তর সম্ভবত আমাকে অপরাধীর সন্ধানের কয়েক ঘন্টা বাঁচিয়েছে।
'11:

দেখে মনে হচ্ছে এমনকি bar.bar.aব্যবহারটি বেশিরভাগ ব্যবহারের ক্ষেত্রে খুব বেশি সহায়তা করবে না। সংকলন বা মডিউল লোডিং এবং রানটাইম অ্যাসাইনমেন্টগুলি মিশ্রিত করা সম্ভবত এটি একটি দুর্বল ধারণা কারণ আপনি নিজেরাই (বা আপনার কোড ব্যবহার করেন এমন অন্যদের) বিভ্রান্ত করবেন। বিশেষত যে ভাষাগুলিতে এটি সম্পর্কে কিছুটা বেমানান আচরণ করা হয়, তেমন অজগর যেমন হয় তেমনি।
ম্যাটানস্টার

26

এই প্রশ্নের সাথে অসুবিধার একটি উত্স হ'ল আপনার নামক একটি প্রোগ্রাম রয়েছে bar/bar.py: import barআমদানি হয় হয় bar/__init__.pyবা হয় bar/bar.pyকোথায় হয় তার উপর নির্ভর করে যা aকোনটি ট্র্যাক করতে এটি একটু জটিল করে তোলে bar.a

এটা যেভাবে কাজ করে:

কী ঘটেছিল তা বোঝার মূল চাবিকাঠিটি এটি আপনার উপলব্ধিতে অনুধাবন করা __init__.py,

from bar import a

বাস্তবে কিছু ভালো লাগে

a = bar.a
# … where bar = bar/bar.py (as if bar were imported locally from __init__.py)

এবং একটি নতুন ভেরিয়েবল সংজ্ঞা দেয় ( bar/__init__.py:a, যদি আপনি চান)। সুতরাং, আপনার from bar import aমধ্যে __init__.pyবেঁধে নাম bar/__init__.py:aআসল bar.py:aবস্তু ( None)। এই জন্যই আপনি কি করতে পারেন from bar import a as a2মধ্যে __init__.py: এই ক্ষেত্রে, এটা স্পষ্ট আপনি উভয় আছে bar/bar.py:aএবং একটি স্বতন্ত্র পরিবর্তনশীল নাম bar/__init__.py:a2(আপনার ক্ষেত্রে, দুটি ভেরিয়েবল নাম মাত্র উভয় হতে ঘটতে a, কিন্তু তারা এখনও বিভিন্ন নামব্যবধান লাইভে: এ __init__.py, তারা bar.aএবং a)।

এখন, আপনি যখন

import bar

print bar.a

আপনি পরিবর্তনশীল অ্যাক্সেস করছেন bar/__init__.py:a(যেহেতু import barআপনার আমদানি করে bar/__init__.py)। এটি আপনার পরিবর্তিত (পরিবর্তনশীল 1)। আপনি ভেরিয়েবলের বিষয়বস্তু স্পর্শ করছেন না bar/bar.py:a। সুতরাং আপনি যখন পরে করবেন

bar.foobar()

আপনাকে কল bar/bar.py:foobar()যা পরিবর্তনশীল, aথেকে bar/bar.pyযা এখনও হয়, None(যখন foobar()সংজ্ঞায়িত করা হয়, এটা একবার পরিবর্তনশীল নামের binds, তাই aমধ্যে bar.pyহয় bar.py:a, অন্য কোন না aপরিবর্তনশীল অন্য সংজ্ঞায়িত মডিউল হিসাবে অনেক হতে পারে aসকল আমদানি করা মডিউল ভেরিয়েবল )। অতএব শেষ Noneআউটপুট।

উপসংহার: এটা কোনো অস্পষ্টতা এড়ানোর ভাল import barদ্বারা না কোনো থাকার bar/bar.py(যেহেতু মডিউল bar.__init__.pyতোলে ডিরেক্টরির bar/একটি প্যাকেজ ইতিমধ্যে, তোমরাও তেমনি সঙ্গে আমদানি করতে পারেন import bar)।


12

অন্য কোনও উপায় রাখার জন্য: এই ভুল ধারণাটি তৈরি করা খুব সহজ। পাইথন ভাষার রেফারেন্সে এটি লুক্কায়িতভাবে সংজ্ঞায়িত করা হয়েছে: চিহ্নের পরিবর্তে অবজেক্টের ব্যবহার । আমি প্রস্তাব দেব যে পাইথন ভাষার রেফারেন্স এটিকে আরও স্পষ্ট এবং কম বিচ্ছিন্ন করে তুলবে ..

fromফর্ম না বেঁধে মডিউল নাম করে: এটা শনাক্তকারী তালিকা মাধ্যমে যায়, ধাপ (1) পাওয়া মডিউলে আপ তাদের প্রতিটি এক দেখায়, এবং স্থানীয় নামস্থান নাম binds বস্তুর এইভাবে পাওয়া যায় নি।

যাহোক:

আপনি যখন আমদানি করেন, আপনি আমদানিকৃত প্রতীকটির বর্তমান মানটি আমদানি করে এবং এটি নির্ধারিত হিসাবে আপনার নামস্থানে যোগ করুন। আপনি কোনও রেফারেন্স আমদানি করছেন না, আপনি কার্যকরভাবে একটি মান আমদানি করছেন।

সুতরাং, এর আপডেট হওয়া মান পেতে iআপনাকে অবশ্যই একটি পরিবর্তনশীল আমদানি করতে হবে যা প্রতীকটির রেফারেন্স ধারণ করে।

অন্য কথায়, আমদানি করা importজাভা-র মতো নয় ,external সি / সি ++ এ ঘোষণা বা useপিইআরএল-তে একটি ধারাও নয়।

বরং পাইথনে নিম্নলিখিত বিবৃতি:

from some_other_module import a as x

কেএন্ডআর সি তে আরও নীচের কোডের মতো :

extern int a; /* import from the EXTERN file */

int x = a;

(সাবধানতা: পাইথনের ক্ষেত্রে, "ক" এবং "এক্স" মূলত আসল মানটির একটি রেফারেন্স: আপনি INT অনুলিপি করছেন না, আপনি রেফারেন্স ঠিকানাটি অনুলিপি করছেন)


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

4
আমাকে বেশ দৃren়তার সাথে একমত হতে হবে। আমদানি / অন্তর্ভুক্ত / ব্যবহারের রেফারেন্স ফর্মটি ব্যবহারের দীর্ঘ ইতিহাস রয়েছে এবং অন্য প্রতিটি ভাষার সম্পর্কে মূল্য ফর্মটি নয়।
মার্ক জেরোলিমাটোস

4
দাম্মিট, আমি ফিরতি হিট করব ... এখানে রেফারেন্সের মাধ্যমে আমদানির একটি প্রত্যাশা রয়েছে (@ ওপি অনুসারে)। আসলে, একটি নতুন পাইথন প্রোগ্রামার, যতই অভিজ্ঞ হোক না কেন, এটি "লুক আউট" সাজানোর পদ্ধতিতে বলতে হবে। এটি কখনই ঘটবে না: সাধারণ ব্যবহারের ভিত্তিতে পাইথন ভুল পথ নিয়েছিল। প্রয়োজনে একটি "আমদানি মান" তৈরি করুন, তবে আমদানির সময় মানগুলির সাথে প্রতীকগুলিকে আবদ্ধ করবেন না।
মার্ক গেরোলিমাটোস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.