পাইথনে উদাহরণস্বরূপ ভেরিয়েবলগুলির জন্য আমি কীভাবে ডিফল্ট মানগুলি ঘোষণা করব?


90

আমি কি আমার শ্রেণীর সদস্যদের এই জাতীয় ডিফল্ট মান দিতে পারি:

class Foo:
    num = 1

বা এই মত?

class Foo:
    def __init__(self):
        self.num = 1

ইন এই প্রশ্নের আমি উভয় ক্ষেত্রেই আবিষ্কার করেন যে,

bar = Foo()
bar.num += 1

একটি ভাল সংজ্ঞায়িত অপারেশন।

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

একটি জিনিস আমি লক্ষ্য করেছি যে জাজানো টিউটোরিয়ালে তারা মডেলগুলি ঘোষণার জন্য দ্বিতীয় পদ্ধতিটি ব্যবহার করে। ব্যক্তিগতভাবে আমি মনে করি যে দ্বিতীয় পদ্ধতিটি আরও মার্জিত, তবে আমি 'স্ট্যান্ডার্ড' উপায়টি কী তা জানতে চাই।

উত্তর:


132

বিপির উত্তর প্রসারিত করে, আমি আপনাকে দেখাতে চেয়েছিলাম যে তিনি অপরিবর্তনীয় প্রকারের দ্বারা কী বোঝাতে চেয়েছিলেন।

প্রথমত, এটি ঠিক আছে:

>>> class TestB():
...     def __init__(self, attr=1):
...         self.attr = attr
...     
>>> a = TestB()
>>> b = TestB()
>>> a.attr = 2
>>> a.attr
2
>>> b.attr
1

তবে এটি কেবলমাত্র অপরিবর্তনীয় (অপরিবর্তনীয়) প্রকারের জন্য কাজ করে। যদি ডিফল্ট মানটি পরিবর্তনীয় হয় (যার অর্থ এটি প্রতিস্থাপন করা যায়) তবে এটি পরিবর্তে ঘটবে:

>>> class Test():
...     def __init__(self, attr=[]):
...         self.attr = attr
...     
>>> a = Test()
>>> b = Test()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[1]
>>> 

উভয় নোট করুন aএবং bএকটি ভাগ বৈশিষ্ট্য আছে। এটি প্রায়শই অযাচিত হয়।

এই উদাহরণটি পরিবর্তনশীলগুলির জন্য ডিফল্ট মান নির্ধারণ করার পাইথোনিক উপায়, যখন প্রকারটি পরিবর্তনীয় হয়:

>>> class TestC():
...     def __init__(self, attr=None):
...         if attr is None:
...             attr = []
...         self.attr = attr
...     
>>> a = TestC()
>>> b = TestC()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[]

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


4
আমি সম্প্রতি পরিবর্তনীয় বৈশিষ্ট্যের জন্য ডিফল্ট মানগুলি প্রয়োগ করার খুব সহজ উপায়টি পেয়েছি। শুধু পদ্ধতির self.attr = attr or []মধ্যে লিখুন __init__। এটি একই ফলাফল অর্জন করে (আমি মনে করি) এবং এখনও স্পষ্ট এবং পঠনযোগ্য।
বিল

4
দুঃখিত লোকেরা। আমি আমার উপরে মন্তব্যে পরামর্শের উপর আরো কিছু গবেষণা করেছেন এবং আপাতদৃষ্টিতে এটি পুরোপুরি একই না করা হয়েছে প্রস্তাবিত নয়
বিল 18

ক্লাস টেস্টসির ফাঁকা বন্ধনী রয়েছে কেন? এটি কি পাইথন 2 উত্তরাধিকার?
ক্রিসজি

55

দুটি স্নিপেট বিভিন্ন জিনিস করে, তাই এটি স্বাদের বিষয় নয় তবে আপনার প্রসঙ্গে সঠিক আচরণটি কী তা নয়। পাইথন ডকুমেন্টেশন পার্থক্য ব্যাখ্যা করে, তবে এখানে কয়েকটি উদাহরণ দেওয়া হল:

একটি প্রদর্শনী

class Foo:
  def __init__(self):
    self.num = 1

এটি numফু উদাহরণগুলির সাথে আবদ্ধ । এই ক্ষেত্রে পরিবর্তন অন্যান্য দৃষ্টান্তে প্রচারিত হয় না।

এইভাবে:

>>> foo1 = Foo()
>>> foo2 = Foo()
>>> foo1.num = 2
>>> foo2.num
1

প্রদর্শন বি

class Bar:
  num = 1

এটি numবার শ্রেণীর সাথে আবদ্ধ । পরিবর্তন প্রচারিত হয়!

>>> bar1 = Bar()
>>> bar2 = Bar()
>>> bar1.num = 2 #this creates an INSTANCE variable that HIDES the propagation
>>> bar2.num
1
>>> Bar.num = 3
>>> bar2.num
3
>>> bar1.num
2
>>> bar1.__class__.num
3

আসল উত্তর

যদি আমার ক্লাস ভেরিয়েবলের প্রয়োজন না হয় তবে কেবলমাত্র আমার ইনস্ট্যান্স ভেরিয়েবলের জন্য একটি ডিফল্ট মান সেট করা দরকার, উভয় পদ্ধতি কি সমানভাবে ভাল? নাকি তাদের একজনের চেয়ে অপরটির চেয়ে বেশি 'পাইথোনিক'?

বি এর কোডটি কোড এর জন্য পরিষ্কার ভুল: আপনি কেন একটি শ্রেণীর বৈশিষ্ট্য (উদাহরণস্বরূপ সৃষ্টিতে ডিফল্ট মান) বাঁধতে চান?

এ-তে প্রদর্শিত কোডটি ঠিক আছে।

আপনি যদি আপনার কনস্ট্রাক্টরে উদাহরণস্বরূপ ভেরিয়েবলের জন্য ডিফল্ট দিতে চান তবে আমি এটি করব:

class Foo:
  def __init__(self, num = None):
    self.num = num if num is not None else 1

...অথবা এমনকি:

class Foo:
  DEFAULT_NUM = 1
  def __init__(self, num = None):
    self.num = num if num is not None else DEFAULT_NUM

... বা এমনকি: (পছন্দনীয়, তবে এবং যদি কেবলমাত্র আপনি অপরিবর্তনীয় ধরণের সাথেই আচরণ করছেন!)

class Foo:
  def __init__(self, num = 1):
    self.num = num

এইভাবে আপনি করতে পারেন:

foo1 = Foo(4)
foo2 = Foo() #use default

4
এই উদাহরণটিতে ব্যবহৃত সূচনা পদ্ধতিটি কি আন্ডারস্কোর___ইনিট_উইন্ডস্কোর থেকে শুরু করে @ বিডাব্ল্যাপি
এলিথেসিয়ান

প্রথম উদাহরণটি হওয়া উচিত নয়def __init__(self, num = None)
পাইওয়ালার 2797

6

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

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

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


3

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

>>> class c:
...     l = []
... 
>>> x = c()
>>> y = c()
>>> x.l
[]
>>> y.l
[]
>>> x.l.append(10)
>>> y.l
[10]
>>> c.l
[10]

শুধুমাত্র প্রথমদিকে []প্রায় ক্লোন করা ছাড়া ; x.lএবং y.lদু'টিই দু'জনের নাম এবং একই সাথে পৃথক পৃথক মান। (ভাষার উকিল শর্তাবলী গঠিত)
ফিলিপ

1

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

>>> class TestClass(object):
...     t = None
... 
>>> test = TestClass()
>>> test.t
>>> test2 = TestClass()
>>> test.t = 'test'
>>> test.t
'test'
>>> test2.t
>>>

এছাড়াও যদি আপনার ডিফল্ট প্রয়োজন হয়:

>>> class TestClassDefaults(object):
...    t = None
...    def __init__(self, t=None):
...       self.t = t
... 
>>> test = TestClassDefaults()
>>> test.t
>>> test2 = TestClassDefaults([])
>>> test2.t
[]
>>> test.t
>>>

অবশ্যই এখনও ডিফল্ট হিসাবে পরিবর্তনীয় বনাম অপরিবর্তনীয় প্রকারের ব্যবহার সম্পর্কে অন্যান্য উত্তরের তথ্য অনুসরণ করুন __init__


0

সঙ্গে dataclasses , একটি বৈশিষ্ট্য পাইথন 3.7 যোগ, সেখানে এখন আরেকটি (বেশ সুবিধাজনক) পথ বর্গ দৃষ্টান্ত ডিফল্ট মান নির্ধারণের অর্জন হয়। সাজসজ্জারটি dataclassস্বয়ংক্রিয়ভাবে আপনার ক্লাসে কয়েকটি পদ্ধতি তৈরি করবে যেমন কনস্ট্রাক্টর। উপরের নোটগুলির সাথে ডকুমেন্টেশনের লিঙ্ক হিসাবে, "[টি] তিনি এই উত্পন্ন পদ্ধতিতে ব্যবহারের জন্য ভেরিয়েবলগুলি পিইপি 526 প্রকারের টিকা ব্যবহার করে সংজ্ঞায়িত হন "।

ওপির উদাহরণ বিবেচনা করে আমরা এটি এর মতো প্রয়োগ করতে পারি:

from dataclasses import dataclass

@dataclass
class Foo:
    num: int = 0

এই শ্রেণীর ধরণের একটি অবজেক্ট তৈরি করার সময় আমরা বিকল্পটি মানটিকে ওভাররাইট করতে পারি।

print('Default val: {}'.format(Foo()))
# Default val: Foo(num=0)
print('Custom val: {}'.format(Foo(num=5)))
# Custom val: Foo(num=5)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.