উদাহরণস্বরূপ শ্রেণীর ডেটা ভাগ করা কীভাবে এড়ানো যায়?


145

আমি যা চাই তা হচ্ছে এই আচরণ:

class a:
    list = []

x = a()
y = a()

x.list.append(1)
y.list.append(2)
x.list.append(3)
y.list.append(4)

print(x.list) # prints [1, 3]
print(y.list) # prints [2, 4]

অবশ্যই, আমি যখন মুদ্রণ করি তখন কী হয়:

print(x.list) # prints [1, 2, 3, 4]
print(y.list) # prints [1, 2, 3, 4]

স্পষ্টতই তারা ক্লাসে ডেটা ভাগ করছে a। আমি যে আচরণটি পছন্দ করি তা অর্জন করার জন্য আমি কীভাবে পৃথক দৃষ্টান্ত পেতে পারি?


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

উত্তর:


147

তুমি এটা চাও:

class a:
    def __init__(self):
        self.list = []

শ্রেণীর ঘোষণার ভিতরে ভেরিয়েবলগুলি ঘোষণা করা তাদের "শ্রেণি" সদস্য করে তোলে উদাহরণস্বরূপ সদস্য নয়। তাদের __init__পদ্ধতির অভ্যন্তরে ঘোষণা করা নিশ্চিত করে তোলে যে বস্তুর প্রতিটি নতুন উদাহরণের পাশাপাশি সদস্যদের একটি নতুন উদাহরণ তৈরি করা হয়েছে, এটিই আপনি যে আচরণটি সন্ধান করছেন এটি।


5
একটি অতিরিক্ত স্পষ্টতা: আপনি যদি উদাহরণগুলির মধ্যে একটিতে তালিকার সম্পত্তিটিকে পুনরায় স্বাক্ষর করেন তবে এটি অন্যকে প্রভাবিত করবে না। সুতরাং আপনি যদি এমন কিছু করেন তবে আপনি x.list = []এটি পরিবর্তন করতে পারবেন এবং অন্যকে প্রভাবিত করতে পারবেন না। আপনি যে সমস্যার মুখোমুখি হচ্ছেন তা হ'ল x.listএবং y.listএকই তালিকাগুলি, সুতরাং যখন আপনি একটিতে অ্যাপেনড কল করবেন তখন এটি অন্যটিকে প্রভাবিত করে।
ম্যাট মরিয়ারিটি

তবে কেন এটি কেবল তালিকার জন্য হয়? আমি যখন ইনিজের বাইরে কোনও পূর্ণসংখ্যা বা স্ট্রিং ঘোষণা করলাম , তখন এটি বস্তুর মধ্যে ভাগ করা হয়নি? কেউ কি এই ধারণার সাথে কোনও ডক লিঙ্ক ভাগ করতে পারেন?
অমল টিএস

1
@ অমল্টস দেখে মনে হচ্ছে আপনি পাইথনের অ্যাসাইনমেন্টটি কীভাবে কাজ করে তা বোঝেন না। দেখুন এই ভিডিওটি বা এই তাই পোস্ট । আপনি যে আচরণটি দেখছেন তা এই ঘটনার কারণে ঘটে যে আপনি তালিকার পরিবর্তন করছেন তবে ইনট এবং স্ট্রিংগুলিকে রেফেন্ডিং রেফারেন্স করে।
13

4
@ অমল্টস দ্রষ্টব্য: শ্রেণীর বৈশিষ্ট্যগুলিকে উদাহরণের বৈশিষ্ট্যের জন্য "অলস" ডিফল্ট মান হিসাবে ব্যবহার করা এটি একটি খারাপ অভ্যাস হিসাবে বিবেচিত। এমনকি যদি বৈশিষ্ট্যগুলি একটি অপরিবর্তনীয় প্রকারের হয় তবে সেগুলি ভিতরে assignুকিয়ে দেওয়া আরও ভাল __init__
Андрей Беньковский

21

গৃহীত উত্তরটি কাজ করে তবে আরও কিছুটা ব্যাখ্যা ক্ষতি করে না।

শ্রেণীর বৈশিষ্ট্যগুলি যখন কোনও উদাহরণ তৈরি করা হয় তখন উদাহরণ বৈশিষ্ট্য হয়ে ওঠে না। যখন তাদের কাছে কোনও মান নির্ধারিত হয় তখন এগুলি উদাহরণস্বরূপ বৈশিষ্ট্য হয়ে ওঠে।

মূল listকোডটিতে ইনস্ট্যান্টেশনের পরে কোনও মান নির্ধারিত হয় না ; সুতরাং এটি একটি শ্রেণি বৈশিষ্ট্য থেকে যায়। __init__কাজের ভিতরে তালিকা সংজ্ঞায়িত করা কারণ __init__তাত্ক্ষণিকতার পরে বলা হয়। বিকল্পভাবে, এই কোডটি পছন্দসই আউটপুট উত্পাদন করতে পারে:

>>> class a:
    list = []

>>> y = a()
>>> x = a()
>>> x.list = []
>>> y.list = []
>>> x.list.append(1)
>>> y.list.append(2)
>>> x.list.append(3)
>>> y.list.append(4)
>>> print(x.list)
[1, 3]
>>> print(y.list)
[2, 4]

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

>>> class a:
    string = ''


>>> x = a()
>>> y = a()
>>> x.string += 'x'
>>> y.string += 'y'
>>> x.string
'x'
>>> y.string
'y'

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


11

আপনি "তালিকা "টিকে" শ্রেণি স্তরের সম্পত্তি "হিসাবে ঘোষণা করেছেন," উদাহরণ স্তরের সম্পত্তি "হিসাবে নয়। উদাহরণ স্তরে বৈশিষ্ট্যগুলি স্কোপ করার জন্য, আপনাকে __init__পদ্ধতিতে (বা অবস্থার উপর নির্ভর করে অন্য কোথাও) "স্ব" প্যারামিটারের সাথে রেফারেন্সের মাধ্যমে এগুলি শুরু করতে হবে ।

আপনাকে __init__পদ্ধতিতে উদাহরণ বৈশিষ্টগুলি কঠোরভাবে শুরু করতে হবে না তবে এটি সহজ বোঝার জন্য তৈরি করে।


11

যদিও গৃহীত অ্যানওয়ারটি স্পট রয়েছে, তবে আমি কিছুটা বর্ণনা যুক্ত করতে চাই।

একটি ছোট অনুশীলন করা যাক

প্রথমে নিম্নরূপ কোনও শ্রেণি সংজ্ঞায়িত করুন:

class A:
    temp = 'Skyharbor'

    def __init__(self, x):
        self.x = x

    def change(self, y):
        self.temp = y

তাই আমরা এখানে কি আছে?

  • আমাদের একটি খুব সাধারণ বর্গ রয়েছে যার একটি বৈশিষ্ট্য রয়েছে tempযা একটি স্ট্রিং
  • একটি __init__পদ্ধতি যা সেট করেself.x
  • একটি পরিবর্তন পদ্ধতি সেট self.temp

খুব সোজা এগিয়ে এতদুর হাঁ? এবার এই ক্লাসটি নিয়ে চারপাশে খেলা শুরু করা যাক। প্রথমে এই ক্লাসটি শুরু করি:

a = A('Tesseract')

এখন নিম্নলিখিতগুলি করুন:

>>> print(a.temp)
Skyharbor
>>> print(A.temp)
Skyharbor

ঠিক আছে, a.tempপ্রত্যাশার মতো কাজ করেছেন কিন্তু কীভাবে A.tempকাজ করলেন? ভাল এটি কাজ করেছে কারণ টেম্প একটি শ্রেণি বৈশিষ্ট্য। পাইথনের সমস্ত কিছুই একটি বস্তু। এখানে এও বর্গের একটি বিষয় type। সুতরাং অ্যাট্রিবিউট টেম্প একটি Aশ্রেণীর দ্বারা অনুষ্ঠিত একটি বৈশিষ্ট্য এবং আপনি যদি টেম্পের মান পরিবর্তন করেন A(এবং কোনও উদাহরণের মাধ্যমে নয় a), পরিবর্তিত মানটি Aশ্রেণীর সমস্ত ক্ষেত্রে প্রতিফলিত হতে চলেছে । আসুন এগিয়ে যান এবং এটি করা:

>>> A.temp = 'Monuments'
>>> print(A.temp)
Monuments
>>> print(a.temp)
Monuments

আকর্ষণীয় তাই না? এবং এটি দ্রষ্টব্য id(a.temp)এবং id(A.temp)এখনও একই

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

>>> print(A.__dict__)
{
    'change': <function change at 0x7f5e26fee6e0>,
    '__module__': '__main__',
    '__init__': <function __init__ at 0x7f5e26fee668>,
    'temp': 'Monuments',
    '__doc__': None
}
>>> print(a.__dict__)
{x: 'Tesseract'}

নোট করুন যে tempবৈশিষ্ট্যটি Aশ্রেণীর বৈশিষ্ট্যগুলির মধ্যে তালিকাভুক্ত থাকে যখন xউদাহরণের জন্য তালিকাভুক্ত থাকে।

সুতরাং কীভাবে আসুন আমরা a.tempউদাহরণস্বরূপ তালিকাভুক্ত না হলে এটির একটি নির্ধারিত মান পাই a। ওয়েল যে __getattribute__()পদ্ধতির ম্যাজিক । পাইথনে ডটেড সিনট্যাক্স স্বয়ংক্রিয়ভাবে এই পদ্ধতিটি ডাকে তাই আমরা যখন লিখি তখন a.tempপাইথন কার্যকর করে a.__getattribute__('temp')। এই পদ্ধতিটি অ্যাট্রিবিউট লুকিং ক্রিয়া সম্পাদন করে, অর্থাত্ বিভিন্ন জায়গায় অনুসন্ধান করে গুণকের মান খুঁজে বের করে।

স্ট্যান্ডার্ড প্রয়োগকরণ __getattribute__()প্রথমে কোনও সামগ্রীর অভ্যন্তরীণ অভিধান ( ডিক্ট ) অনুসন্ধান করে তারপরে বস্তুর ধরণটি। এই ক্ষেত্রে a.__getattribute__('temp')প্রথমে a.__dict__['temp']এবং তারপরে মৃত্যুদন্ড কার্যকর করা হয়a.__class__.__dict__['temp']

ঠিক আছে এখন আমাদের changeপদ্ধতিটি ব্যবহার করা যাক :

>>> a.change('Intervals')
>>> print(a.temp)
Intervals
>>> print(A.temp)
Monuments

ভাল এখন যে আমরা ব্যবহার করেছি self, print(a.temp)আমাদের থেকে আলাদা মান দেয় print(A.temp)

এখন যদি আমরা তুলনা করি id(a.temp)এবং id(A.temp), তারা আলাদা হবে।


3

হ্যাঁ আপনাকে অবশ্যই "কনস্ট্রাক্টর" এ ঘোষণা করতে হবে যদি আপনি চান যে তালিকাটি কোনও শ্রেণীর সম্পত্তি নয় বরং কোনও বস্তুর সম্পত্তি হয়ে যায়।


3

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

class mymeta(type):
    def __init__(cls, name, bases, d):
        pass

    def __setattr__(cls, attr, value):
        print("setting " + attr)
        super(mymeta, cls).__setattr__(attr, value)

class myclass(object):
    __metaclass__ = mymeta
    myattr = []

a = myclass()
a.myattr = []           #NOTHING IS PRINTED
myclass.myattr = [5]    #change is printed here
b = myclass()
print(b.myattr)         #pass through lookup on the base class

class expando(object):
    pass

a = expando()
a.random = 5            #no class variable required
print(a.random)         #but it still works

সংক্ষিপ্ত শ্রেণিতে ভেরিয়েবলগুলির উদাহরণ ভেরিয়েবলগুলির সাথে কিছু করার নেই।

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


0

অন্য উদাহরণ দ্বারা ভাগ করা আপনার ভেরিয়েবলটি সুরক্ষিত রাখতে আপনার প্রতিবার কোনও ইনস্ট্যান্স তৈরি করার সময় আপনাকে নতুন ইনস্ট্যান্স ভেরিয়েবল তৈরি করতে হবে। আপনি যখন শ্রেণীর অভ্যন্তরে কোনও ভেরিয়েবল ঘোষণা করছেন এটি বর্গ ভেরিয়েবল এবং সমস্ত দৃষ্টিকোণ দ্বারা ভাগ করা হয়। আপনি যদি উদাহরণস্বরূপ এটি তৈরি করতে চান তবে উদাহরণটি উল্লেখ করে চলকটি পুনরায় পুনঃনির্মাণের জন্য init পদ্ধতিটি ব্যবহার করা দরকার

পাইথন অবজেক্টস এবং ক্লাস থেকে প্রোগ্রামিজ.কম :

__init__()ফাংশন। যখনই এই শ্রেণীর কোনও নতুন অবজেক্ট তাত্ক্ষণিক হয় তখন এই বিশেষ ফাংশনটি ডাকা হয়।

এই ধরণের ফাংশনটিকে অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং (ওওপি) এর কনস্ট্রাক্টরও বলা হয়। আমরা সাধারণত এটি সমস্ত ভেরিয়েবল শুরু করতে ব্যবহার করি।

উদাহরণ স্বরূপ:

class example:
    list=[] #This is class variable shared by all instance
    def __init__(self):
        self.list = [] #This is instance variable referred to specific instance
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.