سؤال

لما و لما لا؟

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

المحلول

للأداء، خاصة عند التكرار على نطاق واسع، xrange() عادة ما يكون أفضل.ومع ذلك، لا تزال هناك بعض الحالات التي قد تفضلها range():

  • في بيثون 3، range() يفعل ما xrange() تستخدم للقيام و xrange() غير موجود.إذا كنت تريد كتابة تعليمات برمجية تعمل على كل من Python 2 وPython 3، فلا يمكنك استخدامها xrange().

  • range() يمكن أن يكون في الواقع أسرع في بعض الحالات - على سبيل المثال.إذا تم التكرار على نفس التسلسل عدة مرات. xrange() يجب إعادة بناء الكائن الصحيح في كل مرة، ولكن range() سيكون لها كائنات عددية حقيقية.(سيكون أداؤه دائمًا أسوأ من حيث الذاكرة)

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

[عدل] هناك منشوران يذكران كيفية القيام بذلك range() سيتم ترقيته بواسطة أداة 2to3.للتسجيل، إليك نتيجة تشغيل الأداة على بعض نماذج استخدامات range() و xrange()

RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: ws_comma
--- range_test.py (original)
+++ range_test.py (refactored)
@@ -1,7 +1,7 @@

 for x in range(20):
-    a=range(20)
+    a=list(range(20))
     b=list(range(20))
     c=[x for x in range(20)]
     d=(x for x in range(20))
-    e=xrange(20)
+    e=range(20)

كما ترون، عند استخدامه في حلقة for أو فهم، أو عندما يتم تغليفه بالفعل بـ list()، يتم ترك النطاق دون تغيير.

نصائح أخرى

لا، كلاهما له استخداماته:

يستخدم xrange() عند التكرار، لأنه يحفظ الذاكرة.يقول:

for x in xrange(1, one_zillion):

بدلا من:

for x in range(1, one_zillion):

ومن ناحية أخرى، استخدم range() إذا كنت تريد فعلا قائمة الأرقام.

multiples_of_seven = range(7,100,7)
print "Multiples of seven < 100: ", multiples_of_seven

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

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

Python 2.7.3 (default, Jul 13 2012, 22:29:01) 
[GCC 4.7.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(123456787676676767676676,123456787676676767676679)
[123456787676676767676676L, 123456787676676767676677L, 123456787676676767676678L]
>>> xrange(123456787676676767676676,123456787676676767676679)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: Python int too large to convert to C long

لا يواجه Python 3 هذه المشكلة:

Python 3.2.3 (default, Jul 14 2012, 01:01:48) 
[GCC 4.7.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(123456787676676767676676,123456787676676767676679)
range(123456787676676767676676, 123456787676676767676679)

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

ما لم أكن بحاجة على وجه التحديد إلى قائمة لشيء ما، فأنا أفضّل ذلك دائمًا xrange()

تقوم الدالة range() بإرجاع قائمة، بينما تقوم الدالة xrange() بإرجاع كائن xrange.

xrange() أسرع قليلاً وأكثر كفاءة في الذاكرة.لكن المكسب ليس كبيرا جدا.

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

لا يزال إصدار Python 3.0 قيد التطوير، لكن نطاق IIRC () سيكون مشابهًا جدًا لـ xrange () لـ 2.X ويمكن استخدام القائمة () لإنشاء القوائم.

أود فقط أن أقول إنه ليس من الصعب حقًا الحصول على كائن xrange مع وظيفة الشريحة والفهرسة.لقد كتبت بعض التعليمات البرمجية التي تعمل بشكل جيد جدًا وهي بنفس سرعة xrange عندما يكون ذلك مهمًا (التكرارات).

from __future__ import division

def read_xrange(xrange_object):
    # returns the xrange object's start, stop, and step
    start = xrange_object[0]
    if len(xrange_object) > 1:
       step = xrange_object[1] - xrange_object[0]
    else:
        step = 1
    stop = xrange_object[-1] + step
    return start, stop, step

class Xrange(object):
    ''' creates an xrange-like object that supports slicing and indexing.
    ex: a = Xrange(20)
    a.index(10)
    will work

    Also a[:5]
    will return another Xrange object with the specified attributes

    Also allows for the conversion from an existing xrange object
    '''
    def __init__(self, *inputs):
        # allow inputs of xrange objects
        if len(inputs) == 1:
            test, = inputs
            if type(test) == xrange:
                self.xrange = test
                self.start, self.stop, self.step = read_xrange(test)
                return

        # or create one from start, stop, step
        self.start, self.step = 0, None
        if len(inputs) == 1:
            self.stop, = inputs
        elif len(inputs) == 2:
            self.start, self.stop = inputs
        elif len(inputs) == 3:
            self.start, self.stop, self.step = inputs
        else:
            raise ValueError(inputs)

        self.xrange = xrange(self.start, self.stop, self.step)

    def __iter__(self):
        return iter(self.xrange)

    def __getitem__(self, item):
        if type(item) is int:
            if item < 0:
                item += len(self)

            return self.xrange[item]

        if type(item) is slice:
            # get the indexes, and then convert to the number
            start, stop, step = item.start, item.stop, item.step
            start = start if start != None else 0 # convert start = None to start = 0
            if start < 0:
                start += start
            start = self[start]
            if start < 0: raise IndexError(item)
            step = (self.step if self.step != None else 1) * (step if step != None else 1)
            stop = stop if stop is not None else self.xrange[-1]
            if stop < 0:
                stop += stop

            stop = self[stop]
            stop = stop

            if stop > self.stop:
                raise IndexError
            if start < self.start:
                raise IndexError
            return Xrange(start, stop, step)

    def index(self, value):
        error = ValueError('object.index({0}): {0} not in object'.format(value))
        index = (value - self.start)/self.step
        if index % 1 != 0:
            raise error
        index = int(index)


        try:
            self.xrange[index]
        except (IndexError, TypeError):
            raise error
        return index

    def __len__(self):
        return len(self.xrange)

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

مثال جيد ورد في الكتاب: بيثون العملي بقلم ماجنوس لي هيتلاند

>>> zip(range(5), xrange(100000000))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]

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

نعم قرأت إجابة @ براين:في بايثون 3، النطاق () هو مولد على أي حال وxrange () غير موجود.

اذهب مع النطاق لهذه الأسباب:

1) سيختفي xrange في إصدارات Python الأحدث.وهذا يمنحك سهولة التوافق في المستقبل.

2) سوف يأخذ النطاق الكفاءات المرتبطة بـ xrange.

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

ومع ذلك، ما أعتقد أنكم تريدون سماعه هو أن الخيار المفضل هو xrange.نظرًا لأن النطاق في Python 3 عبارة عن مكرر، فإن أداة تحويل التعليمات البرمجية 2to3 ستحول جميع استخدامات xrange إلى range بشكل صحيح، وستظهر خطأ أو تحذيرًا لاستخدامات النطاق.إذا كنت تريد التأكد من تحويل التعليمات البرمجية الخاصة بك بسهولة في المستقبل، فستستخدم xrange فقط، وlist(xrange) عندما تكون متأكدًا من أنك تريد قائمة.لقد تعلمت هذا خلال سباق CPython في PyCon هذا العام (2008) في شيكاغو.

  • range(): range(1, 10) تقوم بإرجاع قائمة من 1 إلى 10 أرقام مع الاحتفاظ بالقائمة بأكملها في الذاكرة.
  • xrange():يحب range(), ، ولكن بدلاً من إرجاع قائمة، يتم إرجاع كائن يقوم بإنشاء الأرقام الموجودة في النطاق عند الطلب.بالنسبة للحلقات، هذا أسرع قليلاً من 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__
Out[3]: xrange([start,] stop[, step]) -> xrange object

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

بينما xrange أسرع من range في معظم الظروف، يكون الفرق في الأداء ضئيلًا جدًا.يقارن البرنامج الصغير أدناه التكرار عبر ملف range و xrange:

import timeit
# Try various list sizes.
for list_len in [1, 10, 100, 1000, 10000, 100000, 1000000]:
  # Time doing a range and an xrange.
  rtime = timeit.timeit('a=0;\nfor n in range(%d): a += n'%list_len, number=1000)
  xrtime = timeit.timeit('a=0;\nfor n in xrange(%d): a += n'%list_len, number=1000)
  # Print the result
  print "Loop list of len %d: range=%.4f, xrange=%.4f"%(list_len, rtime, xrtime)

النتائج أدناه تظهر ذلك xrange هو في الواقع أسرع، ولكن ليس بما يكفي للعرق.

Loop list of len 1: range=0.0003, xrange=0.0003
Loop list of len 10: range=0.0013, xrange=0.0011
Loop list of len 100: range=0.0068, xrange=0.0034
Loop list of len 1000: range=0.0609, xrange=0.0438
Loop list of len 10000: range=0.5527, xrange=0.5266
Loop list of len 100000: range=10.1666, xrange=7.8481
Loop list of len 1000000: range=168.3425, xrange=155.8719

لذلك استخدم بكل الوسائل xrange, ، ولكن ما لم تكن تستخدم أجهزة مقيدة، فلا تقلق كثيرًا بشأن ذلك.

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