পাইথন 3.7 ডেটাচ্লাসে শ্রেণীর উত্তরাধিকার


90

আমি বর্তমানে পাইথন ৩.7-এ নতুন নতুন ডেটাগ্লাস নির্মাণে হাত দেওয়ার চেষ্টা করছি। আমি বর্তমানে একটি অভিভাবক শ্রেণীর কিছু উত্তরাধিকার করার চেষ্টা করতে আটকে আছি। দেখে মনে হচ্ছে আর্গুমেন্টের ক্রমটি আমার বর্তমান পদ্ধতির সাথে মিলিত হয়েছে যাতে শিশু শ্রেণিতে বোল প্যারামিটারটি অন্যান্য পরামিতিগুলির আগে পাস হয়ে যায়। এটি একটি ধরণের ত্রুটি ঘটায়।

from dataclasses import dataclass

@dataclass
class Parent:
    name: str
    age: int
    ugly: bool = False

    def print_name(self):
        print(self.name)

    def print_age(self):
        print(self.age)

    def print_id(self):
        print(f'The Name is {self.name} and {self.name} is {self.age} year old')

@dataclass
class Child(Parent):
    school: str
    ugly: bool = True


jack = Parent('jack snr', 32, ugly=True)
jack_son = Child('jack jnr', 12, school = 'havard', ugly=True)

jack.print_id()
jack_son.print_id()

আমি এই কোডটি চালানোর সময় আমি এটি পাই TypeError:

TypeError: non-default argument 'school' follows default argument

আমি কিভাবে এটা ঠিক করব?


ugly: bool = True= rekt :)
চার

উত্তর:


138

ডেটাচলসগুলি যেভাবে বৈশিষ্ট্যগুলিকে একত্রিত করে তা আপনাকে বেস শ্রেণিতে ডিফল্টের সাথে অ্যাট্রিবিউট ব্যবহার করতে সক্ষম হতে এবং তারপরে একটি সাবক্লাসে ডিফল্ট (অবস্থানগত বৈশিষ্ট্য) ছাড়াই বৈশিষ্ট্যগুলি ব্যবহার করতে বাধা দেয়।

এটি কারণ এমআরওয়ের নীচ থেকে শুরু করে এবং প্রথম দেখা ক্রমে বিশদগুলির একটি আদেশযুক্ত তালিকা তৈরি করে বৈশিষ্ট্যগুলি একত্রিত করা হয়; ওভাররাইডগুলি তাদের মূল স্থানে রাখা হয়। সুতরাং যেখানে একটি ডিফল্ট আছে Parentদিয়ে শুরু হয় , এবং তারপরে তালিকার শেষে যুক্ত হয় ( ইতিমধ্যে তালিকার সাথে)। এর অর্থ আপনার শেষ হয়েছে এবং এতে কোনও ডিফল্ট নেই কারণ এটির জন্য একটি অবৈধ যুক্তি তালিকার ফলাফল['name', 'age', 'ugly']uglyChild['school']ugly['name', 'age', 'ugly', 'school']school__init__

এই নথিভুক্ত করা PEP-557 Dataclasses অধীন উত্তরাধিকার :

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

এবং নির্দিষ্টকরণের অধীনে :

TypeErrorডিফল্ট মানবিহীন একটি ক্ষেত্র যদি ডিফল্ট মান সহ কোনও ক্ষেত্র অনুসরণ করে তবে উত্থাপিত হবে। এটি সত্য হয় যখন এটি একটি একক শ্রেণিতে ঘটে থাকে বা শ্রেণীর উত্তরাধিকারের ফলস্বরূপ।

এই সমস্যাটি এড়াতে আপনার কাছে এখানে কয়েকটি বিকল্প রয়েছে।

প্রথম বিকল্পটি হ'ল এমআরও ক্রমের পরে অবস্থানে ডিফল্টগুলি সহ ক্ষেত্রগুলিকে বাধ্য করার জন্য পৃথক বেস ক্লাস ব্যবহার করা। যে কোনও মূল্যে, বেস ক্লাস যেমন ব্যবহার করা যেতে পারে এমন ক্লাসগুলিতে সরাসরি ক্ষেত্রগুলি স্থাপন করা এড়িয়ে চলুনParent

নিম্নলিখিত শ্রেণীর শ্রেণিবিন্যাস কাজ করে:

# base classes with fields; fields without defaults separate from fields with.
@dataclass
class _ParentBase:
    name: str
    age: int

@dataclass
class _ParentDefaultsBase:
    ugly: bool = False

@dataclass
class _ChildBase(_ParentBase):
    school: str

@dataclass
class _ChildDefaultsBase(_ParentDefaultsBase):
    ugly: bool = True

# public classes, deriving from base-with, base-without field classes
# subclasses of public classes should put the public base class up front.

@dataclass
class Parent(_ParentDefaultsBase, _ParentBase):
    def print_name(self):
        print(self.name)

    def print_age(self):
        print(self.age)

    def print_id(self):
        print(f"The Name is {self.name} and {self.name} is {self.age} year old")

@dataclass
class Child(Parent, _ChildDefaultsBase, _ChildBase):
    pass

মধ্যে ক্ষেত্রগুলি টেনে পৃথক অক্ষমতা এবং অক্ষমতা সঙ্গে ক্ষেত্র ছাড়া ক্ষেত্র, এবং একটি যত্নসহকারে নির্বাচিত উত্তরাধিকার অর্ডার দিয়ে বেস ক্লাস, আপনি একটি ম্রো তৈরী করতে পারে যে অক্ষমতা যাদের সামনে অক্ষমতা ছাড়া রাখে সব ক্ষেত্র। বিপরীত এমআরও (উপেক্ষা করা object) এর জন্য Child:

_ParentBase
_ChildBase
_ParentDefaultsBase
_ChildDefaultsBase
Parent

নোট করুন যে Parentকোনও নতুন ক্ষেত্র সেট করে না, তাই এখানে ক্ষেত্রের তালিকা ক্রমে এটি 'শেষ' হয়ে যায় তা এখানে গুরুত্বপূর্ণ নয়। অক্ষমতা ছাড়া ক্ষেত্রের সাথে ক্লাস ( _ParentBaseএবং _ChildBase) অক্ষমতা সঙ্গে ক্ষেত্রের সাথে ক্লাস বসে ( _ParentDefaultsBaseএবং_ChildDefaultsBase )।

ফলাফলটি হয়েছে Parentএবং Childবুদ্ধিমান ক্ষেত্রের সাথে ক্লাসগুলি পুরানো, যদিও Childএখনও এটির একটি সাবক্লাস রয়েছে Parent:

>>> from inspect import signature
>>> signature(Parent)
<Signature (name: str, age: int, ugly: bool = False) -> None>
>>> signature(Child)
<Signature (name: str, age: int, school: str, ugly: bool = True) -> None>
>>> issubclass(Child, Parent)
True

এবং তাই আপনি উভয় শ্রেণীর উদাহরণ তৈরি করতে পারেন:

>>> jack = Parent('jack snr', 32, ugly=True)
>>> jack_son = Child('jack jnr', 12, school='havard', ugly=True)
>>> jack
Parent(name='jack snr', age=32, ugly=True)
>>> jack_son
Child(name='jack jnr', age=12, school='havard', ugly=True)

অন্য বিকল্পটি হ'ল কেবলমাত্র খেলাপি খেলাগুলি ব্যবহার করা; আপনি এখনও কোনও schoolমান বাড়িয়ে না দিয়ে ত্রুটি তৈরি করতে পারেন __post_init__:

_no_default = object()

@dataclass
class Child(Parent):
    school: str = _no_default
    ugly: bool = True

    def __post_init__(self):
        if self.school is _no_default:
            raise TypeError("__init__ missing 1 required argument: 'school'")

কিন্তু এই করে ক্ষেত্র অর্ডার পরিবর্তন করা; schoolপরে শেষ ugly:

<Signature (name: str, age: int, ugly: bool = True, school: str = <object object at 0x1101d1210>) -> None>

এবং একটি প্রকার ইঙ্গিত চেকার সম্পর্কে অভিযোগ করবে_no_default স্ট্রিং না হওয়ার ।

আপনি attrsপ্রজেক্টটিও ব্যবহার করতে পারেন যা অনুপ্রেরণা করেছিল এমন প্রকল্প dataclasses। এটি একটি পৃথক উত্তরাধিকার মার্জ করার কৌশল ব্যবহার করে; এটা ক্ষেত্র তালিকার শেষে একটি উপশ্রেণী ওভাররাইড করা ক্ষেত্র pulls, তাই ['name', 'age', 'ugly']মধ্যে Parentবর্গ হয়ে ['name', 'age', 'school', 'ugly']Childবর্গ; ডিফল্ট দিয়ে ফিল্ডটি ওভাররাইড করে attrsএকটি এমআরও নাচ না করে ওভাররাইডকে মঞ্জুরি দেয়।

attrsপ্রকার ইঙ্গিত ছাড়াই ক্ষেত্রগুলি সংজ্ঞায়িত করা সমর্থন করে, তবে সেটিংসের দ্বারা সমর্থিত প্রকার হিন্টিং মোডে আটকে দিন auto_attribs=True:

import attr

@attr.s(auto_attribs=True)
class Parent:
    name: str
    age: int
    ugly: bool = False

    def print_name(self):
        print(self.name)

    def print_age(self):
        print(self.age)

    def print_id(self):
        print(f"The Name is {self.name} and {self.name} is {self.age} year old")

@attr.s(auto_attribs=True)
class Child(Parent):
    school: str
    ugly: bool = True

4
বিস্তারিত উত্তরের জন্য অনেক ধন্যবাদ
মিস্টেরিও

এটি খুব সহায়ক। যদিও ম্রো সম্পর্কে আমি বিভ্রান্ত। চলমান মুদ্রণ (চাইল্ড.ম্রো ()) আমি পেয়েছি: [<শ্রেণীর ' প্রধান। শিশু'>, <শ্রেণি ' প্রধান। পিতা'>, <শ্রেণি ' প্রধান ._ChildDefaultsBase'>, <শ্রেণীর ' প্রধান ._PenderDefaultsBase'>, < ক্লাস ' মেন ._ChildBase'>, <ক্লাস ' প্রধান ._PenderBase'>, <ক্লাস 'অবজেক্ট'>]] তাহলে কি ডিফল্ট বেসগুলি বেস ক্লাসের আগে চলে না?
অলি

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

প্রকৃতপক্ষে, অ্যাটর্সরা কাজ করতে পারে তবে আপনাকে ব্যবহার করা দরকার attr.ib(kw_only=True), github.com/python-attrs/attrs/issues/38 দেখুন
laike9m

8

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

থেকে একটি উদাহরণ PEP-557 - ডেটা ক্লাস :

@dataclass
class Base:
    x: Any = 15.0
    y: int = 0

@dataclass
class C(Base):
    z: int = 10
    x: int = 15

ক্ষেত্রগুলির চূড়ান্ত তালিকাটি, ক্রমে x, y, z,। চূড়ান্ত টাইপ xহয় intক্লাসে উল্লিখিত, C

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


আমি পেয়েছি যে অ-ডিফল্ট আর্গুমেন্টটি অবশ্যই ডিফল্টটির আগে উপস্থিত হওয়া উচিত তবে যখন পিতা-মাতার তর্কগুলি সন্তানের যুক্তি যুক্ত করার আগে আরম্ভ হয় তখন এটি কীভাবে সম্ভব?
মিস্টেরিও

4
দুর্ভাগ্যক্রমে এর আশেপাশে কোনও উপায় নেই বলে আমি মনে করি না। আমার বোধগম্যতা হল যদি পিতামাত্ত শ্রেণীর ডিফল্ট যুক্তি থাকে তবে কোনও শিশু শ্রেণীর অ-ডিফল্ট যুক্তি থাকতে পারে না।
প্যাট্রিক হাহ

4
আমি চিহ্নিত করার আগে আপনি কি উত্তরটিতে সেই তথ্য যুক্ত করতে পারেন? এটি একদিন কাউকে সাহায্য করবে। এটি বেশ দুর্ভাগ্যজনক যে ডেটাচ্লাসগুলির সীমাবদ্ধতা। এটি আমার বর্তমান অজগর প্রকল্পটি রেন্ডার করে। এই জাতীয় বাস্তবায়নগুলি দেখে ভাল লাগল
মিস্টেরিও

6

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

from dataclasses import dataclass, field

@dataclass
class Parent:
    name: str
    age: int
    ugly: bool = field(default=False, init=False)

@dataclass
class Child(Parent):
    school: str

jack = Parent('jack snr', 32)
jack_son = Child('jack jnr', 12, school = 'havard')
jack_son.ugly = True

আমি মনে করি এই উত্তরটি আরও স্বীকৃত হওয়া উচিত। এটি প্যারেন্ট ক্লাসে একটি ডিফল্ট ক্ষেত্র থাকার সমস্যাটি সমাধান করে, সুতরাং এটি টাইপআরার সরিয়ে দেয়।
নীলস বেঙ্গস্টসন

5

মার্তিজন পিটার সমাধানের ভিত্তিতে আমি নিম্নলিখিতটি করেছি:

1) পোস্ট_ইনিট বাস্তবায়ন করে একটি মিশ্রণ তৈরি করুন

from dataclasses import dataclass

no_default = object()


@dataclass
class NoDefaultAttributesPostInitMixin:

    def __post_init__(self):
        for key, value in self.__dict__.items():
            if value is no_default:
                raise TypeError(
                    f"__init__ missing 1 required argument: '{key}'"
                )

2) তারপরে উত্তরাধিকারের সমস্যা সহ ক্লাসগুলিতে:

from src.utils import no_default, NoDefaultAttributesChild

@dataclass
class MyDataclass(DataclassWithDefaults, NoDefaultAttributesPostInitMixin):
    attr1: str = no_default

সম্পাদনা:

একসময় পরে আমি এই মাইপি সহ এই সমাধান করতে সমস্যাগুলিও পাই, নিম্নলিখিত কোডটি সমস্যার সমাধান করে।

from dataclasses import dataclass
from typing import TypeVar, Generic, Union

T = TypeVar("T")


class NoDefault(Generic[T]):
    ...


NoDefaultVar = Union[NoDefault[T], T]
no_default: NoDefault = NoDefault()


@dataclass
class NoDefaultAttributesPostInitMixin:
    def __post_init__(self):
        for key, value in self.__dict__.items():
            if value is NoDefault:
                raise TypeError(f"__init__ missing 1 required argument: '{key}'")


@dataclass
class Parent(NoDefaultAttributesPostInitMixin):
    a: str = ""

@dataclass
class Child(Foo):
    b: NoDefaultVar[str] = no_default

আপনি কি "ক্লাস মাইডাটাক্লাস (ডেটাগ্লাস উইথডেফাল্টস, নোডাফল্টঅ্যাট্রিবিউটসপোস্টইনিটমিক্সিন)" উপরে লেখার পরিকল্পনা করেছিলেন 2)?
স্কট পি।

5

খাঁটি অজগর ব্যবহার করার সময় dataclassesএবং বেশি বয়লারপ্লেট কোড ছাড়াই নীচের পদ্ধতির সাথে এই সমস্যাটি দেখা যায় ।

ugly_init: dataclasses.InitVar[bool]একটি হিসেবে কাজ করে সিউডো-ক্ষেত্র শুধু আমাদের আরম্ভের এবং একবার উদাহরণস্বরূপ তৈরি করা হয় হারিয়ে যাবে সাহায্য করার জন্য। যদিও ugly: bool = field(init=False)এটি একটি সদস্য সদস্য যা __init__পদ্ধতি দ্বারা আরম্ভ করা হবে না তবে বিকল্পটি __post_init__পদ্ধতি ব্যবহার করে আরম্ভ করা যেতে পারে (আপনি এখানে আরও সন্ধান করতে পারেন ))।

from dataclasses import dataclass, field

@dataclass
class Parent:
    name: str
    age: int
    ugly: bool = field(init=False)
    ugly_init: dataclasses.InitVar[bool]

    def __post_init__(self, ugly_init: bool):
        self.ugly = ugly_init

    def print_name(self):
        print(self.name)

    def print_age(self):
        print(self.age)

    def print_id(self):
        print(f'The Name is {self.name} and {self.name} is {self.age} year old')

@dataclass
class Child(Parent):
    school: str

jack = Parent('jack snr', 32, ugly_init=True)
jack_son = Child('jack jnr', 12, school='havard', ugly_init=True)

jack.print_id()
jack_son.print_id()

আপনি যদি এমন কোনও প্যাটার্নটি ব্যবহার করতে চান যেখানে ugly_initalচ্ছিক, আপনি প্যারেন্টের উপর একটি শ্রেণিবদ্ধের সংজ্ঞা দিতে পারেন যা al ugly_initচ্ছিক পরামিতি হিসাবে অন্তর্ভুক্ত করে :

from dataclasses import dataclass, field, InitVar

@dataclass
class Parent:
    name: str
    age: int
    ugly: bool = field(init=False)
    ugly_init: InitVar[bool]

    def __post_init__(self, ugly_init: bool):
        self.ugly = ugly_init
    
    @classmethod
    def create(cls, ugly_init=True, **kwargs):
        return cls(ugly_init=ugly_init, **kwargs)

    def print_name(self):
        print(self.name)

    def print_age(self):
        print(self.age)

    def print_id(self):
        print(f'The Name is {self.name} and {self.name} is {self.age} year old')

@dataclass
class Child(Parent):
    school: str

jack = Parent.create(name='jack snr', age=32, ugly_init=False)
jack_son = Child.create(name='jack jnr', age=12, school='harvard')

jack.print_id()
jack_son.print_id()

এখন আপনি createডিফল্ট মান সহ পিতামাতাদের / শিশু ক্লাসগুলি তৈরির জন্য কারখানা পদ্ধতি হিসাবে ক্লাস পদ্ধতিটি ব্যবহার করতে পারেন ugly_init। নোট করুন কাজের জন্য এই পদ্ধতির জন্য আপনাকে অবশ্যই নামযুক্ত প্যারামিটার ব্যবহার করতে হবে।


ugly_init এখন কোনও ডিফল্ট নয় এমন প্রয়োজনীয় প্যারামিটার
ভাদিয়াম তায়মিরভ

2

আমি এই প্রশ্নে ফিরে এসেছি যে ডেটাগ্লাসগুলি আবিষ্কার করতে পারে একটি প্রসাধক প্যারামিটার ক্ষেত্র পুনর্বিন্যস্তভাবে হওয়ার অনুমতি দেয় পেয়ে যাবে। এটি অবশ্যই একটি আশাব্যঞ্জক বিকাশ, যদিও এই বৈশিষ্ট্যটির বিকাশ কিছুটা থামিয়ে দিয়েছে বলে মনে হচ্ছে।

এই মুহুর্তে, আপনি এই আচরণটি পেতে পারেন, সাথে সাথে ড্যাটাক্ল্যাসি ব্যবহার করে কিছু অন্যান্য চমত্কারতা অর্জন করতে পারেন , আমার এই ডেটাক্লাসগুলির পুনর্বিবেচনা যা এই জাতীয় হতাশা কাটিয়ে উঠেছে। মূল উদাহরণের from dataclassyজায়গায় ব্যবহার করার from dataclassesঅর্থ এটি ত্রুটি ছাড়াই চলে।

পরিদর্শন ব্যবহার করে স্বাক্ষর মুদ্রণের জন্য Childযা চলছে তা পরিষ্কার করে দেয়; ফলাফল হলো(name: str, age: int, school: str, ugly: bool = True) । ক্ষেত্রগুলি সর্বদা পুনঃক্রম হয় যাতে ডিফল্ট মান সহ ক্ষেত্রগুলি আরম্ভকারী পরামিতিগুলিতে বিনা ক্ষেত্রের পরে আসে। উভয় তালিকাগুলি (ডিফল্টবিহীন ক্ষেত্র এবং তাদের সাথে থাকা) এখনও সংজ্ঞা অনুসারে অর্ডার করা হয়েছে।

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


1

একটি সম্ভাব্য কাজ হ'ল মাতৃ ক্ষেত্রগুলি সংযোজন করার জন্য বানর-প্যাচিং ব্যবহার করা

import dataclasses as dc

def add_args(parent): 
    def decorator(orig):
        "Append parent's fields AFTER orig's fields"

        # Aggregate fields
        ff  = [(f.name, f.type, f) for f in dc.fields(dc.dataclass(orig))]
        ff += [(f.name, f.type, f) for f in dc.fields(dc.dataclass(parent))]

        new = dc.make_dataclass(orig.__name__, ff)
        new.__doc__ = orig.__doc__

        return new
    return decorator

class Animal:
    age: int = 0 

@add_args(Animal)
class Dog:
    name: str
    noise: str = "Woof!"

@add_args(Animal)
class Bird:
    name: str
    can_fly: bool = True

Dog("Dusty", 2)               # --> Dog(name='Dusty', noise=2, age=0)
b = Bird("Donald", False, 40) # --> Bird(name='Donald', can_fly=False, age=40)

চেক করে নন-ডিফল্ট ক্ষেত্রগুলি প্রিপেন্ড করাও সম্ভব if f.default is dc.MISSING, তবে এটি সম্ভবত খুব নোংরা।

বানর-প্যাচিংয়ে উত্তরাধিকারের কয়েকটি বৈশিষ্ট্য অভাবের পরেও এটি সমস্ত ছদ্ম-শিশু শ্রেণিতে পদ্ধতি যুক্ত করতে ব্যবহার করা যেতে পারে।

আরও সূক্ষ্ম-নিয়ন্ত্রণযুক্ত নিয়ন্ত্রণের জন্য ডিফল্ট মানগুলি ব্যবহার করে সেট করুন dc.field(compare=False, repr=True, ...)


1

আপনি ডেটাচ্লাসের একটি পরিবর্তিত সংস্করণ ব্যবহার করতে পারেন, যা কেবলমাত্র একটি কীওয়ার্ড __init__পদ্ধতি তৈরি করবে :

import dataclasses


def _init_fn(fields, frozen, has_post_init, self_name):
    # fields contains both real fields and InitVar pseudo-fields.
    globals = {'MISSING': dataclasses.MISSING,
               '_HAS_DEFAULT_FACTORY': dataclasses._HAS_DEFAULT_FACTORY}

    body_lines = []
    for f in fields:
        line = dataclasses._field_init(f, frozen, globals, self_name)
        # line is None means that this field doesn't require
        # initialization (it's a pseudo-field).  Just skip it.
        if line:
            body_lines.append(line)

    # Does this class have a post-init function?
    if has_post_init:
        params_str = ','.join(f.name for f in fields
                              if f._field_type is dataclasses._FIELD_INITVAR)
        body_lines.append(f'{self_name}.{dataclasses._POST_INIT_NAME}({params_str})')

    # If no body lines, use 'pass'.
    if not body_lines:
        body_lines = ['pass']

    locals = {f'_type_{f.name}': f.type for f in fields}
    return dataclasses._create_fn('__init__',
                      [self_name, '*'] + [dataclasses._init_param(f) for f in fields if f.init],
                      body_lines,
                      locals=locals,
                      globals=globals,
                      return_type=None)


def add_init(cls, frozen):
    fields = getattr(cls, dataclasses._FIELDS)

    # Does this class have a post-init function?
    has_post_init = hasattr(cls, dataclasses._POST_INIT_NAME)

    # Include InitVars and regular fields (so, not ClassVars).
    flds = [f for f in fields.values()
            if f._field_type in (dataclasses._FIELD, dataclasses._FIELD_INITVAR)]
    dataclasses._set_new_attribute(cls, '__init__',
                       _init_fn(flds,
                                frozen,
                                has_post_init,
                                # The name to use for the "self"
                                # param in __init__.  Use "self"
                                # if possible.
                                '__dataclass_self__' if 'self' in fields
                                else 'self',
                                ))

    return cls


# a dataclass with a constructor that only takes keyword arguments
def dataclass_keyword_only(_cls=None, *, repr=True, eq=True, order=False,
              unsafe_hash=False, frozen=False):
    def wrap(cls):
        cls = dataclasses.dataclass(
            cls, init=False, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen)
        return add_init(cls, frozen)

    # See if we're being called as @dataclass or @dataclass().
    if _cls is None:
        # We're called with parens.
        return wrap

    # We're called as @dataclass without parens.
    return wrap(_cls)

(এছাড়াও একটি হিসেবে পোস্ট সারকথা , পাইথন 3.6 গুলো পুরনো সাথে পরীক্ষিত)

এটির হিসাবে শিশু শ্রেণীর সংজ্ঞা দেওয়া দরকার

@dataclass_keyword_only
class Child(Parent):
    school: str
    ugly: bool = True

এবং উত্পন্ন করবে __init__(self, *, name:str, age:int, ugly:bool=True, school:str)(যা বৈধ অজগর)। এখানে কেবলমাত্র ক্যাভিয়েট স্থিতিগত আর্গুমেন্ট সহ বস্তুগুলিকে আরম্ভ করার অনুমতি দিচ্ছে না, তবে অন্যথায় এটি dataclassকোনও কুৎসিত হ্যাক ছাড়া সম্পূর্ণ নিয়মিত ।

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