python - "সংক্ষিপ্ত Astonishment" এবং পরিবর্তনযোগ্য ডিফল্ট আর্গুমেন্ট




language-design least-astonishment (20)

পাইথনের সাথে দীর্ঘ সময় ধরে যেকোনো টুকরো টুকরা করা হয়েছে নিম্নলিখিত বিষয়টির দ্বারা বাছাই করা হয়েছে (বা টুকরো টুকরা করা হয়েছে):

def foo(a=[]):
    a.append(5)
    return a

পাইথন উপন্যাসগুলি এই ফাংশনটি কেবলমাত্র একমাত্র উপাদানগুলির সাথে একটি তালিকাটি প্রত্যাবর্তনের আশা করবে: [5] । ফলাফল পরিবর্তে খুব ভিন্ন, এবং খুব বিস্ময়কর (একটি নববধূ জন্য):

>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()

আমার একজন ম্যানেজারের এই বৈশিষ্ট্যটির সাথে একবার তার প্রথম মুখোমুখি হয়েছিল এবং এটি "ভাষাটির একটি নাটকীয় নকশা ত্রুটি" হিসাবে পরিচিত ছিল। আমি উত্তর দিলাম যে আচরণটির অন্তর্নিহিত ব্যাখ্যা ছিল, এবং যদি আপনি অভ্যন্তরীণ বোঝেন না তবে এটি সত্যিই খুব বিরক্তিকর এবং অপ্রত্যাশিত। যাইহোক, আমি নিজেকে নিম্নলিখিত প্রশ্নের উত্তর দিতে পারিনি: ফাংশন সংজ্ঞাতে ডিফল্ট আর্গুমেন্টটি বাঁধার কারন কি? আমি অভিজ্ঞ আচরণের একটি ব্যবহারিক ব্যবহার আছে সন্দেহ (যারা প্রকৃতপক্ষে সি স্ট্যাটিক ভেরিয়েবল ব্যবহৃত, বাগ প্রজনন ছাড়া?)

সম্পাদনা করুন :

Baczek একটি আকর্ষণীয় উদাহরণ তৈরি। একসাথে আপনার বেশিরভাগ মন্তব্য এবং উটালের সাথে আমি আরও বিস্তারিতভাবে ব্যাখ্যা করেছি:

>>> def a():
...     print("a executed")
...     return []
... 
>>>            
>>> def b(x=a()):
...     x.append(5)
...     print(x)
... 
a executed
>>> b()
[5]
>>> b()
[5, 5]

আমার কাছে মনে হচ্ছে নকশাটির সিদ্ধান্তটি প্যারামিটারের সুযোগ কোথায় রাখে তার সাথে সম্পর্কিত ছিল: ফাংশনের ভিতরে বা "একসঙ্গে" এর সাথে?

ফাংশনের ভেতর বাঁধাই করা মানে অর্থাত্ x কার্যকরভাবে নির্ধারিত ডিফল্টের সাথে আবদ্ধ থাকে যখন ফাংশন বলা হয়, সংজ্ঞায়িত না হয় এমন কিছু যা একটি গভীর ত্রুটি প্রদর্শন করবে: def "সংকর" (ফাংশন অবজেক্টের) ফাংশন আমন্ত্রণ সময়তে সংজ্ঞা, এবং অংশ (ডিফল্ট পরামিতি বরাদ্দ) ঘটবে।

প্রকৃত আচরণ আরও সামঞ্জস্যপূর্ণ: যে লাইনটি কার্যকর করা হয়, সেই লাইনের সবকিছু মূল্যায়ন করা হয়, অর্থ ফাংশন সংজ্ঞাতে।


পাইথন প্রতিরক্ষা 5 পয়েন্ট

  1. সরলতা : আচরণটি নিম্নলিখিত অর্থে সহজ: বেশিরভাগ লোকই এই ফাঁদে পড়ে একাধিকবার নয়।

  2. ধারাবাহিকতা : পাইথন সবসময় বস্তু, নাম না পাস। ডিফল্ট প্যারামিটার অবশ্যই, ফাংশন শিরোনামের অংশ (ফাংশন শরীর নয়)। তাই এটি মডিউল লোড সময় (এবং শুধুমাত্র মডিউল লোড সময়, ন্যস্ত না হওয়া পর্যন্ত) এ ফাংশন কল সময়, মূল্যায়ন করা উচিত।

  3. ব্যবহারযোগ্যতা : ফ্রেডেরিক লুন্ন্ড "পাইথনয়ের ডিফল্ট পরামিতি মানগুলি" এর ব্যাখ্যাতে উল্লেখ করেছেন, বর্তমান আচরণ উন্নত প্রোগ্রামিংয়ের জন্য বেশ উপযোগী হতে পারে। (সতর্কতার সাথে অল্পকরে ব্যবহার করা.)

  4. পর্যাপ্ত ডকুমেন্টেশন : সবচেয়ে মৌলিক পাইথন ডকুমেন্টেশনের ক্ষেত্রে, টিউটোরিয়াল, এই বিষয়টিকে " ফাংশন নির্ধারণের আরও বেশি " বিভাগের প্রথম উপবিভাগে "গুরুত্বপূর্ণ সতর্কতা" হিসাবে ঘোষণা করা হয়। সতর্কতা এমনকি boldface ব্যবহার করে, যা খুব কমই শিরোনামের বাইরে প্রয়োগ করা হয়। RTFM: জরিমানা ম্যানুয়াল পড়ুন।

  5. মেটা-লার্নিং : ফাঁদে ফাটানো আসলে একটি খুব সহায়ক মুহূর্ত (অন্তত যদি আপনি প্রতিফলিত শিখি হন), কারণ পরবর্তীকালে আপনি উপরে "সঙ্গতিপূর্ণ" বিন্দুটি আরও ভালভাবে বুঝতে পারবেন এবং এটি আপনাকে পাইথন সম্পর্কে অনেক কিছু শেখাবে।


স্থাপত্য

একটি ফাংশন কল ডিফল্ট মান নির্ধারণ একটি কোড গন্ধ হয়।

def a(b=[]):
    pass

এটি একটি ফাংশনের স্বাক্ষর যা কোনও ভাল নয়। শুধু অন্যান্য উত্তর দ্বারা বর্ণিত সমস্যা নয়। আমি যে এখানে যেতে হবে না।

এই ফাংশন দুটি জিনিস করতে লক্ষ্য। একটি নতুন তালিকা তৈরি করুন, এবং একটি কার্যকারিতা চালানো, সর্বাধিক বলা তালিকা উপর।

আমরা দুটি ধাপে কাজ করি এমন ফাংশন হল খারাপ ফাংশন, যেমন আমরা পরিষ্কার কোড অনুশীলন থেকে শিখি।

পলিমারফিজমের সাথে এই সমস্যাটি আক্রমণ করলে, আমরা পাইথন তালিকাটি প্রসারিত করব অথবা একটি শ্রেণীতে মোড়ানো করব, তারপরে আমাদের ফাংশনটি সম্পাদন করব।

কিন্তু আপনি অপেক্ষা করুন বলে, আমি আমার এক liners পছন্দ।

ভাল, অনুমান কি। কোড হার্ডওয়্যার আচরণ নিয়ন্ত্রণ করার একটি উপায় চেয়ে বেশি। এটি একটি উপায়:

  • একই কোড কাজ, অন্যান্য ডেভেলপারদের সঙ্গে যোগাযোগ।

  • নতুন প্রয়োজনীয়তা দেখা দেয় যখন হার্ডওয়্যার আচরণ পরিবর্তন করতে সক্ষম হচ্ছে।

  • উপরের উল্লিখিত পরিবর্তনটি করার জন্য দুই বছরের পর আবার কোডটি নেওয়ার পরে প্রোগ্রামটির প্রবাহ বুঝতে সক্ষম হবেন।

পরে বাছাই করার জন্য সময়-বোমা ত্যাগ করবেন না।

এই ফাংশনটিকে দুটি জিনিসতে আলাদা করে, আমাদের একটি শ্রেণির প্রয়োজন

class ListNeedsFives(object):
    def __init__(self, b=None):
        if b is None:
            b = []
        self.b = b

    def foo():
        self.b.append(5)

দ্বারা চালিত

a = ListNeedsFives()
a.foo()
a.b

এবং কেন সব উপরে কোড একটি একক ফাংশন mashing চেয়ে ভাল।

def dontdothis(b=None):
    if b is None:
        b = []
    b.append(5)
    return b

কেন এই না?

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

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

পদ্ধতি foo()তালিকায় ফিরে আসে না কেন?

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

def dontdothis(b=None):স্বাক্ষর ফাংশন এই সুবিধার কেউই হয়েছে।


কেন আপনি আত্মসমর্পণ না?

আমি সত্যিই অবাক হলাম যে কেউ কাউকেবেলগুলিতে পাইথন ( 2 এবং 3 প্রযোজ্য) দ্বারা উপলব্ধ অন্তর্দৃষ্টিপূর্ণ অন্তর্নিহিতকরণ সম্পাদন করেনি।

একটি সাধারণ সামান্য ফাংশন func হিসাবে সংজ্ঞায়িত:

>>> def func(a = []):
...    a.append(5)

পাইথন যখন এটির মুখোমুখি হয়, তখন এটি প্রথম কাজটি করবে এই ফাংশনের জন্য code অবজেক্ট তৈরি করার জন্য। এই সংকলন পদক্ষেপটি সম্পন্ন করা হলেও, পাইথন মূল্যায়ন করে এবং তারপর ফাংশন বস্তুর মধ্যে ডিফল্ট আর্গুমেন্টগুলি (একটি খালি তালিকা [] এখানে সঞ্চয় করে) । শীর্ষ উত্তর উল্লিখিত: তালিকাটি এখন ফাংশন func একটি সদস্য হিসাবে বিবেচনা করা যেতে পারে।

সুতরাং, কিছু অন্তর্নিহিতকরণ, কীভাবে ফাংশন অবজেক্টের ভিতরে তালিকাটি প্রসারিত হয় তা পরীক্ষা করার আগে এবং পরে। আমি Python 3.x ব্যবহার করছি, পাইথন 2 এর জন্য একই প্রযোজ্য (পাইথন 2 এ __defaults__ বা func_defaults ব্যবহার করুন; হ্যাঁ, একই জিনিসটির জন্য দুটি নাম)।

এক্সিকিউশন আগে ফাংশন:

>>> def func(a = []):
...     a.append(5)
...     

পাইথন এই সংজ্ঞাটি কার্যকর করার পরে এটি কোনও ডিফল্ট প্যারামিটার নির্দিষ্ট করে দেবে ( a = [] এখানে) এবং ফাংশন অবজেক্টের জন্য __defaults__ বৈশিষ্ট্যতে __defaults__ করে __defaults__ (প্রাসঙ্গিক বিভাগ: কল্যাবল):

>>> func.__defaults__
([],)

ঠিক আছে, সুতরাং __defaults__ একক এন্ট্রি হিসাবে একটি খালি তালিকা, ঠিক যেমন প্রত্যাশিত।

এক্সিকিউশন করার পরে ফাংশন:

আসুন এখন এই ফাংশনটি চালানো যাক:

>>> func()

এখন, ঐ __defaults__ আবার দেখা যাক:

>>> func.__defaults__
([5],)

বিস্মিত? বস্তুর ভিতরে মান পরিবর্তন! ফাংশন পরিবর্তনশীল কল এখন কেবল যে এমবেডেড list বস্তুর যোগ করা হবে:

>>> func(); func(); func()
>>> func.__defaults__
([5, 5, 5, 5],)

সুতরাং, সেখানে আপনার আছে, কেন এই 'ত্রুটি' ঘটে, কারণ ডিফল্ট আর্গুমেন্ট ফাংশন অবজেক্টের অংশ। এখানে অদ্ভুত কিছু যাচ্ছে না, এটি সব কিছু মাত্র বিস্ময়কর।

এটিকে মোকাবেলা করার সাধারণ সমাধানটি ডিফল্ট হিসাবে None ব্যবহার করা হয় না এবং ফাংশন শরীরের মধ্যে শুরু করা হয়:

def func(a = None):
    # or: a = [] if a is None else a
    if a is None:
        a = []

যেহেতু ফাংশন শরীরটি প্রতিবার নতুন করে নির্বাহিত হয়, তাই যদি আপনি কোনও আর্গুমেন্ট পাস না করেন তবে আপনি সর্বদা একটি নতুন খালি তালিকা পাবেন।

__defaults__ এর তালিকাটি ফাংশন func ব্যবহৃত যেটি একই হিসাবে যাচাই করতে আপনি ফাংশন শরীরের ভিতরে ব্যবহৃত তালিকাটির id ফেরত দিতে আপনার ফাংশনটি কেবলমাত্র পরিবর্তন করতে পারেন। তারপরে, __defaults__ ( __defaults__ অবস্থান [0]__defaults__ সাথে __defaults__ ) এবং আপনি দেখতে পাবেন যে কীভাবে এটি একই তালিকা উদাহরণে আসলেই রেফার করছে:

>>> def func(a = []): 
...     a.append(5)
...     return id(a)
>>>
>>> id(func.__defaults__[0]) == func()
True

আত্মসমর্পণ ক্ষমতা দিয়ে সব!

* পিনথন ফাংশন সংকলনের সময় ডিফল্ট আর্গুমেন্টগুলি মূল্যায়ন করে যাচাই করতে, নিম্নলিখিতটি কার্যকর করার চেষ্টা করুন:

def bar(a=input('Did you just see me without calling the function?')): 
    pass  # use raw_input in Py2

হিসাবে আপনি লক্ষ্য করবেন, input() ফাংশন নির্মাণের প্রক্রিয়া এবং নাম bar এটি বাঁধাই করার আগে বলা হয়।


AFAICS এখনো কেউ documentation প্রাসঙ্গিক অংশ পোস্ট করেনি:

ফাংশন সংজ্ঞা কার্যকর করা হয় যখন ডিফল্ট পরামিতি মান মূল্যায়ন করা হয়। এর অর্থ হল এক্সপ্রেশনটি একবার একবার মূল্যায়ন করা হয়, যখন ফাংশনটি সংজ্ঞায়িত করা হয় এবং একই কল "পূর্ব-গণিত" প্রতিটি কলটির জন্য ব্যবহৃত হয়। ডিফল্ট প্যারামিটারটি একটি পরিবর্তনযোগ্য বস্তু, যেমন একটি তালিকা বা অভিধান হিসাবে বুঝার জন্য বিশেষত গুরুত্বপূর্ণ: যদি ফাংশন বস্তুটি সংশোধন করে (যেমন একটি তালিকাতে আইটেম যুক্ত করে), ডিফল্ট মানটি কার্যত সংশোধন করা হয়। এই সাধারণত কি উদ্দেশ্যে ছিল না। এর চারপাশে একটি উপায় ডিফল্ট হিসাবে কেউ ব্যবহার করা হয় না, এবং ফাংশন শরীরের জন্য স্পষ্টভাবে এটি পরীক্ষা [...]


আপনি কি জিজ্ঞাসা করছেন কেন এই:

def func(a=[], b = 2):
    pass

অভ্যন্তরীণভাবে এই সমান নয়:

def func(a=None, b = None):
    a_default = lambda: []
    b_default = lambda: 2
    def actual_func(a=None, b=None):
        if a is None: a = a_default()
        if b is None: b = b_default()
    return actual_func
func = func()

স্পষ্টভাবে ফনক্ক (কোনটি, কিছুই না) কল করার ক্ষেত্রে, যা আমরা উপেক্ষা করব।

অন্য কথায়, ডিফল্ট প্যারামিটারগুলি মূল্যায়ন করার পরিবর্তে, কেন তাদের প্রত্যেককে সঞ্চয় করবেন না এবং ফাংশনটি কবে তাদের মূল্যায়ন করবেন?

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


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

1. পারফরম্যান্স

def foo(arg=something_expensive_to_compute())):
    ...

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

2. আবদ্ধ পরামিতি বাধ্যতামূলক

Lambda তৈরি করা হয় যখন একটি পরিবর্তনশীল বর্তমান বাঁধাই একটি Lambda পরামিতি আবদ্ধ করা একটি দরকারী কৌশল। উদাহরণ স্বরূপ:

funcs = [ lambda i=i: i for i in range(10)]

এটি ফাংশনগুলির একটি তালিকা প্রদান করে যা যথাক্রমে 0,1,2,3 ... প্রদান করে। আচরণ পরিবর্তিত হলে, i পরিবর্তে i কল-সময় মানকে বাঁধাই করব, তাই আপনি ফাংশনগুলির একটি তালিকা পাবেন যা সমস্ত 9 ফিরে এসেছে।

অন্যথায় এই বাস্তবায়ন করার একমাত্র উপায় আমি আবদ্ধ সঙ্গে আরও বন্ধ করতে হবে, অর্থাত্:

def make_func(i): return lambda: i
funcs = [make_func(i) for i in range(10)]

3. অন্তর্নিহিতকরণ

কোড বিবেচনা করুন:

def foo(a='test', b=100, c=[]):
   print a,b,c

আমরা inspect মডিউল ব্যবহার করে আর্গুমেন্ট এবং ডিফল্ট সম্পর্কে তথ্য পেতে পারেন, যা

>>> inspect.getargspec(foo)
(['a', 'b', 'c'], None, None, ('test', 100, []))

এই তথ্য ডকুমেন্ট প্রজন্ম, মেটাপ্রোগ্রামিং, সজ্জা ইত্যাদি বিষয়গুলির জন্য খুব দরকারী।

এখন, অনুমান করুন যে ডিফল্টের আচরণ পরিবর্তিত হতে পারে যাতে এটি সমান হয়:

_undefined = object()  # sentinel value

def foo(a=_undefined, b=_undefined, c=_undefined)
    if a is _undefined: a='test'
    if b is _undefined: b=100
    if c is _undefined: c=[]

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


এই আচরণ দ্বারা সহজ ব্যাখ্যা করা হয়:

  1. ফাংশন (বর্গ ইত্যাদি) ঘোষণা শুধুমাত্র একবার কার্যকর করা হয়, সমস্ত ডিফল্ট মান বস্তু তৈরি
  2. সবকিছু রেফারেন্স দ্বারা গৃহীত হয়

তাই:

def x(a=0, b=[], c=[], d=0):
    a = a + 1
    b = b + [1]
    c.append(1)
    print a, b, c
  1. a পরিবর্তন হয় না - প্রতিটি নিয়োগ কল নতুন int বস্তু তৈরি করে - নতুন বস্তু মুদ্রিত হয়
  2. b পরিবর্তন হয় না - নতুন অ্যারে ডিফল্ট মান থেকে তৈরি এবং মুদ্রিত হয়
  3. c পরিবর্তন - অপারেশন একই বস্তুর সঞ্চালিত হয় - এবং এটি মুদ্রিত হয়

ধরুন আপনি নিম্নলিখিত কোড আছে

fruits = ("apples", "bananas", "loganberries")

def eat(food=fruits):
    ...

যখন আমি খাওয়ার ঘোষণাটি দেখি, তখন অন্তত বিস্ময়কর জিনিসটি ভাবতে হবে যে যদি প্রথম পরামিতি দেওয়া না হয় তবে এটি টিপলে ("apples", "bananas", "loganberries") সমান হবে।

তবে, কোড পরে পরে অনুমিত, আমি কিছু ভালো

def some_random_function():
    global fruits
    fruits = ("blueberries", "mangos")

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

আসল সমস্যাটি পরিবর্তনযোগ্য ভেরিয়েবলগুলির সাথে রয়েছে, এবং সমস্ত ভাষার কিছুটা সমস্যা রয়েছে। এখানে একটি প্রশ্ন আছে: জাভাতে অনুমান করুন আমার নিম্নলিখিত কোড আছে:

StringBuffer s = new StringBuffer("Hello World!");
Map<StringBuffer,Integer> counts = new HashMap<StringBuffer,Integer>();
counts.put(s, 5);
s.append("!!!!");
System.out.println( counts.get(s) );  // does this work?

মানচিত্রের মধ্যে স্থাপন করা হলে StringBuffer কীটির মান এখন আমার মানচিত্র ব্যবহার করে, নাকি এটি রেফারেন্স দ্বারা কী সঞ্চয় করে? উভয় উপায়, কেউ অবাক হয়; যে ব্যক্তিটি Map থেকে বস্তুটিকে তার সাথে যুক্ত করে এমন একটি মান ব্যবহার করে বস্তুটি ব্যবহার করার চেষ্টা করে, অথবা যে ব্যক্তিটি তার অবজেক্টটি পুনরুদ্ধার করতে পারে বলে মনে হচ্ছে না সেটি ব্যবহার করে এমন কীটি আসলেই একই বস্তুটিকে মানচিত্রে ঢুকানোর জন্য ব্যবহার করা হয়েছিল (এটি আসলেই পাইথন তার পরিবর্তনযোগ্য অন্তর্নির্মিত ডাটা প্রকারগুলিকে অভিধান কী হিসাবে ব্যবহার করার অনুমতি দেয় না)।

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

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


এটি একটি নকশা ত্রুটি নয় । যে কেউ এই উপর ভ্রমণ করে কিছু ভুল করছেন।

3 টি ক্ষেত্রে আমি দেখি যেখানে আপনি এই সমস্যাটি চালাতে পারেন:

  1. আপনি ফাংশনের একটি পার্শ্ব প্রতিক্রিয়া হিসাবে যুক্তি পরিবর্তন করতে ইচ্ছুক। এই ক্ষেত্রে এটি একটি ডিফল্ট যুক্তি আছে জ্ঞান করে তোলে না । একমাত্র ব্যতিক্রমটি যখন আপনি ক্রিয়াকলাপের বৈশিষ্ট্যগুলির জন্য যুক্তি তালিকার অপব্যবহার করছেন, উদাহরণস্বরূপ cache={}, এবং আপনি কোনও প্রকৃত যুক্তি সহ ফাংশনটি কল করার প্রত্যাশিত হবেন না।
  2. আপনি unmodified যুক্তি ছেড়ে মনস্থ করা, কিন্তু আপনি ঘটনাক্রমে এটি সংশোধন করেছেন। এটি একটি বাগ, এটা ঠিক।
  3. আপনি ফাংশনের ভেতর ব্যবহারের জন্য যুক্তি সংশোধন করতে চান তবে ফাংশনটির বাইরে পরিবর্তনটি দর্শনযোগ্য হওয়ার আশা রাখেন না। সেই ক্ষেত্রে আপনাকে যুক্তিটির একটি অনুলিপি তৈরি করতে হবে, তা ডিফল্ট কিনা বা না! পাইথন কল-বাই-মান ভাষা নয় তাই এটি আপনার জন্য অনুলিপি তৈরি করে না, আপনাকে এটি সম্পর্কে স্পষ্ট হতে হবে।

প্রশ্নটির উদাহরণটি 1 বা 3 নম্বর শ্রেণীতে পড়তে পারে। এটি বিজোড় যে এটি উভয় পাশে তালিকা পরিবর্তন করে এবং এটি ফেরত দেয়; আপনি এক বা অন্য বাছাই করা উচিত।


আপনি নিম্নলিখিত বিবেচনার মধ্যে নিতে যদি এই আচরণ বিস্ময়কর নয়:

  1. পাঠ্য-শুধুমাত্র শ্রেণির আচরণ বরাদ্দ প্রচেষ্টা, এবং যে উপর বৈশিষ্ট্য
  2. ফাংশন বস্তু (গৃহীত উত্তর ভাল ব্যাখ্যা)।

ভূমিকা (2) এই থ্রেড ব্যাপকভাবে আচ্ছাদিত করা হয়েছে। (1) সম্ভবত বিস্ময়কর কারণের কারণ, যেহেতু অন্যান্য ভাষা থেকে আসার সময় এই আচরণ "স্বজ্ঞাত" নয়।

(1) ক্লাসে পাইথন টিউটোরিয়ালে বর্ণিত হয়েছে । শুধুমাত্র পঠনযোগ্য শ্রেণির গুণাবলীতে একটি মান বরাদ্দ করার প্রচেষ্টাতে:

... সর্বাধিক সুযোগের বাইরে পাওয়া সমস্ত ভেরিয়েবলগুলি কেবল পঠনযোগ্য (এই ধরনের পরিবর্তনশীলকে লিখার একটি প্রচেষ্টা কেবলমাত্র অন্তর্বর্তী স্কোপে একটি নতুন স্থানীয় পরিবর্তনশীল তৈরি করবে, যা একইভাবে বাইরের পরিবর্তনশীল বাইরের পরিবর্তনশীলকে ছাড়িয়ে যাবে )।

মূল উদাহরণ ফিরে তাকান এবং উপরের পয়েন্ট বিবেচনা করুন:

def foo(a=[]):
    a.append(5)
    return a

এখানে fooএকটি বস্তু এবং aএকটি বৈশিষ্ট্য foo(এ উপলব্ধ foo.func_defs[0])। যেহেতু aএকটি তালিকা, aপরিবর্তনযোগ্য এবং এইভাবে একটি পড়ার-লিখুন বৈশিষ্ট্য foo। ফাংশনটি তাত্ক্ষণিকভাবে স্বাক্ষর অনুসারে নির্দিষ্ট খালি তালিকাতে শুরু হয় এবং যতক্ষণ ফাংশন অবজেক্ট বিদ্যমান থাকে ততক্ষণ এটি পড়ার এবং লেখার জন্য উপলব্ধ।

fooডিফল্ট মান থেকে একটি ডিফল্ট ব্যবহার overriding ছাড়া কলিং foo.func_defs। এই ক্ষেত্রে, ফাংশন বস্তুর কোড সুযোগের foo.func_defs[0]জন্য ব্যবহৃত হয় a। পরিবর্তনের aপরিবর্তন foo.func_defs[0], যা fooবস্তুর অংশ এবং কোডটি কার্যকর করার ক্ষেত্রে চলতে থাকে foo

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

def foo(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

গ্রহণ (1) এবং (2) অ্যাকাউন্টে, কেউ দেখতে পারেন কেন এটি পছন্দসই আচরণ সম্পাদন করে:

  • যখন fooফাংশন বস্তুর তাত্ক্ষণিক foo.func_defs[0]হয় None, একটি অপরিবর্তনীয় বস্তু সেট করা হয় ।
  • যখন ফাংশনটি ডিফল্টের সাথে সম্পাদিত হয় ( Lফাংশন কলটিতে নির্দিষ্ট কোন প্যারামিটার সহ ), foo.func_defs[0]( None) এটি স্থানীয় দশা হিসাবে উপলব্ধ L
  • উপর L = [], অ্যাসাইনমেন্ট সফল হতে পারে না foo.func_defs[0], কারণ যে বৈশিষ্ট্য শুধুমাত্র-পড়া হয়।
  • প্রতি (1) , স্থানীয় স্থানীয় ভেরিয়েবল নামেও একটি নতুন স্থানীয় পরিবর্তনশীল Lতৈরি করা হয় এবং ফাংশন কলটির বাকি অংশের জন্য ব্যবহৃত হয়। foo.func_defs[0]এইভাবে ভবিষ্যতে invocations জন্য অপরিবর্তিত রয়ে যায় foo

আমরা যখন এটা করি:

def foo(a=[]):
    ...

... যদি aকোনও নামহীন নাম না দেয় তবে আমরা একটি নামহীন তালিকাতে যুক্তি পেশ করি ।

এই আলোচনার জন্য আরও সহজ করতে, আসুন সাময়িকভাবে নামহীন তালিকাটি একটি নাম দিন। কিভাবে সম্পর্কে pavlo?

def foo(a=pavlo):
   ...

যে কোনও সময়ে, যদি আহ্বায়ক আমাদের জানান না a, আমরা পুনঃব্যবহার করি pavlo

যদি pavloপরিবর্তনযোগ্য (সংশোধনযোগ্য) হয়, এবং fooএটি সংশোধন করা শেষ হয়, আমরা একটি প্রভাব fooনির্দিষ্ট সময় নোটিশ ছাড়াই বলা হয় যে বিজ্ঞপ্তি a

সুতরাং আপনি যা দেখেন তা (মনে রাখবেন, pavlo[[]] তে শুরু হয়েছে:

 >>> foo()
 [5]

এখন, pavlo[5]।

কলিং foo()আবার আবার সংশোধন pavlo:

>>> foo()
[5, 5]

নির্দিষ্ট করা aযখন কলিং foo()নিশ্চিত pavloছোঁয়া দিচ্ছে না।

>>> ivan = [1, 2, 3, 4]
>>> foo(a=ivan)
[1, 2, 3, 4, 5]
>>> ivan
[1, 2, 3, 4, 5]

তাই, pavloএখনও [5, 5]

>>> foo()
[5, 5, 5]

আমি একটি ফাংশন একটি ডিফল্ট তালিকা মান পাস করার জন্য একটি বিকল্প গঠন প্রদর্শন করতে যাচ্ছি (এটি অভিধান সঙ্গে সমানভাবে ভাল কাজ করে)।

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

ভুল পদ্ধতি (সম্ভবত ...) :

def foo(list_arg=[5]):
    return list_arg

a = foo()
a.append(6)
>>> a
[5, 6]

b = foo()
b.append(7)
# The value of 6 appended to variable 'a' is now part of the list held by 'b'.
>>> b
[5, 6, 7]  

# Although 'a' is expecting to receive 6 (the last element it appended to the list),
# it actually receives the last element appended to the shared list.
# It thus receives the value 7 previously appended by 'b'.
>>> a.pop()             
7

আপনি এটি ব্যবহার করে এক এবং একই বস্তুর যাচাই করতে পারেন id:

>>> id(a)
5347866528

>>> id(b)
5347866528

প্রতি ব্রেট স্ল্যাটিকিনের "কার্যকরী পাইথন: আরও ভাল প্যাথন লেখার 59 টি নির্দিষ্ট উপায়", আইটেম ২0: Noneগতিশীল ডিফল্ট আর্গুমেন্টগুলি নির্দিষ্ট করতে ব্যবহার এবং ডকস্ট্রিংগুলি (পৃষ্ঠা 48)

পাইথন এ পছন্দসই ফলাফল অর্জনের জন্য কনভেনশনটি Noneডকস্ট্রিংয়ের প্রকৃত আচরণের একটি ডিফল্ট মান এবং নথি সরবরাহ করা।

এই বাস্তবায়ন নিশ্চিত করে যে প্রতিটি ফাংশনটিতে কলটি ডিফল্ট তালিকা পায় বা অন্যথায় ফাংশনটি প্রেরিত হয়।

পছন্দের পদ্ধতি :

def foo(list_arg=None):
   """
   :param list_arg:  A list of input values. 
                     If none provided, used a list with a default value of 5.
   """
   if not list_arg:
       list_arg = [5]
   return list_arg

a = foo()
a.append(6)
>>> a
[5, 6]

b = foo()
b.append(7)
>>> b
[5, 7]

c = foo([10])
c.append(11)
>>> c
[10, 11]

'ভুল পদ্ধতি' এর জন্য বৈধ ব্যবহার ক্ষেত্রে হতে পারে যেখানে প্রোগ্রামারটি ডিফল্ট তালিকা প্যারামিটারটি ভাগ করে নেওয়ার উদ্দেশ্যে ব্যবহার করে, তবে এটি নিয়মটির চেয়ে ব্যতিক্রম।


আমি মাঝে মাঝে নিচের প্যাটার্নের বিকল্প হিসাবে এই আচরণটি শোষণ করি:

singleton = None

def use_singleton():
    global singleton

    if singleton is None:
        singleton = _make_singleton()

    return singleton.use_me()

যদি singletonশুধুমাত্র ব্যবহার করা হয় use_singleton, আমি প্রতিস্থাপন হিসাবে নিম্নলিখিত প্যাটার্ন পছন্দ করি:

# _make_singleton() is called only once when the def is executed
def use_singleton(singleton=_make_singleton()):
    return singleton.use_me()

আমি বহিরাগত সম্পদ অ্যাক্সেস ক্লায়েন্ট ক্লাস তাত্ক্ষণিক জন্য, এবং memoization জন্য ডিক্ট বা তালিকা তৈরি করার জন্য এই ব্যবহার করেছি।

যেহেতু আমি মনে করি না এই প্যাটার্নটি সুপরিচিত, ভবিষ্যতে ভুল বোঝাবুঝির বিরুদ্ধে সতর্ক থাকার জন্য আমি একটি সংক্ষিপ্ত মন্তব্য করি।


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

def bar(a=[]):
     print id(a)
     a = a + [1]
     print id(a)
     return a

>>> bar()
4484370232
4484524224
[1]
>>> bar()
4484370232
4484524152
[1]
>>> bar()
4484370232 # Never change, this is 'class property' of the function
4484523720 # Always a new object 
[1]
>>> id(bar.func_defaults[0])
4484370232

এটা সত্য হতে পারে যে:

  1. কেউ প্রতি ভাষা / লাইব্রেরি বৈশিষ্ট্য ব্যবহার করা হয়, এবং
  2. এখানে আচরণ স্যুইচিং খারাপ পরামর্শ দেওয়া হবে, কিন্তু

এটি উপরের উভয় বৈশিষ্ট্য ধরে রাখা সম্পূর্ণরূপে সামঞ্জস্যপূর্ণ এবং এখনও অন্য বিন্দু তৈরি করে:

  1. এটি একটি বিভ্রান্তিকর বৈশিষ্ট্য এবং এটি পাইথন মধ্যে দুর্ভাগ্যজনক।

অন্যান্য উত্তর, অথবা কমপক্ষে কিছু তাদের পয়েন্ট 1 এবং 2 কিন্তু 3 নয়, বা পয়েন্ট 3 এবং ডাউনপ্লে পয়েন্ট 1 এবং 2 করে। কিন্তু তিনটি সত্য।

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

বিদ্যমান আচরণ Pythonic নয়, এবং পাইথন সফল হয় কারণ ভাষা সম্পর্কে খুব সামান্য যে কোন জায়গায় বিস্ময়ের ন্যূনতম সূত্র লঙ্ঘন কাছাকাছিএই খারাপ। এটি একটি বাস্তব সমস্যা, এটি বাজেয়াপ্ত করা বিজ্ঞ হবে কিনা। এটি একটি নকশা ত্রুটি। আচরণটি খুঁজে বের করার চেষ্টা করে আপনি ভাষাটি আরও ভালভাবে বুঝতে পারলে, আমি বলতে পারি যে C ++ এই সমস্ত এবং আরও কিছু করে; আপনি নেভিগেট করার দ্বারা অনেক কিছু শিখতে পারেন, উদাহরণস্বরূপ, সূক্ষ্ম পয়েন্টার ত্রুটি। কিন্তু এটি পাইথনিক নয়: যারা এই পদ্ধতির মুখোমুখি হওয়ার জন্য যথেষ্ট পিয়থনকে যত্নশীল, তারা এমন ভাষা যারা ভাষাতে টেনে নিয়ে যায় কারণ পাইথনটি অন্য ভাষার তুলনায় অনেক কম আশ্চর্য। Dabblers এবং অদ্ভুত Pythonistas হয়ে ওঠে যখন তারা কিছু কাজ পেতে কত সময় লাগে তা অবাক হয়ে যায় - কোনও নকশা ফ্লিনের অর্থ নয় - লুকানো যুক্তিযুক্ত ধাঁধা - যা পাইথনে আঁকা প্রোগ্রামারদের অন্তর্দৃষ্টিগুলির বিরুদ্ধে ছেয়ে যায় কারণ এটি শুধু কাজ করে


কেউ ব্যবহার করে একটি সহজ কাজকর্ম

>>> def bar(b, data=None):
...     data = data or []
...     data.append(b)
...     return data
... 
>>> bar(3)
[3]
>>> bar(3)
[3]
>>> bar(3)
[3]
>>> bar(3, [34])
[34, 3]
>>> bar(3, [34])
[34, 3]

শুধু ফাংশন পরিবর্তন হতে:

>>> def a():
>>>    print "a executed"
>>>    return []
>>> x =a()
a executed
>>> def b(m=[]):
>>>    m.append(5)
>>>    print m
>>> b(x)
[5]
>>> b(x)
[5, 5]

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

উদাহরণ:

def foo(a=[]):                 # the same problematic function
    a.append(5)
    return a

>>> somevar = [1, 2]           # an example without a default parameter
>>> foo(somevar)
[1, 2, 5]
>>> somevar
[1, 2, 5]                      # usually expected [1, 2]

সমাধান : একটি অনুলিপি
একটি একেবারে নিরাপদ সমাধান copyবা deepcopyইনপুট বস্তুর প্রথম এবং তারপর অনুলিপি দিয়ে যা করতে হবে।

def foo(a=[]):
    a = a[:]     # a copy
    a.append(5)
    return a     # or everything safe by one line: "return a + [5]"

অনেক builtin চপল ধরনের মত একটি কপি পদ্ধতি আছে some_dict.copy()বা some_set.copy()অথবা মত সহজ অনুলিপি করা যায় somelist[:]বা list(some_list)। প্রতিটি বস্তুর দ্বারা আরও অনুলিপি করা যেতে পারে copy.copy(any_object)অথবা আরও পুঙ্খানুপুঙ্খভাবে copy.deepcopy()(অপব্যবহারযোগ্য বস্তু পরিবর্তনযোগ্য অবজেক্ট থেকে তৈরি করা হলে পরবর্তীটি দরকারী)। কিছু বস্তুগুলি মৌলিকভাবে "ফাইল" বস্তুর মতো পার্শ্ব প্রতিক্রিয়াগুলির উপর ভিত্তি করে এবং অনুলিপি দ্বারা অর্থপূর্ণভাবে পুনরুত্পাদন করা যাবে না। copying

অনুরূপ SO প্রশ্নের জন্য উদাহরণ সমস্যা

class Test(object):            # the original problematic class
  def __init__(self, var1=[]):
    self._var1 = var1

somevar = [1, 2]               # an example without a default parameter
t1 = Test(somevar)
t2 = Test(somevar)
t1._var1.append([1])
print somevar                  # [1, 2, [1]] but usually expected [1, 2]
print t2._var1                 # [1, 2, [1]] but usually expected [1, 2]

এটি এই ফাংশনের দ্বারা প্রদত্ত একটি উদাহরণের কোনও সার্বজনীন বৈশিষ্ট্যগুলিতে সংরক্ষণ করা উচিত নয় । (অনুমানের যে ব্যক্তিগত বৈশিষ্ট্যগুলি এই ক্লাস বা উপশ্রেণীগুলির বাইরে থেকে সংশোধন করা উচিত নয়, _var1যেমন একটি ব্যক্তিগত বৈশিষ্ট্য)

উপসংহার:
ইনপুট প্যারামিটার বস্তুগুলি স্থানান্তরিত করা উচিত নয় (পরিবর্তিত) না এবং ফাংশন দ্বারা ফেরত আসা বস্তুর মধ্যে আবদ্ধ করা উচিত নয়। (যদি আমরা দৃঢ়ভাবে সুপারিশ না করে পার্শ্ব প্রতিক্রিয়া ছাড়াই প্রোগ্রামিং পছন্দ করি। উইকি দেখুন "পার্শ্ব প্রতিক্রিয়া" (প্রথম দুটি অনুচ্ছেদ এই প্রসঙ্গে প্রকাশ করা হয়।)।)

2)
প্রকৃত প্যারামিটারের পার্শ্ব প্রতিক্রিয়া কেবলমাত্র ডিফল্ট প্যারামিটারে অযাচিত থাকলে কেবল দরকারী সমাধানটি def ...(var1=None): if var1 is None: var1 = [] More..

3) কিছু ক্ষেত্রে ডিফল্ট পরামিতিগুলির পরিবর্তনযোগ্য আচরণ দরকারী


এটি একটি কর্মক্ষমতা অপ্টিমাইজেশান। এই কার্যকারিতাটির ফলস্বরূপ, এই দুটি ফাংশন কলগুলির মধ্যে আপনি কোনটি দ্রুত মনে করেন?

def print_tuple(some_tuple=(1,2,3)):
    print some_tuple

print_tuple()        #1
print_tuple((1,2,3)) #2

আমি আপনাকে একটি ইঙ্গিত দিতে হবে। এখানে disassembly ( http://docs.python.org/library/dis.html ):

# 1

0 LOAD_GLOBAL              0 (print_tuple)
3 CALL_FUNCTION            0
6 POP_TOP
7 LOAD_CONST               0 (None)
10 RETURN_VALUE

# 2

 0 LOAD_GLOBAL              0 (print_tuple)
 3 LOAD_CONST               4 ((1, 2, 3))
 6 CALL_FUNCTION            1
 9 POP_TOP
10 LOAD_CONST               0 (None)
13 RETURN_VALUE

আমি অভিজ্ঞ আচরণের একটি ব্যবহারিক ব্যবহার আছে সন্দেহ (যারা প্রকৃতপক্ষে সি স্ট্যাটিক ভেরিয়েবল ব্যবহৃত, বাগ প্রজনন ছাড়া?)

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


সংক্ষিপ্ততম উত্তর সম্ভবত "সংজ্ঞা কার্যকর করা" হবে, তাই পুরো যুক্তি কোন কঠোর ধারণা দেয় না। একটি আরো রূপান্তরিত উদাহরণ হিসাবে, আপনি এই উদ্ধৃত করতে পারেন:

def a(): return []

def b(x=a()):
    print x

আশা করা যায় যে defবিবৃতি কার্যকর করার সময় ডিফল্ট আর্গুমেন্ট এক্সপ্রেশনগুলি নির্বাহ করাটি সহজ নয় বা বোঝা বা উভয়ই নয় তা দেখানোর জন্য যথেষ্ট ।

যদিও আপনি ডিফল্ট কন্সট্রকটার ব্যবহার করার চেষ্টা করেন তবে এটি একটি গোচচা সম্মত হয়।





least-astonishment