শ্রেণি এবং উদাহরণের বৈশিষ্ট্যের মধ্যে পার্থক্য কী?


132

এর মধ্যে কোনও অর্থপূর্ণ পার্থক্য রয়েছে:

class A(object):
    foo = 5   # some default value

বনাম

class B(object):
    def __init__(self, foo=5):
        self.foo = foo

যদি আপনি প্রচুর উদাহরণ তৈরি করেন তবে দুটি শৈলীর জন্য পারফরম্যান্স বা স্থানের প্রয়োজনীয়তার মধ্যে কোনও পার্থক্য রয়েছে কি? আপনি যখন কোডটি পড়েন, আপনি কি দুটি শৈলীর অর্থ উল্লেখযোগ্যভাবে আলাদা বলে বিবেচনা করবেন?


1
আমি কেবল বুঝতে পেরেছিলাম যে এখানে একটি অনুরূপ প্রশ্ন জিজ্ঞাসা করা হয়েছিল এবং এখানে উত্তর দেওয়া হয়েছে: stackoverflow.com/questions/206734/… আমার এই প্রশ্নটি মুছে ফেলা উচিত?
ড্যান হোম্রিক

2
এটি আপনার প্রশ্ন, এটি মুছে ফেলার জন্য নির্দ্বিধায়। যেহেতু এটি আপনার, তাই কেন অন্য কারও মতামত জিজ্ঞাসা করুন?
এস .লট

উত্তর:


146

পারফরম্যান্স বিবেচনার বাইরে, একটি গুরুত্বপূর্ণ অর্থগত পার্থক্য রয়েছে। শ্রেণি বৈশিষ্ট্যের ক্ষেত্রে, কেবলমাত্র একটি অবজেক্ট উল্লেখ করা হয়েছে। ইনস্ট্যান্ট-এট্রিবিউট-সেট-এ-ইনস্ট্যান্টিয়েটে, এখানে উল্লেখ করা একাধিক অবজেক্ট থাকতে পারে। এই ক্ষেত্রে

>>> class A: foo = []
>>> a, b = A(), A()
>>> a.foo.append(5)
>>> b.foo
[5]
>>> class A:
...  def __init__(self): self.foo = []
>>> a, b = A(), A()
>>> a.foo.append(5)
>>> b.foo    
[]

4
কেবল পরিবর্তনীয় প্রকারগুলি ভাগ করা আছে। পছন্দ করুন intএবং strতারা এখনও ক্লাসের পরিবর্তে প্রতিটি দৃষ্টান্তের সাথে সংযুক্ত।
বাবু

11
@Babu: না, intএবং strহয় এছাড়াও ঠিক একই ভাবে ভাগ করা। আপনি সহজেই isবা এর সাথে এটি পরীক্ষা করতে পারেন id। অথবা কেবল প্রতিটি উদাহরণ __dict__এবং শ্রেণীর সন্ধান করুন __dict__। অপরিবর্তনীয় ধরণের ভাগ করা হয় কি না তা সাধারণত খুব বেশি কিছু যায় আসে না।
22-28 এ abarnert

17
তবে নোট করুন যে আপনি যদি a.foo = 5তা করেন তবে উভয় ক্ষেত্রেই আপনি b.fooরিটার্ন দেখতে পাবেন []। এটি কারণ প্রথম ক্ষেত্রে, আপনি a.fooএকই নামের নতুন উদাহরণ বৈশিষ্ট্য সহ শ্রেণীর বৈশিষ্ট্যটি ওভাররাইট করছেন ।
কনস্টান্টিন শুবার্ট

39

পার্থক্যটি হ'ল শ্রেণীর উপরের বৈশিষ্ট্যটি সমস্ত দৃষ্টান্ত দ্বারা ভাগ করা হয়। একটি দৃষ্টান্তের বৈশিষ্ট্যটি সেই দৃষ্টিতে অনন্য।

যদি সি ++ থেকে আসে তবে ক্লাসের বৈশিষ্ট্যগুলি স্থির সদস্যের ভেরিয়েবলগুলির মতো।


1
এটি কি ভাগ করে নেওয়া কেবল পরিবর্তনীয় প্রকারের নয়? গৃহীত উত্তরটি একটি তালিকা দেখায়, যা কাজ করে, তবে এটি যদি কোনও পূর্ববর্তী বিষয় হয় তবে এটি উদাহরণসত্তর হিসাবে একই বলে মনে হয়: >>> class A(object): foo = 5 >>> a, b = A(), A() >>> a.foo = 10 >>> b.foo 5
রাফ

6
@ রাফা: না, সমস্ত প্রকার ভাগ করা আছে। আপনি বিভ্রান্ত হওয়ার কারণটি a.foo.append(5)হ'ল মূল্যটির জন্য কোনও নতুন নাম তৈরি a.fooকরার সময় মানকে যা পরিবর্তিত করে তা । সুতরাং, আপনি ক্লাসের বৈশিষ্ট্যকে আড়াল করে এমন একটি উদাহরণ বৈশিষ্ট্য দিয়ে শেষ করে। অ্যালেক্সের সংস্করণে একই চেষ্টা করে দেখুন এবং এটি অপরিবর্তিত রয়েছে। a.foo = 5a.foo5a.foo = 5b.foo
অবার্নেট

30

এখানে একটি খুব ভাল পোস্ট , এবং নীচের মত এটি সংক্ষিপ্ত।

class Bar(object):
    ## No need for dot syntax
    class_var = 1

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

## Need dot syntax as we've left scope of class namespace
Bar.class_var
## 1
foo = MyClass(2)

## Finds i_var in foo's instance namespace
foo.i_var
## 2

## Doesn't find class_var in instance namespace…
## So look's in class namespace (Bar.__dict__)
foo.class_var
## 1

এবং ভিজ্যুয়াল আকারে

এখানে চিত্র বর্ণনা লিখুন

শ্রেণীর বৈশিষ্ট্য অ্যাসাইনমেন্ট

  • ক্লাস অ্যাক্সেস করে যদি কোনও শ্রেণীর বৈশিষ্ট্য সেট করা থাকে তবে এটি সমস্ত দৃষ্টান্তের জন্য মানটিকে ওভাররাইড করে

    foo = Bar(2)
    foo.class_var
    ## 1
    Bar.class_var = 2
    foo.class_var
    ## 2
  • যদি কোনও ক্লাস ভেরিয়েবল কোনও ইনস্ট্যান্স অ্যাক্সেস করে সেট করা থাকে তবে এটি কেবলমাত্র সেই উদাহরণটির জন্য মানটিকে ওভাররাইড করবে । এটি মূলত বর্গ ভেরিয়েবলকে ওভাররাইড করে এবং এটিকে ইনস্ট্যান্স ভেরিয়েবল হিসাবে উপলব্ধ করে, স্বজ্ঞাতভাবে, কেবলমাত্র সেই উদাহরণের জন্য

    foo = Bar(2)
    foo.class_var
    ## 1
    foo.class_var = 2
    foo.class_var
    ## 2
    Bar.class_var
    ## 1

আপনি কখন শ্রেণীর বৈশিষ্ট্য ব্যবহার করবেন?

  • ধ্রুবক সংরক্ষণ করা । শ্রেণীর বৈশিষ্ট্যগুলি শ্রেণীর বৈশিষ্ট্য হিসাবে অ্যাক্সেসযোগ্য হিসাবে ক্লাস বিস্তৃত, শ্রেণি-নির্দিষ্ট ধ্রুবকগুলি সংরক্ষণ করার জন্য তাদের ব্যবহার করা প্রায়শই ভাল it's

    class Circle(object):
         pi = 3.14159
    
         def __init__(self, radius):
              self.radius = radius   
        def area(self):
             return Circle.pi * self.radius * self.radius
    
    Circle.pi
    ## 3.14159
    c = Circle(10)
    c.pi
    ## 3.14159
    c.area()
    ## 314.159
  • ডিফল্ট মান নির্ধারণ করা । তুচ্ছ উদাহরণ হিসাবে, আমরা একটি সীমাবদ্ধ তালিকা তৈরি করতে পারি (যেমন, একটি তালিকা যা কেবলমাত্র একটি নির্দিষ্ট সংখ্যক উপাদান বা তার চেয়ে কম সংখ্যককে ধরে রাখতে পারে) এবং 10 টি আইটেমের ডিফল্ট ক্যাপ রাখার জন্য বেছে নিতে পারি

    class MyClass(object):
        limit = 10
    
        def __init__(self):
            self.data = []
        def item(self, i):
            return self.data[i]
    
        def add(self, e):
            if len(self.data) >= self.limit:
                raise Exception("Too many elements")
            self.data.append(e)
    
     MyClass.limit
     ## 10

19

যদিও এই মন্তব্য এখানে এবং হিসাবে চিহ্নিত dups সব প্রদর্শিত দুই অন্য কোন প্রশ্ন মানুষের একই ভাবে এই সম্পর্কে বিভ্রান্ত করা যাবে, আমি এটা এর মূল্য উপরে একটি অতিরিক্ত উত্তর যোগ করার চিন্তা অ্যালেক্স কভেন্ট্রি এর

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

>>> class A: foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
True
>>> class A:
...     def __init__(self): self.foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
False

(আপনি যদি ভাবছেন যে আমি কেন এটির object()পরিবর্তে ব্যবহার করেছিলাম , বলুন, 5এটি যে দুটি সম্পূর্ণ অন্যান্য ইস্যু আমি এখানে toোকাতে চাই না সেগুলি এড়ানো এড়ানো; দুটি ভিন্ন কারণে সম্পূর্ণ পৃথকভাবে তৈরি 5হওয়াগুলিই শেষ হয়ে যেতে পারে সংখ্যার একই উদাহরণ 5But তবে সম্পূর্ণ পৃথকভাবে তৈরি করা object()গুলি পারে না))


সুতরাং, কেন এটি a.foo.append(5)অ্যালেক্সের উদাহরণে প্রভাবিত করে b.foo, তবে a.foo = 5আমার উদাহরণে তা হয় না? ওয়েল, চেষ্টা a.foo = 5Alex এর উদাহরণে, এবং বিজ্ঞপ্তি এটি কোনো প্রভাব পড়ে না b.fooসেখানে পারেন

a.foo = 5শুধু a.fooজন্য একটি নাম করা হয় 5। এটি প্রভাবিত করে না b.fooবা প্রবীণ মানটির জন্য অন্য কোনও নাম যা a.fooউল্লেখ করা হত * * এটি একটি সামান্য কৌশল যে আমরা একটি উদাহরণের বৈশিষ্ট্য তৈরি করি যা একটি শ্রেণীর বৈশিষ্ট্যকে আড়াল করে, ** তবে আপনি যখন এটি পেয়ে যান, জটিল কিছুই হয় না এখানে ঘটছে।


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


* সি ++ এর মতো ভাষা থেকে আসা লোকদের জন্য বিভ্রান্তি হ'ল পাইথনে, মানগুলি ভেরিয়েবলগুলিতে সংরক্ষণ করা হয় না। মানগুলি ভ্যালু-ল্যান্ডে লাইভ থাকে, নিজস্বভাবে, ভেরিয়েবলগুলি কেবলমাত্র মানগুলির নাম এবং অ্যাসাইনমেন্ট কেবল একটি মানের জন্য একটি নতুন নাম তৈরি করে। এটি যদি সহায়তা করে তবে প্রতিটি পাইথন ভেরিয়েবলকে এ এর shared_ptr<T>পরিবর্তে ভাবেন T

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


0

আরও একটি পরিস্থিতি রয়েছে।

শ্রেণি এবং উদাহরণের বৈশিষ্ট্যগুলি হ'ল বর্ণনাকারী

# -*- encoding: utf-8 -*-


class RevealAccess(object):
    def __init__(self, initval=None, name='var'):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        return self.val


class Base(object):
    attr_1 = RevealAccess(10, 'var "x"')

    def __init__(self):
        self.attr_2 = RevealAccess(10, 'var "x"')


def main():
    b = Base()
    print("Access to class attribute, return: ", Base.attr_1)
    print("Access to instance attribute, return: ", b.attr_2)

if __name__ == '__main__':
    main()

উপরে আউটপুট হবে:

('Access to class attribute, return: ', 10)
('Access to instance attribute, return: ', <__main__.RevealAccess object at 0x10184eb50>)

ক্লাসের মাধ্যমে একই ধরণের অ্যাক্সেস অ্যাক্সেস বা উদাহরণগুলি বিভিন্ন ফলাফল দেয়!

এবং আমি c.PyObject_GenericGetAttr সংজ্ঞা, এবং একটি দুর্দান্ত পোস্ট পেয়েছি ।

ব্যাখ্যা করা

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

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