পাইথন পরিবর্তনীয় ডিফল্ট যুক্তি: কেন?


20

আমি জানি যে ফাংশন আরম্ভের সময় ডিফল্ট আর্গুমেন্ট তৈরি করা হয় এবং প্রতিটি সময় ফাংশনটি বলা হয় না। নিম্নলিখিত কোডটি দেখুন:

def ook (item, lst=[]):
    lst.append(item)
    print 'ook', lst

def eek (item, lst=None):
    if lst is None: lst = []
    lst.append(item)
    print 'eek', lst

max = 3
for x in xrange(max):
    ook(x)

for x in xrange(max):
    eek(x)

আমি যা পাই না তা হ'ল এটি কেন এইভাবে প্রয়োগ করা হয়েছিল। এই আচরণটি প্রতিটি কল সময়ে একটি সূচনাতে কী সুবিধা দেয়?


এটি ইতিমধ্যে স্ট্যাক ওভারফ্লো সম্পর্কে বিস্ময়কর বিশদে আলোচনা করা হয়েছে : stackoverflow.com/q/1132941/5419599
ওয়াইল্ডকার্ড

উত্তর:


14

আমি মনে করি কারণটি বাস্তবায়নের সরলতা। আমাকে বিস্তারিত জানাতে দিন।

ফাংশনের ডিফল্ট মান হল এমন একটি অভিব্যক্তি যা আপনাকে মূল্যায়ন করতে হবে। আপনার ক্ষেত্রে এটি একটি সাধারণ অভিব্যক্তি যা বন্ধের উপর নির্ভর করে না, তবে এটি এমন কিছু হতে পারে যাতে ফ্রি ভেরিয়েবলগুলি থাকে - def ook(item, lst = something.defaultList())। যদি আপনি পাইথন ডিজাইন করতে চান তবে আপনার একটি পছন্দ থাকবে - ফাংশনটি সংজ্ঞায়িত হয়ে গেলে বা ফাংশনটি যখন ডাকা হয় তখন প্রতিবার আপনি একবার এটি মূল্যায়ন করেন। পাইথন প্রথমটি বেছে নেয় (রুবির বিপরীতে যা দ্বিতীয় বিকল্পের সাথে যায়)।

এর জন্য কিছু সুবিধা রয়েছে।

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

আর একটি সুবিধা হ'ল সরলতা। ভাবটি কীভাবে মূল্যায়ন করা হয় তা বোঝা বেশ সহজ - ফাংশনটি সংজ্ঞায়িত করার সময় এটি লেজিকাল স্কোপ ব্যবহার করে। যদি তারা অন্যভাবে চলে যায় তবে সংজ্ঞা এবং অনুরোধের মধ্যে লেজিক স্কোপ পরিবর্তন হতে পারে এবং এটি ডিবাগ করা কিছুটা শক্ত করে তোলে। সেই ক্ষেত্রে পাইথন চূড়ান্তভাবে সোজা হতে দীর্ঘ পথ পাড়ি দেয়।


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

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

সুযোগ সম্পর্কে ভাল পয়েন্ট
0xc0de

আমি মনে করি সুযোগটি আরও গুরুত্বপূর্ণ বিট। যেহেতু আপনি ডিফল্টর জন্য ধ্রুবকগুলিতে সীমাবদ্ধ নন তাই আপনার জন্য এমন ভেরিয়েবলের প্রয়োজন হতে পারে যা কল সাইটে সুযোগ নেই।
মার্ক রান্সম

5

এটি দেওয়ার একটি উপায় হ'ল প্যারামিটারটি পরিবর্তন lst.append(item) করে নাlstlstএখনও একই তালিকা রেফারেন্স। এটি কেবলমাত্র সেই তালিকার সামগ্রীটি পরিবর্তিত হয়েছে।

মূলত পাইথনের কোনও ধ্রুবক বা অপরিবর্তনীয় ভেরিয়েবল মোটেই থাকে না - তবে এর কিছু ধ্রুবক, অপরিবর্তনীয় প্রকার রয়েছে। আপনি একটি পূর্ণসংখ্যার মানটি পরিবর্তন করতে পারবেন না, আপনি কেবল এটি প্রতিস্থাপন করতে পারবেন। তবে আপনি কোনও লিস্টের স্থান পরিবর্তন না করে কোনও লিখিত সামগ্রী পরিবর্তন করতে পারেন can

একটি পূর্ণসংখ্যার মতো, আপনি কোনও রেফারেন্স সংশোধন করতে পারবেন না, আপনি কেবল এটি প্রতিস্থাপন করতে পারেন। তবে আপনি রেফারেন্স করা অবজেক্টের সামগ্রীটি পরিবর্তন করতে পারেন।

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


+1 একদম ঠিক। ইন্ডিয়ারেশনের স্তরটি বোঝা গুরুত্বপূর্ণ - যে কোনও ভেরিয়েবলের মান হয় না ; পরিবর্তে এটি একটি মান উল্লেখ করে । একটি ভেরিয়েবল পরিবর্তন করতে, মানটি অদলবদল করা যেতে পারে , বা পরিবর্তন করতে পারে (যদি তা পরিবর্তনীয় হয়)।
জুনাস পুলক্কা

পাইথনটিতে ভেরিয়েবল জড়িত এমন কোনও জটিল সমস্যার মুখোমুখি হয়ে গেলে, আমি "=" কে "নাম-বাঁধাইকারী অপারেটর" হিসাবে বিবেচনা করা সহায়ক মনে করি; নামটি সর্বদা রিবাউন্ড হয়, আমরা যে জিনিসটিকে এটি বেঁধে রাখছি তা নতুন (তাজা অবজেক্ট বা অপরিবর্তনীয় টাইপের উদাহরণ) কিনা।
স্টারওয়েভার

4

এই আচরণটি প্রতিটি কল সময়ে একটি সূচনাতে কী সুবিধা দেয়?

এটি আপনার পছন্দসই আচরণটি নির্বাচন করতে দেয়, যেমন আপনি উদাহরণ হিসাবে দেখিয়েছেন। সুতরাং যদি আপনি চান যে ডিফল্ট যুক্তিটি অপরিবর্তনীয়, আপনি একটি অপরিবর্তনীয় মান ব্যবহার করেন , যেমন Noneবা 1। আপনি যদি ডিফল্ট আর্গুমেন্টকে পরিবর্তনীয় করতে চান তবে আপনি কিছু পরিবর্তনীয়, যেমন ব্যবহার করুন []। এটি কেবল নমনীয়তা, যদিও স্বীকার করে নিন, আপনি এটি না জানলে এটি কামড় ফেলতে পারে।


2

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

a = []
for i in range(3):
    a.append(lambda: i)
print [ f() for f in a ]

যা দেয় [2, 2, 2]যেখানে আপনি একটি সত্য অবসান উত্পাদন করতে আশা [0, 1, 2]

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

def foo(a, b=a.b):
    ...

চূড়ান্ত কার্যকর হতে পারে তবে ফাংশন সংজ্ঞা সময় "ক" এর সুযোগ নেই, সুতরাং আপনি এটি করতে পারবেন না এবং তার পরিবর্তে খড়মুটি করতে হবে:

def foo(a, b=None):
    if b is None:
        b = a.b

যা প্রায় একই জিনিস ... প্রায়।



1

একটি বিশাল সুবিধা স্মৃতিচারণ। এটি একটি আদর্শ উদাহরণ:

def fibmem(a, cache={0:1,1:1}):
    if a in cache: return cache[a]
    res = fib(a-1, cache) + fib(a-2, cache)
    cache[a] = res
    return res

এবং তুলনার জন্য:

def fib(a):
    if a == 0 or a == 1: return 1
    return fib(a-1) + fib(a-2)

আইপথনে সময় পরিমাপ:

In [43]: %time print(fibmem(33))
5702887
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 200 µs

In [43]: %time print(fib(33))
5702887
CPU times: user 1.44 s, sys: 15.6 ms, total: 1.45 s
Wall time: 1.43 s

0

এটি ঘটে কারণ পাইথনে সংকলন বর্ণনামূলক কোড সম্পাদন করে সম্পাদিত হয়।

কেউ যদি বলেন

def f(x = {}):
    ....

এটি বেশ পরিষ্কার হবে যে আপনি প্রতিবার একটি নতুন অ্যারে চেয়েছিলেন।

তবে আমি যদি বলি:

list_of_all = {}
def create(stuff, x = list_of_all):
    ...

এখানে আমি অনুমান করব যে আমি বিভিন্ন তালিকায় স্টাফ তৈরি করতে চাই এবং যখন আমি তালিকাটি নির্দিষ্ট না করি তখন একক বিশ্বব্যাপী ক্যাচ-অল থাকি।

তবে সংকলকটি কীভাবে এটি অনুমান করবে? তাহলে কেন চেষ্টা করবেন? আমরা এটির নামকরণ হয়েছিল কিনা তার উপর নির্ভর করতে পারি এবং এটি কখনও কখনও সহায়তা করতে পারে তবে সত্যই এটি অনুমান করা হবে। একই সময়ে, চেষ্টা না করার একটি ভাল কারণ রয়েছে - ধারাবাহিকতা।

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

আমরা যদি নামযুক্ত কেস থেকে নামবিহীন পার্থক্য করতে চাই, যেটি সংকলনের সময় কোডটি রান-টাইমে মৃত্যুদন্ড কার্যকর হওয়ার চেয়ে কার্যকরভাবে নির্ধারিত কার্য সম্পাদনে অন্তর্ভুক্ত করবে। তাই আমরা বিশেষ কেসটি করি না।


-5

এটি ঘটে কারণ পাইথনে ফাংশনগুলি প্রথম শ্রেণির অবজেক্ট :

ফাংশন সংজ্ঞা কার্যকর করা হলে ডিফল্ট প্যারামিটার মানগুলি মূল্যায়ন করা হয়। এর অর্থ হ'ল অভিব্যক্তিটি একবার মূল্যায়ন করা হয় , যখন ফাংশনটি সংজ্ঞায়িত হয় এবং প্রতিটি কলের জন্য একই "প্রাক-গণিত" মান ব্যবহৃত হয় ।

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

যার অর্থ এটি def foo(l=[])যখন কল করা হয় তখন সেই ফাংশনের একটি উদাহরণ হয়ে ওঠে এবং পরবর্তী কলগুলির জন্য পুনরায় ব্যবহৃত হয়। কোনও অবজেক্টের বৈশিষ্ট্যগুলি বাদ দিয়ে ফাংশন পরামিতিগুলি ভাবেন।

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

class Foo(object):
    def bar(self, l=None):
        if not l:
            l = []
        l.append(5)
        return l

f = Foo()
print(f.bar())
print(f.bar())

g = Foo()
print(g.bar())
print(g.bar())

উৎপাদনের:

[৫] [৫] [৫] [৫]

অপ্রত্যাশিত পরিবর্তে:

[৫] [৫, ৫] [৫, ৫, ৫] [৫, ৫, ৫, ৫]


5
না। আপনি প্রতিটি কলের জন্য আবার ডিফল্ট আর্গুমেন্ট এক্সপ্রেশন মূল্যায়নের জন্য ফাংশনগুলি (প্রথম শ্রেণির বা না) আলাদাভাবে সংজ্ঞায়িত করতে পারেন। এবং তারপরে সমস্ত কিছুই, অর্থাৎ উত্তরের প্রায় 90%, পুরোপুরি প্রশ্নের পাশে রয়েছে। -1

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

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

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