পাইথন পান্ডাস ডেটা ফ্রেম, এটি কি পাস-বাই-ভ্যালু বা পাস-বাই-রেফারেন্স


88

যদি আমি কোনও ফাংশনে ডেটাফ্রেম পাস করি এবং ফাংশনের অভ্যন্তরে এটি সংশোধন করি, তবে তা কী পাস-বাই-মান বা পাস-বাই-রেফারেন্স হয়?

আমি নিম্নলিখিত কোড চালাচ্ছি

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
def letgo(df):
    df = df.drop('b',axis=1)
letgo(a)

aফাংশন কল করার পরে এর মান পরিবর্তন হয় না। এর অর্থ কী এটি পাস-বাই-ভ্যালু?

আমি নিম্নলিখিত চেষ্টাও করেছিলাম

xx = np.array([[1,2], [3,4]])
def letgo2(x):
    x[1,1] = 100
def letgo3(x):
    x = np.array([[3,3],[3,3]])

এটি letgo2()পরিবর্তিত হয় না xxএবং letgo3()না। কেন এমন হয়?


উত্তর:


95

সংক্ষিপ্ত উত্তরটি হল, পাইথন সর্বদা পাস-বাই-মান করে তবে প্রতিটি পাইথন ভেরিয়েবল আসলে কোনও কোনও বস্তুর পয়েন্টার হয়, তাই কখনও কখনও এটি পাস-বাই-রেফারেন্সের মতো দেখায়।

পাইথনে প্রতিটি বস্তু হয় হয় পরিবর্তনীয় বা অ-পরিবর্তনীয়। উদাহরণস্বরূপ, তালিকাগুলি, ডিক্টস, মডিউল এবং পান্ডাস ডেটা ফ্রেমগুলি পারস্পরিক পরিবর্তনযোগ্য এবং ইনটস, স্ট্রিং এবং টিপলগুলি অ-পরিবর্তনীয়। পরিবর্তনীয় অবজেক্টগুলি অভ্যন্তরীণভাবে পরিবর্তিত হতে পারে (উদাহরণস্বরূপ, তালিকায় একটি উপাদান যুক্ত করুন), তবে অ-পরিবর্তনীয় অবজেক্টগুলি পারে না।

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

যদি আপনি মূল অবজেক্টটি পরিবর্তন করতে চান (কেবলমাত্র পরিবর্তনযোগ্য ডেটা ধরণের সাহায্যে সম্ভব), আপনাকে এমন কিছু করতে হবে যা স্থানীয় ভেরিয়েবলকে সম্পূর্ণ নতুন মান নির্ধারণ না করেই বস্তুকে পরিবর্তন করে দেয়। এ কারণেই letgo()এবং letgo3()বাহ্যিক আইটেমটি আনল্যাটারড ছেড়ে দিন, তবে letgo2()এটি পরিবর্তন করে।

যেমন @ উর্সান উল্লেখ করেছেন, letgo()পরিবর্তে যদি এরকম কিছু ব্যবহার করা হয়, তবে এটি মূল অবজেক্টকে পরিবর্তিত করতে (পরিবর্তন করতে) dfবদলে দেবে যা বিশ্বব্যাপী aভেরিয়েবলের মাধ্যমে দেখা মানকে পরিবর্তিত করবে :

def letgo(df):
    df.drop('b', axis=1, inplace=True)

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo(a)  # will alter a

কিছু ক্ষেত্রে, আপনি আসল ভেরিয়েবলটি পুরোপুরি ফাঁকা করে সরাসরি নতুন অ্যাসাইনমেন্ট না করেই এটি নতুন ডেটা দিয়ে পুনরায় পূরণ করতে পারেন, উদাহরণস্বরূপ এটি সেই মূল বস্তুকে বদলে দেবে vযা আপনি vপরে ব্যবহার করার সময় দেখা ডাটা পরিবর্তন করবে :

def letgo3(x):
    x[:] = np.array([[3,3],[3,3]])

v = np.empty((2, 2))
letgo3(v)   # will alter v

লক্ষ্য করুন যে আমি সরাসরি কিছু বরাদ্দ করছি না x; আমি পুরো অভ্যন্তরীণ পরিসীমাতে কিছু বরাদ্দ করছি x

যদি আপনার অবশ্যই একেবারে নতুন একটি অবজেক্ট তৈরি করা উচিত এবং এটি বাহ্যিকভাবে দৃশ্যমান করা উচিত (যা কখনও কখনও প্যান্ডাসের ক্ষেত্রেও হয়) আপনার কাছে দুটি বিকল্প রয়েছে। 'ক্লিন' বিকল্পটি কেবলমাত্র নতুন অবজেক্টটি ফিরিয়ে আনতে হবে, যেমন,

def letgo(df):
    df = df.drop('b',axis=1)
    return df

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
a = letgo(a)

অন্য বিকল্পটি হ'ল আপনার ফাংশনের বাইরে পৌঁছানো এবং সরাসরি একটি বৈশ্বিক পরিবর্তনশীল পরিবর্তন করা। এটি aএকটি নতুন অবজেক্টের দিকে নির্দেশ করতে পরিবর্তিত হয় এবং যে কোনও ক্রিয়াকলাপ aপরে উল্লেখ করা হয় সেই নতুন বস্তুটি দেখতে পাবে:

def letgo():
    global a
    a = a.drop('b',axis=1)

a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo()   # will alter a!

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


8

@ মাইক গ্রাহামের উত্তরে যোগ করতে, কে খুব ভাল পড়ার দিকে ইঙ্গিত করেছে:

আপনার ক্ষেত্রে, যা মনে রাখা গুরুত্বপূর্ণ তা হল নাম এবং মানগুলির মধ্যে পার্থক্য । a, df, xx, x, সব নাম , কিন্তু তারা একই বা ভিন্ন পড়ুন মান আপনার উদাহরণ বিভিন্ন পয়েন্ট হয়:

  • প্রথম উদাহরণে, অন্য letgo মানটিতে প্রত্যাবর্তন df করা হয়, কারণ আপনি যুক্তিটি সেট না করে ( ডক দেখুন ) df.dropনতুন করে দেয় returns এর অর্থ হ'ল নাম ( ফাংশনটির স্থানীয় ), যা মানটির কথা উল্লেখ করছিল , এখন একটি নতুন মানকে এখানে উল্লেখ করছে, এখানে ফেরতের মান। মানটি এখনও বিদ্যমান বলে উল্লেখ করা হচ্ছে এবং কোনও পরিবর্তন হয়নি।DataFrameinplace = Truedfletgoadf.dropa

  • দ্বিতীয় উদাহরণে, letgo2 mutates x , এটা rebinding ছাড়া কেন যা xxদ্বারা রুপান্তরিত করা হয়েছে letgo2। পূর্ববর্তী উদাহরণের বিপরীতে, এখানে স্থানীয় নামটি xসর্বদা নামটিকে উল্লেখ করা হচ্ছে এমন মানকে xxউল্লেখ করে এবং সেই স্থানে পরিবর্তিত হয় সেই কারণেই মানটি xxউল্লেখ করা হচ্ছে ring

  • তৃতীয় উদাহরণে, letgo3 rebinds x একটি নতুন np.array। এর ফলে নামটি xস্থানীয় হয় letgo3এবং পূর্বে এর মানটিকে উল্লেখ xxকরে এখন অন্য একটি মানকে নতুন হিসাবে উল্লেখ করে np.array। মান xxউল্লেখ করা হয়নি পরিবর্তিত।


7

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

পাইথনের নামগুলির সিস্টেম কী তা http://nedbatchelder.com/text/names.html খুব ভালভাবে ব্যাখ্যা করে।


4
পাইথনে পাসিং এবং অ্যাসাইনমেন্টের শব্দার্থকতা জাভা হিসাবে ঠিক একই রকম, এবং আপনি যে জিনিসগুলি বলেন সেটি জাভাতেও সমানভাবে প্রয়োগ করা যেতে পারে। তবুও স্ট্যাকওভারফ্লো এবং ইন্টারনেটের অন্য কোথাও লোকে আপাতদৃষ্টিতে আপনার উপর প্রভাবিত করতে এটি "আলোকিত" মনে করে যে এই সমস্যাটি যখনই আসে তখনই জাভা সর্বদা মান দ্বারা পাস হয়।
newacct

3

পাইথন মান দ্বারা পাস হয় না বা রেফারেন্স দ্বারা পাস হয় না। এটি অ্যাসাইনমেন্ট দ্বারা পাস হয়।

সমর্থনকারী রেফারেন্স, পাইথন এফএকিউ: https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-paraters-call-by-references

আইওউ:

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

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

ইজি:

def change_it(list_):
    # This change would be seen in the caller if we left it alone
    list_[0] = 28

    # This change is also seen in the caller, and replaces the above
    # change
    list_[:] = [1, 2]

    # This change is not seen in the caller.
    # If this were pass by reference, this change too would be seen in
    # caller.
    list_ = [3, 4]

thing = [10, 20]
change_it(thing)
# here, thing is [1, 2]

আপনি যদি সি ফ্যান হন তবে আপনি এটিকে মান দ্বারা একটি পয়েন্টার উত্তোলন হিসাবে ভাবতে পারেন - কোনও মানের কোনও পয়েন্টারের কাছে কোনও পয়েন্টার নয়, একটি মানের একটি পয়েন্টার।

এইচটিএইচ।


0

ড্রপ জন্য এখানে ডক:

অনুরোধীকৃত অক্ষগুলিতে লেবেল সহ নতুন বস্তুটি ফিরিয়ে দিন।

সুতরাং একটি নতুন তথ্য ফ্রেম তৈরি করা হয়। আসলটি পরিবর্তন হয়নি।

তবে পাইথনের সমস্ত অবজেক্টের জন্য তথ্য ফ্রেমটি রেফারেন্স দ্বারা ফাংশনে প্রেরণ করা হয়।


তবে আমি এটিকে dfফাংশনের অভ্যন্তরে নির্ধারিত করেছি , এর অর্থ এই নয় যে রেফারেন্সযুক্ত মানটি নতুন অবজেক্টে পরিবর্তিত হয়েছে?
নম্বর

একটি স্থানীয় নাম অর্পণ করা কখনই কোনও নামটিকে অন্য স্কোপের সাথে আবদ্ধ করা জিনিসটিকে পরিবর্তন করবে না।
মাইক গ্রাহাম

0

ফাংশনের শুরুতে আপনাকে 'একটি' গ্লোবাল তৈরি করতে হবে অন্যথায় এটি স্থানীয় পরিবর্তনশীল এবং মূল কোডটিতে 'এ' পরিবর্তন করে না।

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