سؤال

من الواضح أن xrange أسرع ولكن ليس لدي أي فكرة عن سبب كونه أسرع (ولا يوجد دليل إلى جانب القصص المتناقلة حتى الآن على أنه أسرع) أو ما هو المختلف إلى جانب ذلك

for i in range(0, 20):
for i in xrange(0, 20):
هل كانت مفيدة؟

المحلول

range بإنشاء قائمة، لذلك إذا قمت بذلك range(1, 10000000) يقوم بإنشاء قائمة في الذاكرة مع 9999999 عناصر.

xrange هو كائن تسلسل يتم تقييمه بتكاسل.

يجب إضافته من تلميح @ Thiago، أنه في python3، النطاق يعادل نطاق python's xrange

نصائح أخرى

range بإنشاء قائمة، لذلك إذا قمت بذلك range(1, 10000000) يقوم بإنشاء قائمة في الذاكرة مع 9999999 عناصر.

xrange هو مولد، لذلك هو كائن تسلسل هو الذي يقيم بتكاسل.

هذا صحيح، لكن في بايثون 3، .range() سيتم تنفيذه بواسطة Python 2 .xrange().إذا كنت تريد إنشاء القائمة بالفعل، فسوف يتعين عليك القيام بما يلي:

list(range(1,100))

تذكر، استخدم timeit وحدة لاختبار أي من المقتطفات الصغيرة من التعليمات البرمجية تكون أسرع!

$ python -m timeit 'for i in range(1000000):' ' pass'
10 loops, best of 3: 90.5 msec per loop
$ python -m timeit 'for i in xrange(1000000):' ' pass'
10 loops, best of 3: 51.1 msec per loop

أنا شخصياً أستخدمه دائمًا .range(), ، إلا إذا كنت أتعامل مع حقًا قوائم ضخمة -- كما ترون، من حيث الوقت، بالنسبة لقائمة تضم مليون إدخال، فإن الحمل الإضافي هو 0.04 ثانية فقط.وكما يشير كوري، في بايثون 3.0 .xrange() سوف تذهب بعيدا و .range() سوف أعطيك سلوك مكرر لطيف على أي حال.

xrange يقوم فقط بتخزين معلمات النطاق وإنشاء الأرقام عند الطلب.ومع ذلك، فإن تطبيق لغة C لـ Python يقيد وسيطاتها حاليًا على لغة C الطويلة:

xrange(2**32-1, 2**32+1)  # When long is 32 bits, OverflowError: Python int too large to convert to C long
range(2**32-1, 2**32+1)   # OK --> [4294967295L, 4294967296L]

لاحظ أنه في Python 3.0 لا يوجد سوى range ويتصرف مثل 2.x xrange ولكن بدون القيود على الحد الأدنى والحد الأقصى لنقاط النهاية.

يُرجع xrange مُكرِّرًا ويحتفظ برقم واحد فقط في الذاكرة في كل مرة.يحتفظ النطاق بقائمة كاملة من الأرقام في الذاكرة.

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

تتمثل ميزة نوع XRange في أن كائن Xrange سيأخذ دائمًا نفس القدر من الذاكرة ، بغض النظر عن حجم النطاق الذي يمثله.لا توجد مزايا أداء متسقة.

هناك طريقة أخرى للعثور على معلومات سريعة حول بنية Python وهي سلسلة المستندات ووظيفة المساعدة:

print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)

يقوم range بإنشاء قائمة، لذلك إذا قمت بإجراء range(1, 10000000) فإنه يقوم بإنشاء قائمة في الذاكرة تحتوي على 10000000 عنصر.xrange هو مولد، لذلك يتم تقييمه بتكاسل.

وهذا يجلب لك ميزتين:

  1. يمكنك تكرار قوائم أطول دون الحصول على MemoryError.
  2. نظرًا لأنه يحل كل رقم بتكاسل، إذا قمت بإيقاف التكرار مبكرًا، فلن تضيع الوقت في إنشاء القائمة بأكملها.

لقد صدمت لا أحد يقرأ وثيقة:

هذه الوظيفة مشابهة جدًا لـ range(), ، ولكن ترجع xrange كائن بدلاً من القائمة.هذا هو نوع تسلسل غير شفاف ينتج عنه نفس القيم مثل القائمة المقابلة، دون تخزينها جميعًا في وقت واحد.ميزة xrange() زيادة range() هو الحد الأدنى (منذ xrange() لا يزال يتعين عليه إنشاء القيم عند طلبها) إلا عند استخدام نطاق كبير جدًا على جهاز متعطش للذاكرة أو عندما لا يتم استخدام جميع عناصر النطاق مطلقًا (مثل عندما يتم إنهاء الحلقة عادةً بـ break).

إنه لأسباب التحسين.

سيقوم range() بإنشاء قائمة بالقيم من البداية إلى النهاية (0 ..20 في مثالك).ستصبح هذه عملية مكلفة على نطاقات كبيرة جدًا.

من ناحية أخرى، يعتبر xrange() أكثر تحسينًا.سيحسب القيمة التالية فقط عند الحاجة (عبر كائن تسلسل xrange) ولا يقوم بإنشاء قائمة بجميع القيم كما يفعل range().

سوف تجد ميزة xrange زيادة range في هذا المثال البسيط:

import timeit

t1 = timeit.default_timer()
a = 0
for i in xrange(1, 100000000):
    pass
t2 = timeit.default_timer()

print "time taken: ", (t2-t1)  # 4.49153590202 seconds

t1 = timeit.default_timer()
a = 0
for i in range(1, 100000000):
    pass
t2 = timeit.default_timer()

print "time taken: ", (t2-t1)  # 7.04547905922 seconds

المثال أعلاه لا يعكس أي شيء أفضل بكثير في حالة xrange.

انظر الآن إلى الحالة التالية حيث range هو حقا بطيء حقا، مقارنة ب xrange.

import timeit

t1 = timeit.default_timer()
a = 0
for i in xrange(1, 100000000):
    if i == 10000:
        break
t2 = timeit.default_timer()

print "time taken: ", (t2-t1)  # 0.000764846801758 seconds

t1 = timeit.default_timer()
a = 0
for i in range(1, 100000000):
    if i == 10000:
        break
t2 = timeit.default_timer() 

print "time taken: ", (t2-t1)  # 2.78506207466 seconds

مع range, ، فهو يقوم بالفعل بإنشاء قائمة من 0 إلى 100000000 (تستغرق وقتًا طويلاً)، ولكن xrange هو مولد وهو يولد أرقامًا فقط بناءً على الحاجة، أي إذا استمر التكرار.

في Python-3، تم تنفيذ range الوظيفة هي نفس وظيفة xrange في Python-2، بينما تخلصوا من ذلك xrange في بيثون-3

ترميز سعيد!!

يتراوح(): يُرجع النطاق (1، 10) قائمة من 1 إلى 10 أرقام ويحتفظ بالقائمة بأكملها في الذاكرة.

xrange(): مثل range()، ولكن بدلاً من إرجاع قائمة، تقوم بإرجاع كائن يقوم بإنشاء الأرقام الموجودة في النطاق عند الطلب.بالنسبة للتكرار، يعد هذا أسرع قليلاً من النطاق () وأكثر كفاءة في الذاكرة.كائن xrange() مثل المكرر ويقوم بإنشاء الأرقام حسب الطلب. (تقييم كسول)

In [1]: range(1,10)

Out[1]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

In [2]: xrange(10)

Out[2]: xrange(10)

In [3]: print xrange.__doc__

xrange([start,] stop[, step]) -> xrange object

range(x,y) إرجاع قائمة بكل رقم بين x وy إذا كنت تستخدم a for حلقة، ثم range أبطأ.في الحقيقة، range لديه نطاق مؤشر أكبر. range(x.y) سيتم طباعة قائمة بجميع الأرقام الموجودة بين x و y

xrange(x,y) عائدات xrange(x,y) ولكن إذا كنت تستخدم for حلقة، ثم xrange أسرع. xrange لديه نطاق فهرس أصغر. xrange لن تتم طباعتها فقط xrange(x,y) لكنه سيظل يحتفظ بجميع الأرقام الموجودة فيه.

[In] range(1,10)
[Out] [1, 2, 3, 4, 5, 6, 7, 8, 9]
[In] xrange(1,10)
[Out] xrange(1,10)

إذا كنت تستخدم أ for حلقة، ثم أنها ستعمل

[In] for i in range(1,10):
        print i
[Out] 1
      2
      3
      4
      5
      6
      7
      8
      9
[In] for i in xrange(1,10):
         print i
[Out] 1
      2
      3
      4
      5
      6
      7
      8
      9

لا يوجد فرق كبير عند استخدام الحلقات، على الرغم من وجود فرق عند طباعتها فقط!

في بيثون 2.x

النطاق (x) تقوم بإرجاع قائمة تم إنشاؤها في الذاكرة باستخدام عناصر x.

>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]

xrange(x) تقوم بإرجاع كائن xrange وهو كائن منشئ يقوم بإنشاء الأرقام عند الطلب.يتم حسابها أثناء الحلقة (التقييم البطيء).

بالنسبة للتكرار، يعد هذا أسرع قليلاً من النطاق () وأكثر كفاءة في الذاكرة.

>>> b = xrange(5)
>>> b
xrange(5)

عند اختبار النطاق مقابل xrange في حلقة (أعلم أنه يجب علي استخدام الوقت هو, ، ولكن تم حذف هذا بسرعة من الذاكرة باستخدام مثال بسيط لفهم القائمة) لقد وجدت ما يلي:

import time

for x in range(1, 10):

    t = time.time()
    [v*10 for v in range(1, 10000)]
    print "range:  %.4f" % ((time.time()-t)*100)

    t = time.time()
    [v*10 for v in xrange(1, 10000)]
    print "xrange: %.4f" % ((time.time()-t)*100)

الذي يعطي:

$python range_tests.py
range:  0.4273
xrange: 0.3733
range:  0.3881
xrange: 0.3507
range:  0.3712
xrange: 0.3565
range:  0.4031
xrange: 0.3558
range:  0.3714
xrange: 0.3520
range:  0.3834
xrange: 0.3546
range:  0.3717
xrange: 0.3511
range:  0.3745
xrange: 0.3523
range:  0.3858
xrange: 0.3997 <- garbage collection?

أو باستخدام xrange في حلقة for:

range:  0.4172
xrange: 0.3701
range:  0.3840
xrange: 0.3547
range:  0.3830
xrange: 0.3862 <- garbage collection?
range:  0.4019
xrange: 0.3532
range:  0.3738
xrange: 0.3726
range:  0.3762
xrange: 0.3533
range:  0.3710
xrange: 0.3509
range:  0.3738
xrange: 0.3512
range:  0.3703
xrange: 0.3509

هل يتم اختبار المقتطف الخاص بي بشكل صحيح؟هل هناك أي تعليقات على المثيل الأبطأ لـ xrange؟أو مثال أفضل :-)

تشير بعض الإجابات الأخرى إلى أن Python 3 أزال 2.x range وأعيد تسميتها بـ 2.x's xrange ل range.ومع ذلك، إلا إذا كنت تستخدم الإصدار 3.0 أو 3.1 (وهو ما لا ينبغي لأحد أن يستخدمه)، فهو في الواقع نوع مختلف إلى حد ما.

مثل المستندات 3.1 يقول:

كائنات النطاق لها سلوك قليل جدًا:إنهم يدعمون فقط الفهرسة والتكرار و len وظيفة.

لكن في 3.2+ range هو تسلسل كامل - فهو يدعم الشرائح الموسعة، وجميع أساليب collections.abc.Sequence مع نفس الدلالات مثل أ list.*

وعلى الأقل في CPython وPyPy (التطبيقان الوحيدان 3.2+ الموجودان حاليًا)، فإن لديها أيضًا تطبيقات في الوقت الثابت لـ index و count الأساليب و in عامل التشغيل (طالما أنك تمرر الأعداد الصحيحة فقط).وهذا يعني الكتابة 123456 in r معقول في 3.2+، بينما في 2.7 أو 3.1 سيكون فكرة فظيعة.


* حقيقة ان issubclass(xrange, collections.Sequence) عائدات True في 2.6-2.7 و3.0-3.1 هو حشرة تم إصلاح ذلك في 3.2 ولم يتم نقله إلى الخلف.

يعمل كل من xrange() و range() في لغة python بنفس الطريقة التي يعمل بها المستخدم، ولكن الفرق يأتي عندما نتحدث عن كيفية تخصيص الذاكرة في استخدام كلتا الدالتين.

عندما نستخدم النطاق () فإننا نخصص ذاكرة لجميع المتغيرات التي ينشئها، لذلك لا ينصح باستخدامها مع أرقام أكبر.من المتغيرات التي سيتم إنشاؤها.

من ناحية أخرى، يقوم xrange() بإنشاء قيمة معينة فقط في المرة الواحدة ولا يمكن استخدامه إلا مع حلقة for لطباعة جميع القيم المطلوبة.

range ينشئ القائمة بأكملها ويعيدها.لا يقوم xrange بذلك - فهو يقوم بإنشاء الأرقام الموجودة في القائمة عند الطلب.

اقرأ المنشور التالي للمقارنة بين النطاق وxrange مع التحليل الرسومي.

نطاق بايثون مقابل xrange

يستخدم xrange مُكرِّرًا (يُنشئ قيمًا سريعة)، بينما يُرجع النطاق قائمة.

ماذا؟
range إرجاع قائمة ثابتة في وقت التشغيل.
xrange يعود object (الذي يعمل كمولد، على الرغم من أنه ليس كذلك بالتأكيد) والذي يتم إنشاء القيم منه عند الحاجة.

متى تستخدم أي؟

  • يستخدم xrange إذا كنت تريد إنشاء قائمة بنطاق ضخم، مثلاً مليار، خاصة عندما يكون لديك "نظام حساس للذاكرة" مثل الهاتف الخلوي.
  • يستخدم range إذا كنت تريد التكرار على القائمة عدة مرات.

ملاحظة:بايثون 3.x range الوظيفة == بيثون 2.x xrange وظيفة.

فيما يتعلق بمتطلبات المسح الضوئي/الطباعة للعناصر 0-N، يعمل النطاق وxrange على النحو التالي.

range() - ينشئ قائمة جديدة في الذاكرة ويأخذ العناصر بأكملها من 0 إلى N (إجمالي N+1) ويطبعها.xrange() - يقوم بإنشاء مثيل مكرر يقوم بمسح العناصر ويحتفظ فقط بالعنصر الحالي الذي تمت مواجهته في الذاكرة، وبالتالي استخدام نفس مقدار الذاكرة طوال الوقت.

في حالة وجود العنصر المطلوب إلى حد ما في بداية القائمة فقط، فإنه يوفر قدرًا كبيرًا من الوقت والذاكرة.

يقل الفرق بالنسبة للوسائط الأصغر حجمًا range(..) / xrange(..):

$ python -m timeit "for i in xrange(10111):" " for k in range(100):" "  pass"
10 loops, best of 3: 59.4 msec per loop

$ python -m timeit "for i in xrange(10111):" " for k in xrange(100):" "  pass"
10 loops, best of 3: 46.9 msec per loop

في هذه الحالة xrange(100) هو فقط حوالي 20٪ أكثر كفاءة.

لقد أوضح الجميع ذلك بشكل كبير.لكنني أردت أن أرى ذلك بنفسي.أستخدم بايثون3.لذلك، قمت بفتح مراقب الموارد (في نظام التشغيل Windows!)، وقمت أولاً بتنفيذ الأمر التالي أولاً:

a=0
for i in range(1,100000):
    a=a+i

ثم تحقق من التغيير في الذاكرة "قيد الاستخدام".لقد كانت ضئيلة.ثم قمت بتشغيل الكود التالي:

for i in list(range(1,100000)):
    a=a+i

واستغرق الأمر جزءًا كبيرًا من الذاكرة للاستخدام على الفور.ولقد اقتنعت.يمكنك تجربتها بنفسك.

إذا كنت تستخدم Python 2X، فاستبدل "range()" بـ "xrange()" في الكود الأول و"list(range())" بـ "range()".

يتراوح يعود أ قائمة بينما com.xrange يعود com.xrange الكائن الذي يأخذ نفس الذاكرة بغض النظر عن حجم النطاق، كما في هذه الحالة، يتم إنشاء عنصر واحد فقط ويكون متاحًا لكل تكرار بينما في حالة استخدام النطاق، يتم إنشاء جميع العناصر مرة واحدة وتكون متاحة في الذاكرة.

النطاق: - النطاق سوف يملأ كل شيء مرة واحدة. مما يعني أن كل رقم من النطاق سوف يشغل الذاكرة.

xrange: -xrange هو شيء يشبه المولد، وسيظهر في الصورة عندما تريد نطاق الأرقام ولكنك لا تريد تخزينها، كما هو الحال عندما تريد استخدامها في حلقة، لذا فإن الذاكرة فعالة.

من مستندات المساعدة.

بايثون 2.7.12

>>> print range.__doc__
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers

Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3].  The end point is omitted!
These are exactly the valid indices for a list of 4 elements.

>>> print xrange.__doc__
xrange(stop) -> xrange object
xrange(start, stop[, step]) -> xrange object

Like range(), but instead of returning a list, returns an object that
generates the numbers in the range on demand.  For looping, this is 
slightly faster than range() and more memory efficient.

بايثون 3.5.2

>>> print(range.__doc__)
range(stop) -> range object
range(start, stop[, step]) -> range object

Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).

>>> print(xrange.__doc__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'xrange' is not defined

الفرق واضح.في بايثون 2.x، range إرجاع قائمة، xrange تقوم بإرجاع كائن xrange وهو قابل للتكرار.

في بايثون 3.x، range يصبح xrange من بايثون 2.x، و xrange تم حذفه.

بالإضافة إلى ذلك، إذا قمت بذلك list(xrange(...)) سيكون معادلاً ل range(...).

لذا list بطيء.

أيضًا xrange حقا لا يكمل التسلسل بالكامل

ولهذا السبب فهي ليست قائمة، إنها xrange هدف

انظر الى هذا بريد للعثور على الفرق بين النطاق وxrange:

يقتبس:

range إرجاع ما تعتقده بالضبط:قائمة أعداد صحيحة متتالية ، بطول محدد يبدأ بـ 0. xrange, ، ومع ذلك ، يعيد "كائن xrange", ، والذي يعمل إلى حد كبير مثل المكرر

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