ডেটা ক্লাস কি এবং সেগুলি কীভাবে সাধারণ ক্লাস থেকে আলাদা?


141

সঙ্গে PEP 557 ডেটা শ্রেণীর পাইথন মান গ্রন্থাগার মধ্যে চালু করা হয়।

তারা @dataclassসাজসজ্জার ব্যবহার করে এবং তাদের "ডিফল্টর সাথে পরিবর্তনীয় নেমটুপলস" বলে মনে করা হয় তবে আমি আসলেই নিশ্চিত নই যে এর বাস্তব অর্থ কী এবং তারা সাধারণ শ্রেণি থেকে কীভাবে পৃথক understand

পাইথন ডেটা ক্লাসগুলি আসলে কী এবং সেগুলি ব্যবহার করা কখন সেরা?


8
পিইপি'র বিস্তৃত বিষয়বস্তু দেওয়া, আপনি আর কী জানতে চান? namedtupleগুলি পরিবর্তনযোগ্য এবং বৈশিষ্ট্যের জন্য ডিফল্ট মান থাকতে পারে না, যেখানে ডেটা ক্লাসগুলি পরিবর্তনীয় এবং সেগুলি থাকতে পারে।
জোনারশপে

29
@ জোনারশপে আমার পক্ষে যুক্তিযুক্ত বলে মনে হচ্ছে যে বিষয়টিতে স্ট্যাকওভারফ্লো থ্রেড থাকা উচিত। স্ট্যাকওভারফ্লো বলতে প্রশ্নোত্তর ফরমেটে একটি এনসাইক্লোপিডিয়া বোঝানো হয়েছে, না? উত্তরটি কখনই হয় না "কেবল এই অন্যান্য ওয়েবসাইটটিতে দেখুন"। এখানে ডাউনভোটগুলি হওয়া উচিত ছিল না।
লুক ডেভিস

10
তালিকায় কোনও আইটেম সংযুক্ত করার জন্য পাঁচটি থ্রেড রয়েছে। উপর একটি প্রশ্ন @dataclassসাইটকে ভাঙ্গনের কারণ করবে না।
এরিক

2
@ জোনারশপে namedtuplesCAN এর ডিফল্ট মান রয়েছে। এখানে একবার দেখুন: স্ট্যাকওভারফ্লো.com
প্রশ্নগুলি

উত্তর:


152

ডেটা ক্লাসগুলি কেবল নিয়মিত ক্লাস যা স্টোরের স্টোরের দিকে চালিত হয়, এর চেয়ে অনেক বেশি যুক্তি থাকে। প্রতিবার যখন আপনি এমন কোনও শ্রেণি তৈরি করেন যা বেশিরভাগ বৈশিষ্ট্য নিয়ে থাকে আপনি একটি ডেটা ক্লাস তৈরি করেন।

কি dataclassesমডিউল না করতে হয় সহজ ডাটা শ্রেণীর তৈরি করুন। এটি আপনার জন্য প্রচুর বয়লার প্লেটের যত্ন নেয়।

এটি বিশেষত গুরুত্বপূর্ণ যখন আপনার ডেটা ক্লাসটি হ্যাশযোগ্য হতে পারে; এটির __hash__পাশাপাশি একটি __eq__পদ্ধতিও প্রয়োজন। আপনি যদি __repr__ডিবাগিং সহজ করার জন্য একটি কাস্টম পদ্ধতি যুক্ত করেন তবে তা বেশ ভার্জোজ হয়ে যেতে পারে:

class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def __init__(
            self, 
            name: str, 
            unit_price: float,
            quantity_on_hand: int = 0
        ) -> None:
        self.name = name
        self.unit_price = unit_price
        self.quantity_on_hand = quantity_on_hand

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

    def __repr__(self) -> str:
        return (
            'InventoryItem('
            f'name={self.name!r}, unit_price={self.unit_price!r}, '
            f'quantity_on_hand={self.quantity_on_hand!r})'

    def __hash__(self) -> int:
        return hash((self.name, self.unit_price, self.quantity_on_hand))

    def __eq__(self, other) -> bool:
        if not isinstance(other, InventoryItem):
            return NotImplemented
        return (
            (self.name, self.unit_price, self.quantity_on_hand) == 
            (other.name, other.unit_price, other.quantity_on_hand))

এর সাথে dataclassesআপনি এটিকে হ্রাস করতে পারবেন:

from dataclasses import dataclass

@dataclass(unsafe_hash=True)
class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

একই ক্লাসে প্রসাধক এছাড়াও তুলনা পদ্ধতি (তৈরি করতে পারেন __lt__, __gt__, ইত্যাদি) এবং হাতল অপরিবর্তনীয়তা।

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

পিইপি attrsপ্রকল্পটি দ্বারা অনুপ্রাণিত হয়েছিল , যা আরও বেশি কিছু করতে পারে (স্লট, ভ্যালিডিটার, রূপান্তরকারী, মেটাডেটা ইত্যাদি)।

আপনি যদি কয়েকটি উদাহরণ দেখতে চান তবে আমি সম্প্রতি dataclassesআমার বেশ কয়েকটি কোড অ্যাডভেন্ট সমাধানের জন্য ব্যবহার করেছি , 7 , দিন 8 , দিন 11 এবং দিন 20 এর সমাধানগুলি দেখুন ।

আপনি যদি dataclassesপাইথন সংস্করণ <3.7 সংস্করণে মডিউলটি ব্যবহার করতে চান তবে আপনি ব্যাকপোর্টেড মডিউলটি ইনস্টল করতে পারেন (3.6 প্রয়োজন) বা attrsউপরে বর্ণিত প্রকল্পটি ব্যবহার করতে পারেন ।


2
প্রথম উদাহরণে আপনি কি একই নামে উদাহরণস্বরূপ সদস্যদের সহ ক্লাসের সদস্যদের ইচ্ছাকৃতভাবে আড়াল করছেন? দয়া করে এই প্রতিমাটি বুঝতে সহায়তা করুন।
ভ্লাদিমিরলেনিন

4
@ ভ্লাদিমিরলেনিন: কোনও শ্রেণীর বৈশিষ্ট্য নেই, কেবল টাইপ টিকা আছে। পিইপি 526 দেখুন , বিশেষত শ্রেণি এবং উদাহরণের পরিবর্তনশীল টীকাগুলি বিভাগ
মার্তিজান পিটারস

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

1
@Bananach: তাই প্রথম উদাহরণে, আমরা পারে শুধু ফেরত একটি দৃষ্টান্ত অ্যাট্রিবিউট সেটিং এবং ক্লাসটি ছায়া না হয়, তাহলে যে অর্থে যাহাই হউক না কেন অপ্রয়োজনীয় সেটিং তা না হয়, কিন্তু dataclasses না সেট করুন।
মার্টিজন পিটারস

1
@ user2853437 আপনার ব্যবহারের কেসটি সত্যই ডেটাচ্লাস দ্বারা সমর্থিত নয়; সম্ভবত আপনি, dataclasses 'বড় মামাতো ভাই ব্যবহার বন্ধ ভাল হবে attrs । এই প্রকল্পটি প্রতি ক্ষেত্র রূপান্তরকারীদের সমর্থন করে যা আপনাকে ক্ষেত্রের মানকে স্বাভাবিক করতে দেয়। আপনি যদি ডেটাচ্লাসের সাথে লেগে থাকতে চান, তবে হ্যাঁ, __post_init__পদ্ধতিটিতে সাধারণকরণ করুন ।
মার্টিজন পিটারস

62

সংক্ষিপ্ত বিবরণ

প্রশ্ন সম্বোধন করা হয়েছে। যাইহোক, এই উত্তরটি ড্যাটাক্লাসগুলির প্রাথমিক বোঝার ক্ষেত্রে সহায়তা করার জন্য কিছু ব্যবহারিক উদাহরণ যুক্ত করেছে।

পাইথন ডেটা ক্লাসগুলি আসলে কী এবং সেগুলি ব্যবহার করা কখন সেরা?

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

"ডিফল্ট [গুলি] এর সাথে নাম পরিবর্তনকারী"

পরবর্তী বাক্যাংশটির অর্থ এখানে:

  • পরিবর্তনীয় : ডিফল্টরূপে, ডেটাগ্লাস বৈশিষ্ট্যগুলি পুনরায় নিয়োগ দেওয়া যেতে পারে। আপনি optionচ্ছিকভাবে এগুলি পরিবর্তনযোগ্য করতে পারেন (নীচের উদাহরণগুলি দেখুন)।
  • নেমটিউটল : আপনি namedtupleকোনও নিয়মিত ক্লাসের মতো বিন্দুযুক্ত, অ্যাট্রিবিউট অ্যাক্সেস পেয়েছেন ।
  • ডিফল্ট : আপনি বৈশিষ্ট্যগুলিতে ডিফল্ট মান নির্ধারণ করতে পারেন।

সাধারণ শ্রেণীর তুলনায় আপনি প্রাথমিকভাবে বয়লারপ্লেট কোড টাইপ করে সংরক্ষণ করুন।


বৈশিষ্ট্য

এটি ডেটাগ্লাস বৈশিষ্ট্যগুলির একটি ওভারভিউ (টিএল; ডিআর? পরবর্তী বিভাগে সংক্ষিপ্তসার সারণি দেখুন)।

তুমি কি পেলে

ডেটা চশমা থেকে আপনি ডিফল্টরূপে পাবেন এমন বৈশিষ্ট্য এখানে।

বৈশিষ্ট্য + উপস্থাপনা + তুলনা

import dataclasses


@dataclasses.dataclass
#@dataclasses.dataclass()                                       # alternative
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

এই ডিফল্টগুলি স্বয়ংক্রিয়ভাবে নিম্নলিখিত কীওয়ার্ডগুলি সেট করে সরবরাহ করা হয় True:

@dataclasses.dataclass(init=True, repr=True, eq=True)

আপনি কি চালু করতে পারেন

উপযুক্ত কীওয়ার্ড সেট করা থাকলে অতিরিক্ত বৈশিষ্ট্য উপলব্ধ True

ক্রম

@dataclasses.dataclass(order=True)
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

অর্ডারিং পদ্ধতিগুলি এখন প্রয়োগ করা হয় (ওভারলোডিং অপারেটর < > <= >=:) একইভাবে functools.total_orderingশক্তিশালী সাম্য পরীক্ষার সাথেও।

হাস্যযোগ্য, পরিবর্তনযোগ্য

@dataclasses.dataclass(unsafe_hash=True)                        # override base `__hash__`
class Color:
    ...

যদিও বস্তুটি সম্ভাব্যভাবে পরিবর্তনযোগ্য (সম্ভবত অনাকাঙ্ক্ষিত), একটি হ্যাশ প্রয়োগ করা হয়েছে।

হাস্যযোগ্য, অপরিবর্তনীয়

@dataclasses.dataclass(frozen=True)                             # `eq=True` (default) to be immutable 
class Color:
    ...

একটি হ্যাশ এখন প্রয়োগ করা হয়েছে এবং অবজেক্ট পরিবর্তন করা বা বৈশিষ্ট্যগুলি নির্ধারিত করা অনুমোদিত নয়।

সামগ্রিকভাবে, বস্তুটি হ্যাশযোগ্য যদি হয় unsafe_hash=Trueবা হয় frozen=True

আরও বিশদ সহ আসল হ্যাশিং লজিক টেবিলটিও দেখুন।

আপনি কি পাবেন না

নিম্নলিখিত বৈশিষ্ট্যগুলি পেতে, বিশেষ পদ্ধতিগুলি ম্যানুয়ালি প্রয়োগ করতে হবে:

আন-প্যাক

@dataclasses.dataclass
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

    def __iter__(self):
        yield from dataclasses.astuple(self)

অপ্টিমাইজেশান

@dataclasses.dataclass
class SlottedColor:
    __slots__ = ["r", "b", "g"]
    r : int
    g : int
    b : int

বস্তুর আকার এখন হ্রাস করা হয়েছে:

>>> imp sys
>>> sys.getsizeof(Color)
1056
>>> sys.getsizeof(SlottedColor)
888

কিছু পরিস্থিতিতে, __slots__উদাহরণগুলি তৈরি করতে এবং বৈশিষ্ট্য অ্যাক্সেস করার গতিও উন্নত করে। এছাড়াও, স্লটগুলি ডিফল্ট অ্যাসাইনমেন্টের অনুমতি দেয় না; অন্যথায়, একটি ValueErrorউত্থাপিত হয়।

এই ব্লগ পোস্টে স্লট আরও দেখুন ।


সারমর্ম সারনি

+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
|       Feature        |       Keyword        |                      Example                       |           Implement in a Class          |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Attributes           |  init                |  Color().r -> 0                                    |  __init__                               |
| Representation       |  repr                |  Color() -> Color(r=0, g=0, b=0)                   |  __repr__                               |
| Comparision*         |  eq                  |  Color() == Color(0, 0, 0) -> True                 |  __eq__                                 |
|                      |                      |                                                    |                                         |
| Order                |  order               |  sorted([Color(0, 50, 0), Color()]) -> ...         |  __lt__, __le__, __gt__, __ge__         |
| Hashable             |  unsafe_hash/frozen  |  {Color(), {Color()}} -> {Color(r=0, g=0, b=0)}    |  __hash__                               |
| Immutable            |  frozen + eq         |  Color().r = 10 -> TypeError                       |  __setattr__, __delattr__               |
|                      |                      |                                                    |                                         |
| Unpacking+           |  -                   |  r, g, b = Color()                                 |   __iter__                              |
| Optimization+        |  -                   |  sys.getsizeof(SlottedColor) -> 888                |  __slots__                              |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+

+ এই পদ্ধতিগুলি স্বয়ংক্রিয়ভাবে উত্পন্ন হয় না এবং একটি ড্যাটাক্লাসে ম্যানুয়াল বাস্তবায়ন প্রয়োজন।

* __ne__ প্রয়োজন হয় না এবং এভাবে প্রয়োগ করা হয় না


অতিরিক্ত বৈশিষ্ট্য

পোস্ট-আরম্ভের

@dataclasses.dataclass
class RGBA:
    r : int = 0
    g : int = 0
    b : int = 0
    a : float = 1.0

    def __post_init__(self):
        self.a : int =  int(self.a * 255)


RGBA(127, 0, 255, 0.5)
# RGBA(r=127, g=0, b=255, a=127)

উত্তরাধিকার

@dataclasses.dataclass
class RGBA(Color):
    a : int = 0

রূপান্তর

একটি ডেটাক্লাসকে টুপলে বা ডিকে রূপান্তর করুন, পুনরাবৃত্তভাবে :

>>> dataclasses.astuple(Color(128, 0, 255))
(128, 0, 255)
>>> dataclasses.asdict(Color(128, 0, 255))
{r: 128, g: 0, b: 255}

সীমাবদ্ধতা


তথ্যসূত্র

  • আর Hettinger এর আলাপ উপর Dataclasses: সব কোড জেনারেটর শেষ করতে কোড জেনারেটরের
  • টি Hunner এর আলাপ উপর সকল Cruft ছাড়া পাইথন ক্লাস: সহজ ক্লাস
  • হ্যাশিংয়ের বিশদ সম্পর্কিত পাইথনের ডকুমেন্টেশন
  • পাইথন ৩.7-তে ডেটা ক্লাসের চূড়ান্ত গাইড সম্পর্কে রিয়েল পাইথনের গাইড
  • উ: শ এর ব্লগ পোস্ট উপর পাইথন 3.7 ডেটা ক্লাস একটি সংক্ষিপ্ত সফর
  • ই স্মিথের GitHub সংগ্রহস্থলের উপর dataclasses

2

থেকে PEP স্পেসিফিকেশন :

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

@dataclassজেনারেটরের বর্গ যে আপনি অন্যথায় মত নিজেকে সংজ্ঞায়িত সেই ভাষাতে পদ্ধতি যোগ করা __repr__, __init__, __lt__, এবং __gt__


2

এই সাধারণ বর্গ বিবেচনা করুন Foo

from dataclasses import dataclass
@dataclass
class Foo:    
    def bar():
        pass  

এখানে dir()বিল্ট ইন তুলনা করা হয়। বাম দিকে হ'ল Foo@ ড্যাটাক্লাস সাজসজ্জা ছাড়াই এবং ডানদিকে @ ড্যাটাক্লাস সাজসজ্জারের সাথে রয়েছে।

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

inspectতুলনার জন্য মডিউলটি ব্যবহার করার পরে এটি অন্যরকম ।

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

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