سؤال

قد يكون هذا الأمر بالنسبة لمعظم اللغات بشكل عام، لكنني لست متأكدًا.أنا مبتدئ في Python وعملت دائمًا على نسخ القوائم في C# وVB.لكن في Python عندما أقوم بتمرير قائمة كوسيطة وأقوم بالتعداد من خلال استخدام "for i في النطاق"، ثم قم بتغيير قيمة وسيطة القائمة، فإن قيم الإدخال تغير فعليًا القائمة الأصلية.اعتقدت أنه كان من المفترض أن تقوم بايثون بتمرير الوسيطات حسب القيمة افتراضيًا، بحيث لا يزال لدي القيم الأصلية التي كانت موجودة قبل استدعاء الوظيفة بمجرد انتهاء الوظيفة.ماذا ينقصني؟شكرًا!

هل كانت مفيدة؟

المحلول

وبيثون يفعل الحجج تمريرة من قيمة ولكن القيمة التي يتم تلقي نسخة من المرجع (بالمناسبة هذا هو بالضبط نفس الطريقة التي C #، VB.NET تتصرف، وجافا، وكذلك).

وهذا هو الشيء المهم أن نتذكر:

<اقتباس فقرة>   

لا مرت كائنات بالرجوع - يتم تمرير مراجع الكائنات من حيث القيمة

ومنذ لديك نسخة من المرجع، أي عملية على ما أن النقاط المرجعية لستكون تماما كما لو كنت عقد الإشارة الأصلية نفسها.

نصائح أخرى

Python - تمامًا كما تفعل Java مع أي شيء ما عدا الكميات البدائية، ومثل C# وVB.NET تفعل مع معلمات النوع الافتراضية بدلاً من الأنواع المعبأة وparms out/ref - تمرر "حسب مرجع الكائن" (ابحث عن هذه العبارة هنا - هذه هي الطريقة التي يستخدمها جويدو، مهندس ومبدع بايثون، لشرح مفهوم تمرير الحجة).

كل اسم هو إشارة إلى كائن ما؛إن تمرير اسم (أو أي تعبير آخر) كوسيطة هو مجرد إنشاء مرجع آخر لنفس الكائن (الذي يمكن لجسم الوظيفة الوصول إليه من خلال اسم المعلمة).((ليس هناك شيء اسمه "إشارة إلى الاسم"):هناك أسماء, ، وهي نوع واحد من الإشارة إلى الكائنات، والكائن - الفترة)).

عندما تقوم بتمرير كائن قابل للتغيير، على سبيل المثال.التي تحتوي على أساليب تحور (مثل القائمة على سبيل المثال)، يمكن للوظيفة المستدعىة أن تحور الكائن عن طريق استدعاء أساليب التحور الخاصة به، بشكل مباشر أو غير مباشر.((أعني بـ "بشكل غير مباشر" "من خلال المشغلين" - على سبيل المثال:

somelist[len(somelist):] = [whatever]

مطابق تماما ل somelist.append(whatever).))

عندما تريد تمرير قائمة إلى وظيفة، ولكن افعل ذلك لا تريد أن تكون الوظيفة قادرة على تغيير تلك القائمة بأي شكل من الأشكال، يجب عليك تمرير ملف ينسخ من القائمة بدلاً من القائمة الأصلية - تمامًا كما هو الحال في Java وC# وVB.NET.

يكون جداً واضح حول التمييز بين إعادة ربط اسم و تحور كائن.إعادة ربط الاسم ("barename"، أي - الأسماء المؤهلة مختلفة؛-) فقط يؤثر على ذلك اسم -- لا أي كائن على الإطلاق.على سبيل المثال:

def f1(alist):
  alist = [23]

def f2(alist):
  alist[:] = [23]

هل يمكنك اكتشاف الفرق بين هاتين الوظيفتين؟واحد هو إعادة ربط com.barename alist - دون أي تأثير على الإطلاق على أي شيء.والآخر هو تحوير (تغيير، تغيير، ...) كائن القائمة الذي تلقاه كوسيطة - عن طريق تعيين محتواه ليكون قائمة مكونة من عنصر واحد مع int كعنصر وحيد. تماما، تماما أشياء مختلفة!!!

لإضافة إلى الإجابة أندرو، تحتاج إلى إجراء صراحة نسخة من القائمة إذا كنت ترغب في الاحتفاظ الأصلي. يمكنك القيام بذلك باستخدام وحدة copy، أو مجرد تفعل شيئا مثل

a = [1,2]
b = list(a)

ومنذ الأجسام نسخ وعادة ما يعني ضربة الأداء، وأجد أنه من المفيد استخدام صراحة وحدة نسخة في بلدي المشاريع الكبيرة. وبهذه الطريقة، ويمكنني أن تجد بسهولة جميع الأماكن حيث أنا ذاهب إلى استخدام مجموعة أكبر من الذاكرة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top