নেস্টেড ক্লাসের সুযোগ কী?


116

আমি পাইথনের নেস্টেড ক্লাসগুলিতে সুযোগগুলি বোঝার চেষ্টা করছি। এখানে আমার উদাহরণ কোড:

class OuterClass:
    outer_var = 1
    class InnerClass:
        inner_var = outer_var

শ্রেণীর তৈরির কাজ সম্পূর্ণ হয় না এবং আমি ত্রুটিটি পেয়েছি:

<type 'exceptions.NameError'>: name 'outer_var' is not defined

চেষ্টা করেও inner_var = Outerclass.outer_varকাজ হয় না। আমি পাই:

<type 'exceptions.NameError'>: name 'OuterClass' is not defined

আমি এ outer_varথেকে স্থিতি অ্যাক্সেস করার চেষ্টা করছি InnerClass

এই কাজ করতে একটি উপায় আছে কি?

উত্তর:


105
class Outer(object):
    outer_var = 1

    class Inner(object):
        @property
        def inner_var(self):
            return Outer.outer_var

এটি অন্যান্য ভাষায় অনুরূপ জিনিসগুলির মতো একই রকম নয় এবং অ্যাক্সেসটিকে স্কুপ করার পরিবর্তে বিশ্বব্যাপী অনুসন্ধান ব্যবহার করে outer_var। (আপনি যদি নামটির কোন জিনিসটি পরিবর্তন করেনOuter সাথে আবদ্ধ তবে এই কোডটি পরবর্তী সময় এটি কার্যকর করার পরে সেই বস্তুটি ব্যবহার করবে))

আপনি যদি এর পরিবর্তে সব চান Innerএকটি একটি রেফারেন্স আছে বস্তুর Outerকারণ outer_varসত্যিই একটি দৃষ্টান্ত অ্যাট্রিবিউট হল:

class Outer(object):
    def __init__(self):
        self.outer_var = 1

    def get_inner(self):
        return self.Inner(self)
        # "self.Inner" is because Inner is a class attribute of this class
        # "Outer.Inner" would also work, or move Inner to global scope
        # and then just use "Inner"

    class Inner(object):
        def __init__(self, outer):
            self.outer = outer

        @property
        def inner_var(self):
            return self.outer.outer_var

নোট করুন যে বাসা বাঁধার ক্লাসগুলি পাইথনে কিছুটা অস্বাভাবিক, এবং স্বয়ংক্রিয়ভাবে ক্লাসগুলির মধ্যে কোনও ধরণের বিশেষ সম্পর্ককে বোঝায় না। বাসা না করাই ভাল। (আপনি এখনও একটি বর্গ অ্যাট্রিবিউট সেট করতে পারেন Outerকরতে Inner, যদি আপনি চান।)


2
আপনার উত্তরটি অজগরটির কোন সংস্করণ (গুলি) যুক্ত করবে তা যুক্ত হতে পারে।
এজে।

1
আমি এটি ২.6 / ২.x মনে রেখে লিখেছি, তবে এটির দিকে তাকিয়ে আমি এমন কিছুই দেখতে পাচ্ছি যা 3.x তে একই কাজ করবে না।

আপনি এই অংশটির অর্থ কী তা আমি পুরোপুরি বুঝতে পারি না, "(আপনি যদি আউটার নামটির সাথে আবদ্ধ কোন বিষয়টিকে পরিবর্তন করেন তবে এই কোডটি পরবর্তী সময় এটি কার্যকর করার পরে সেই বস্তুটি ব্যবহার করবে))" আপনি দয়া করে আমাকে বুঝতে সাহায্য করতে পারেন?
ব্যাটব্র্যাট

1
@ ব্যাটব্র্যাট এর অর্থ হ'ল প্রতিবার আপনি যখনই করছেন তার রেফারেন্সটি Outerনতুনভাবে সন্ধান করা হবে Inner.inner_var। সুতরাং আপনি যদি নামটিকে Outerকোনও নতুন অবজেক্টে Inner.inner_varফেরত পাঠান তবে সেই নতুন অবজেক্টটি ফেরত দেওয়া শুরু করবে।
ফিলিপ

45

আমি মনে করি আপনি কেবল এটি করতে পারেন:

class OuterClass:
    outer_var = 1

    class InnerClass:
        pass
    InnerClass.inner_var = outer_var

আপনি যে সমস্যার মুখোমুখি হয়েছেন তা হ'ল:

একটি ব্লক পাইথন প্রোগ্রামের পাঠ্যের একটি অংশ যা ইউনিট হিসাবে কার্যকর হয়। নিম্নলিখিত ব্লকগুলি রয়েছে: একটি মডিউল, একটি ফাংশন বডি এবং একটি শ্রেণি সংজ্ঞা।
(...)
একটি সুযোগ একটি ব্লকের মধ্যে নামের দৃশ্যমানতা সংজ্ঞায়িত করে।
(...)
ক্লাস ব্লকে সংজ্ঞায়িত নামের ক্ষেত্রগুলি ক্লাস ব্লকের মধ্যে সীমাবদ্ধ; এটি পদ্ধতির কোড ব্লকগুলিতে প্রসারিত হয় না - এতে জেনারেটর এক্সপ্রেশনগুলি অন্তর্ভুক্ত থাকে কারণ তারা কোনও ফাংশন স্কোপ ব্যবহার করে প্রয়োগ করা হয় implemented এর অর্থ হল যে নিম্নলিখিতগুলি ব্যর্থ হবে:

   class A:  

       a = 42  

       b = list(a + i for i in range(10))

http://docs.python.org/reference/executionmodel.html#naming-and-binding

উপরের অর্থ:
ফাংশন বডি একটি কোড ব্লক এবং একটি পদ্ধতি একটি ফাংশন, তারপরে শ্রেণীর সংজ্ঞায় উপস্থিত ফাংশন বডি থেকে বর্ণিত নামগুলি ফাংশন বডি পর্যন্ত প্রসারিত হয় না।

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


2
অ্যামেজিং। আপনার উদাহরণ ব্যর্থ হয়েছে, দাবি করে "গ্লোবাল নাম 'এ' সংজ্ঞায়িত করা হয়নি"। তবুও একটি তালিকা বোধগম্যতা [a + i for i in range(10)]সফলভাবে আবস্থাকে প্রত্যাশিত তালিকার সাথে আবদ্ধ করে [42..51]।
জর্জ

6
@ জর্জি নোট করুন যে ক্লাস এ সহকারীর উদাহরণটি আমার নয়, পাইথনের অফিসিয়াল ডকের কাছ থেকে আমি এই লিঙ্কটি দিয়েছি। এই উদাহরণটি ব্যর্থ হয় এবং ব্যর্থতা যা এই উদাহরণে প্রদর্শিত হতে চেয়েছিল। আসলে list(a + i for i in range(10))এটি list((a + i for i in range(10)))বলতে হয় list(a_generator)। তারা বলছেন যে কোনও জেনারেটর কার্যকারিতার সুযোগের চেয়ে একই স্কোপ দিয়ে প্রয়োগ করা হয়।
আইকোম

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

5
@ জর্জি: এফডাব্লুআইডাব্লু, list(...)পাইথনে কল বা বোধগম্যতা কাজ 3 নয় পাইথ 3 এর ডকুমেন্টেশনও এটি প্রতিফলিত করে কিছুটা আলাদা। এটি এখন বলেছে " একটি ক্লাস ব্লকে সংজ্ঞায়িত নামের ক্ষেত্রগুলি ক্লাস ব্লকের মধ্যে সীমাবদ্ধ; এটি পদ্ধতিগুলির কোড ব্লকগুলিতে প্রসারিত হয় না - এতে কোনও ফাংশন স্কোপ ব্যবহার করে প্রয়োগ করা হয় বলে এটি বোঝা এবং জেনারেটর এক্সপ্রেশনকে অন্তর্ভুক্ত করে। " (জোর দেওয়া খনি) )।
মার্টিনিউ

আমি তালিকা সম্পর্কে কেন জানতে চাইছি (এএ + আই আই ইন রেঞ্জ (10)) এছাড়াও কাজ করে না, যেখানে আমি এএ দ্বারা একটি স্থির করেছিলাম বলে আমি মনে করি যে এটি বিশ্বব্যাপী নাম হতে পারে।
gaoxinge

20

আপনি যদি নেস্টেড ক্লাসগুলি ব্যবহার না করেন তবে আপনি আরও ভাল হতে পারেন। আপনার যদি অবশ্যই বাসা বাঁধে তবে এটি চেষ্টা করুন:

x = 1
class OuterClass:
    outer_var = x
    class InnerClass:
        inner_var = x

বা উভয় শ্রেণীর বাসা বাঁধার আগে তাদের ঘোষণা করুন:

class OuterClass:
    outer_var = 1

class InnerClass:
    inner_var = OuterClass.outer_var

OuterClass.InnerClass = InnerClass

(এটির পরে del InnerClassআপনার প্রয়োজন হলে করতে পারেন))


3

সবচেয়ে সহজ সমাধান:

class OuterClass:
    outer_var = 1
    class InnerClass:
        def __init__(self):
            self.inner_var = OuterClass.outer_var

এটি আপনার সুস্পষ্ট হওয়া প্রয়োজন, তবে বেশি প্রচেষ্টা নেয় না।


নামের ত্রুটি: নাম 'আউটারক্লাস' সংজ্ঞায়িত করা হয়নি - -1
মিস্টার_আর_মরিস_ডি

3
পয়েন্টটি আউটার ক্লাস স্কোপ থেকে এটি অ্যাক্সেস করা - প্লাস্টারে অনুরূপ ত্রুটি ঘটবে যদি আপনি আউটারের অভ্যন্তরে কোনও স্থিতিশীল সুযোগ থেকে এটি কল করেন। আমি আপনাকে এই পোস্টটি মোছার পরামর্শ দিচ্ছি
Mr_and_Mrs_D

1

পাইথনে পরিবর্তনীয় বস্তুগুলিকে রেফারেন্স হিসাবে পাস করা হয়, সুতরাং আপনি বাইরের শ্রেণীর একটি রেফারেন্সটি অভ্যন্তরীণ শ্রেণিতে পাস করতে পারেন।

class OuterClass:
    def __init__(self):
        self.outer_var = 1
        self.inner_class = OuterClass.InnerClass(self)
        print('Inner variable in OuterClass = %d' % self.inner_class.inner_var)

    class InnerClass:
        def __init__(self, outer_class):
            self.outer_class = outer_class
            self.inner_var = 2
            print('Outer variable in InnerClass = %d' % self.outer_class.outer_var)

2
দয়া করে নোট করুন যে আপনার এখানে একটি রেফারেন্স চক্র রয়েছে এবং কিছু দৃশ্যে এই শ্রেণীর উদাহরণ মুক্ত করা হবে না। সিপাইথনের একটি উদাহরণ, আপনার যদি __del__ পদ্ধতিটি নির্ধারণ করা উচিত তবে আবর্জনা সংগ্রহকারী রেফারেন্স চক্রটি পরিচালনা করতে সক্ষম হবেন না এবং অবজেক্টগুলি প্রবেশ করবে gc.garbage। উপরের কোডটি যেমন রয়েছে তেমন সমস্যাযুক্ত নয়। এটির সাথে মোকাবিলা করার উপায়টি হ'ল দুর্বল রেফারেন্স ব্যবহার করা । আপনি দুর্বলতা (2.7) বা দুর্বল (3.5)
গায়ারাড

0

পাইথন ডকুমেন্টেশন পাইথন টিউটোরিয়ালে সমস্ত ব্যাখ্যা পাওয়া যায়

আপনার প্রথম ত্রুটির জন্য <type 'exceptions.NameError'>: name 'outer_var' is not defined। ব্যাখ্যাটি হ'ল:

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

পাইথন টিউটোরিয়াল থেকে উদ্ধৃত 9.4

আপনার দ্বিতীয় ত্রুটির জন্য <type 'exceptions.NameError'>: name 'OuterClass' is not defined

যখন শ্রেণীর সংজ্ঞাটি সাধারণত (শেষের মাধ্যমে) ছেড়ে যায়, তখন একটি শ্রেণি অবজেক্ট তৈরি হয়।

পাইথন টিউটোরিয়াল থেকে উদ্ধৃত 9.3.1

সুতরাং যখন আপনি চেষ্টা করবেন inner_var = Outerclass.outer_var, Quterclassএখনও তৈরি করা হয়নি, এজন্যইname 'OuterClass' is not defined

আপনার প্রথম ত্রুটির জন্য আরও বিস্তারিত তবে ক্লান্তিকর ব্যাখ্যা:

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

লার্নিং থেকে উদ্ধৃত। পাইথন (5 ম) .মার্ক.লুটজ

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