দুটি তালিকার প্রতিযোগিতা করা - '+ =' এবং প্রসারিত () এর মধ্যে পার্থক্য


243

আমি দেখেছি পাইথনে তালিকাগুলি সংযুক্ত করার জন্য দুটি (সম্ভবত আরও বেশি) উপায় রয়েছে: একটি উপায় হ'ল প্রসারিত () পদ্ধতিটি ব্যবহার করা:

a = [1, 2]
b = [2, 3]
b.extend(a)

প্লাস (+) অপারেটরটি ব্যবহার করার জন্য অন্যটি:

b += a

এখন আমি ভাবছি: এই দুটি অপশনের মধ্যে কোনটি পাইথোনিকের জন্য তালিকাবদ্ধকরণের উপায় এবং এই দুটিয়ের মধ্যে কোনও পার্থক্য রয়েছে (আমি সরকারী পাইথনের টিউটোরিয়ালটি দেখেছি তবে এই বিষয় সম্পর্কে কিছুই খুঁজে পাইনি)।


1
ডাকটিপিংয়ের ক্ষেত্রে পার্থক্যটির আরও বেশি প্রভাব রয়েছে এবং যদি আপনার সম্ভবত-না-আসলে-তালিকার মতো-কিন্তু-এর মতো একটি তালিকা সমর্থন করে .__iadd__()/ .__add__()/ .__radd__()বনাম.extend()
নিক টি

উত্তর:


214

বাইটকোড স্তরের একমাত্র পার্থক্য হ'ল উপায়টিতে .extendএকটি ফাংশন কল জড়িত, যা পাইথনের চেয়ে কিছুটা ব্যয়বহুল INPLACE_ADD

আপনি কোটি কোটি বার এই অপারেশনটি সম্পাদন না করা ছাড়া আপনার সত্যিকারের চিন্তিত হওয়া উচিত নয়। সম্ভবত, সম্ভবত যে বাধাটি অন্য কোনও জায়গায় থাকবে।


16
ডাকটিপিংয়ের ক্ষেত্রে পার্থক্যটির আরও বেশি প্রভাব রয়েছে এবং যদি আপনার সম্ভবত-না-আসলে-তালিকার মতো-তবে-এর মতো একটি তালিকা সমর্থন করে .__iadd__()/ .__add__()/ .__radd__()বনাম.extend()
নিক টি

8
এই উত্তরটি গুরুত্বপূর্ণ স্কোপিং পার্থক্য উল্লেখ করতে ব্যর্থ।
wim

3
প্রকৃতপক্ষে, প্রসারগুলি INPLACE_ADD () অর্থাত্ তালিকার উপসংহারের চেয়ে দ্রুত। gist.github.com/mekarpeles/3408081
আর্কিট কাপুর

178

আপনি অ-লোকাল ভেরিয়েবলের জন্য + = ব্যবহার করতে পারবেন না (ভেরিয়েবল যা ফাংশনের জন্য স্থানীয় নয় এবং বৈশ্বিকও নয়)

def main():
    l = [1, 2, 3]

    def foo():
        l.extend([4])

    def boo():
        l += [5]

    foo()
    print l
    boo()  # this will fail

main()

এটি কারণ প্রসারিত ক্ষেত্রে সংকলক নির্দেশ lব্যবহার করে চলকটি লোড করবে LOAD_DEREF, তবে + = এর জন্য এটি ব্যবহার করবে LOAD_FAST- এবং আপনি পাবেন*UnboundLocalError: local variable 'l' referenced before assignment*


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

8
আমার উদাহরণে পরিবর্তনশীল 'l' ঠিক সেই ধরণের। এটা 'foo বিন্যাস' এবং 'বু' ফাংশন (তাদের সুযোগ বাইরে) জন্য স্থানীয় নয়, কিন্তু এটি (সংজ্ঞায়িত ভিতরে 'প্রধান' func, মডিউল স্তরের উপর নয়) বিশ্বব্যাপী নয়
monitorius

3
আমি নিশ্চিত করতে পারি যে এই ত্রুটিটি অজগর 3.4.2 এর সাথে এখনও ঘটে (আপনার মুদ্রণের জন্য প্রথম বন্ধনী যুক্ত করতে হবে তবে সমস্ত কিছুই একই থাকতে পারে)।
ট্রিকোপলাক্স

7
সেটা ঠিক. কিন্তু অন্তত আপনি ব্যবহার করতে পারেন nonlocal ঠ মধ্যে বিবৃতি বু Python3 হবে।
monitorius

সংকলক -> দোভাষী
জোয়েলব

42

আপনি ফাংশন কলগুলি চেইন করতে পারেন, তবে আপনি সরাসরি কোনও ফাংশন কলকে + = করতে পারবেন না:

class A:
    def __init__(self):
        self.listFoo = [1, 2]
        self.listBar = [3, 4]

    def get_list(self, which):
        if which == "Foo":
            return self.listFoo
        return self.listBar

a = A()
other_list = [5, 6]

a.get_list("Foo").extend(other_list)
a.get_list("Foo") += other_list  #SyntaxError: can't assign to function call

8

আমি বলব যে এটি যখন নাম্বার নিয়ে আসে তখন কিছুটা পার্থক্য থাকে (আমি কেবল দেখলাম যে প্রশ্নটি দুটি তালিকাকে নকল করে দেওয়ার জন্য নয়, তবে যেহেতু এটি আমার মতো শিক্ষানবিশদের জন্য সমস্যা হতে পারে, আমি আশা করি এটি কারও সাহায্য করতে পারে প্রাক্তন হিসাবে, যারা এই পোস্টটির সমাধান খুঁজছেন)।

import numpy as np
a = np.zeros((4,4,4))
b = []
b += a

এটি ত্রুটির সাথে ফিরে আসবে

মান মূল্য: অপারেশনগুলি আকার (0,) (4,4,4) এর সাথে একসাথে সম্প্রচার করা যায়নি

b.extend(a) পুরোপুরি কাজ করে


5

থেকে CPython 3.5.2 সোর্স কোড কোন বড় পার্থক্য।

static PyObject *
list_inplace_concat(PyListObject *self, PyObject *other)
{
    PyObject *result;

    result = listextend(self, other);
    if (result == NULL)
        return result;
    Py_DECREF(result);
    Py_INCREF(self);
    return (PyObject *)self;
}

4

প্রসারিত () যেকোন পুনরাবৃত্ত * এর সাথে কাজ করে, + = কারও সাথে কাজ করে তবে মজার হতে পারে।

import numpy as np

l = [2, 3, 4]
t = (5, 6, 7)
l += t
l
[2, 3, 4, 5, 6, 7]

l = [2, 3, 4]
t = np.array((5, 6, 7))
l += t
l
array([ 7,  9, 11])

l = [2, 3, 4]
t = np.array((5, 6, 7))
l.extend(t)
l
[2, 3, 4, 5, 6, 7]

পাইথন ৩.6
* খুব নিশ্চিত। প্রসারিত () কোনও পুনরাবৃত্তির সাথে কাজ করে তবে দয়া করে আমি ভুল হলে মন্তব্য করুন


টিপল অবশ্যই একটি পুনরাবৃত্তিযোগ্য, তবে এর কোনও প্রসারিত () পদ্ধতি নেই। পুনরাবৃত্তির সাথে প্রসারিত () পদ্ধতির কোনও সম্পর্ক নেই।
wombatonfire

.exte তালিকার শ্রেণীর একটি পদ্ধতি। পাইথন ডকুমেন্টেশন থেকে: list.extend(iterable) Extend the list by appending all the items from the iterable. Equivalent to a[len(a):] = iterable.অনুমান আমি নিজের নিজের নক্ষত্রটির উত্তর দিয়েছি।
grofte

ওহ, আপনি বোঝাতে চেয়েছিলেন যে আপনি প্রসারিত () বাড়ানোর জন্য যে কোনও পুনরাবৃত্তিযোগ্য পাস করতে পারেন। আমি এটিকে "প্রসারিত () যে কোনও পুনরাবৃত্তির জন্য উপলব্ধ" হিসাবে পড়েছি: :) আমার খারাপ, তবে এটি কিছুটা অস্পষ্ট মনে হচ্ছে।
wombatonfire

1
সর্বোপরি, এটি একটি ভাল উদাহরণ নয়, কমপক্ষে এই প্রশ্নের প্রসঙ্গে নয়। আপনি যখন +=বিভিন্ন ধরণের অবজেক্টস সহ অপারেটর ব্যবহার করেন (প্রশ্ন হিসাবে দুটি তালিকার বিপরীতে), আপনি আশা করতে পারবেন না যে আপনি বস্তুর সংমিশ্রণ পাবেন। এবং আপনি প্রত্যাশা করতে পারবেন না যে কোনও listপ্রকার ফেরত আসবে। আপনার কোডটি একবার দেখুন, আপনি এর numpy.ndarrayপরিবর্তে একটি পান list
wombatonfire 13

2

আসলে, সেখানে তিনটি বিকল্প মধ্যে পার্থক্য আছে: ADD, INPLACE_ADDএবংextend । পূর্বেরটি সর্বদা ধীর গতির হয়, অন্য দুটি মোটামুটি একই হয়।

এই তথ্যের সাথে, আমি বরং ব্যবহার করব extend, যা তুলনায় দ্রুত ADDএবং আপনি আমার চেয়ে কী করছেন তা আরও স্পষ্ট বলে মনে হয় INPLACE_ADD

নিম্নলিখিত কোডটি কয়েকবার চেষ্টা করুন (পাইথন 3 এর জন্য):

import time

def test():
    x = list(range(10000000))
    y = list(range(10000000))
    z = list(range(10000000))

    # INPLACE_ADD
    t0 = time.process_time()
    z += x
    t_inplace_add = time.process_time() - t0

    # ADD
    t0 = time.process_time()
    w = x + y
    t_add = time.process_time() - t0

    # Extend
    t0 = time.process_time()
    x.extend(y)
    t_extend = time.process_time() - t0

    print('ADD {} s'.format(t_add))
    print('INPLACE_ADD {} s'.format(t_inplace_add))
    print('extend {} s'.format(t_extend))
    print()

for i in range(10):
    test()
ADD 0.3540440000000018 s
INPLACE_ADD 0.10896000000000328 s
extend 0.08370399999999734 s

ADD 0.2024550000000005 s
INPLACE_ADD 0.0972940000000051 s
extend 0.09610200000000191 s

ADD 0.1680199999999985 s
INPLACE_ADD 0.08162199999999586 s
extend 0.0815160000000077 s

ADD 0.16708400000000267 s
INPLACE_ADD 0.0797719999999913 s
extend 0.0801490000000058 s

ADD 0.1681250000000034 s
INPLACE_ADD 0.08324399999999343 s
extend 0.08062700000000689 s

ADD 0.1707760000000036 s
INPLACE_ADD 0.08071900000000198 s
extend 0.09226200000000517 s

ADD 0.1668420000000026 s
INPLACE_ADD 0.08047300000001201 s
extend 0.0848089999999928 s

ADD 0.16659500000000094 s
INPLACE_ADD 0.08019399999999166 s
extend 0.07981599999999389 s

ADD 0.1710910000000041 s
INPLACE_ADD 0.0783479999999912 s
extend 0.07987599999999873 s

ADD 0.16435900000000458 s
INPLACE_ADD 0.08131200000001115 s
extend 0.0818660000000051 s

2
আপনি এবং ADDসাথে তুলনা করতে পারবেন না । একটি নতুন তালিকা তৈরি করে এবং এতে দুটি মূল তালিকার উপাদানগুলি অনুলিপি করে। নিশ্চিতভাবে এটি এবং এর ইনপ্লেস অপারেশনের চেয়ে ধীর হবে । INPLACE_ADDextend()ADDINPLACE_ADDextend()
wombatonfire

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

1

আমি পাইথনের অফিসিয়াল টিউটোরিয়াল সন্ধান করেছি কিন্তু এই বিষয় সম্পর্কে কিছুই খুঁজে পাইনি

প্রোগ্রামিং এফএকিউতে এই তথ্যটি সমাহিত করা হয় :

... তালিকার জন্য, __iadd__[অর্থাত্ +=] extendতালিকায় কল করা এবং তালিকাটি ফিরিয়ে দেওয়ার সমতুল্য । এজন্য আমরা বলি যে তালিকার জন্য +=এটি একটি "শর্টহ্যান্ড"list.extend

আপনি সিপিথন উত্স কোডে এটি নিজের জন্যও দেখতে পাবেন: https://github.com/python/cpython/blob/v3.8.2/Objects/listobject.c#L1000-L1011


-1

ডেটা অ্যানালাইসিসের পাইথন অনুসারে।

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

everything = []
for chunk in list_of_lists:
    everything.extend(chunk)

সংক্ষিপ্ত বিকল্পের চেয়ে দ্রুত:

everything = []
for chunk in list_of_lists:
    everything = everything + chunk

এখানে চিত্র বর্ণনা লিখুন এখানে চিত্র বর্ণনা লিখুন


4
everything = everything + tempঅগত্যা একইভাবে কার্যকর করা হয় না everything += temp
ডেভিড হ্যারিসন

1
তুমি ঠিক. আপনার স্মরণ করিয়ে দেওয়ার জন্য আপনাকে ধন্যবাদ। তবে আমার বক্তব্য দক্ষতার পার্থক্য সম্পর্কে। :)
লিটল বিয়ার 333

6
@ লিটল বিয়ার 333 everything += tempএমনভাবে প্রয়োগ করা হয়েছে everythingযা অনুলিপি করার দরকার নেই। এটি আপনার উত্তরকে মূল বিষয় হিসাবে চিহ্নিত করে।
nog642
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.