متى لا يكون الوقت المناسب لاستخدام مولدات بايثون؟

StackOverflow https://stackoverflow.com/questions/245792

سؤال

وهذا هو بالأحرى عكس ذلك ما الذي يمكنك استخدام وظائف مولد بايثون؟:مولدات بايثون، وتعبيرات المولدات، و itertools الوحدة هي بعض ميزاتي المفضلة في لغة بايثون هذه الأيام.إنها مفيدة بشكل خاص عند إعداد سلاسل العمليات لتنفيذها على كومة كبيرة من البيانات - غالبًا ما أستخدمها عند معالجة ملفات DSV.

إذن متى لا الوقت المناسب لاستخدام المولد، أو تعبير المولد، أو itertools وظيفة؟

  • متى يجب أن أفضّل zip() زيادة itertools.izip(), ، أو
  • range() زيادة xrange(), ، أو
  • [x for x in foo] زيادة (x for x in foo)?

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

نحن نستخدم المولدات حتى لا نقوم بتعيين قوائم جديدة في الذاكرة للبيانات المؤقتة.وهذا منطقي بشكل خاص بالنسبة لمجموعات البيانات الكبيرة.هل هذا منطقي بالنسبة لمجموعات البيانات الصغيرة أيضًا؟هل هناك مقايضة ملحوظة بين الذاكرة ووحدة المعالجة المركزية؟

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

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

المحلول

استخدم القائمة بدلاً من المولد عندما:

1) تحتاج إلى الوصول إلى البيانات عديد مرات (أيتخزين النتائج مؤقتًا بدلاً من إعادة حسابها):

for i in outer:           # used once, okay to be a generator or return a list
    for j in inner:       # used multiple times, reusing a list is better
         ...

2) تحتاج دخول عشوائي (أو أي وصول بخلاف الترتيب التسلسلي الأمامي):

for i in reversed(data): ...     # generators aren't reversible

s[i], s[j] = s[j], s[i]          # generators aren't indexable

3) تحتاج إلى ينضم السلاسل (التي تتطلب تمريرين عبر البيانات):

s = ''.join(data)                # lists are faster than generators in this use case

4) أنت تستخدم PyPy والتي في بعض الأحيان لا يمكنها تحسين كود المولد بقدر ما تستطيع من خلال استدعاءات الوظائف العادية ومعالجة القائمة.

نصائح أخرى

بشكل عام، لا تستخدم المولد عندما تحتاج إلى عمليات قائمة، مثل len() وreverse() وما إلى ذلك.

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

الملف الشخصي، الملف الشخصي، الملف الشخصي.

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

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

الملف الشخصي، الملف الشخصي، الملف الشخصي.

لا ينبغي لك أبدا أن تفضل zip زيادة izip, range زيادة xrange, ، أو قم بإدراج الفهم على قائمة الفهم المولد.في بايثون 3.0 range لديه xrange-مثل الدلالات و zip لديه izip-مثل الدلالات.

إن فهم القائمة هو في الواقع أكثر وضوحًا list(frob(x) for x in foo) لتلك الأوقات تحتاج إلى قائمة فعلية.

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

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

كما ذكر @u0b34a0f6ae في التعليقات، فإن استخدام المولدات في البداية يمكن أن يسهل عليك التوسع في مجموعات بيانات أكبر.

فيما يتعلق بالأداء:في حالة استخدام psyco، يمكن أن تكون القوائم أسرع قليلاً من المولدات.في المثال أدناه، تكون القوائم أسرع بنسبة 50% تقريبًا عند استخدام psyco.full()

import psyco
import time
import cStringIO

def time_func(func):
    """The amount of time it requires func to run"""
    start = time.clock()
    func()
    return time.clock() - start

def fizzbuzz(num):
    """That algorithm we all know and love"""
    if not num % 3 and not num % 5:
        return "%d fizz buzz" % num
    elif not num % 3:
        return "%d fizz" % num
    elif not num % 5:
        return "%d buzz" % num
    return None

def with_list(num):
    """Try getting fizzbuzz with a list comprehension and range"""
    out = cStringIO.StringIO()
    for fibby in [fizzbuzz(x) for x in range(1, num) if fizzbuzz(x)]:
        print >> out, fibby
    return out.getvalue()

def with_genx(num):
    """Try getting fizzbuzz with generator expression and xrange"""
    out = cStringIO.StringIO()
    for fibby in (fizzbuzz(x) for x in xrange(1, num) if fizzbuzz(x)):
        print >> out, fibby
    return out.getvalue()

def main():
    """
    Test speed of generator expressions versus list comprehensions,
    with and without psyco.
    """

    #our variables
    nums = [10000, 100000]
    funcs = [with_list, with_genx]

    #  try without psyco 1st
    print "without psyco"
    for num in nums:
        print "  number:", num
        for func in funcs:
            print func.__name__, time_func(lambda : func(num)), "seconds"
        print

    #  now with psyco
    print "with psyco"
    psyco.full()
    for num in nums:
        print "  number:", num
        for func in funcs:
            print func.__name__, time_func(lambda : func(num)), "seconds"
        print

if __name__ == "__main__":
    main()

نتائج:

without psyco
  number: 10000
with_list 0.0519102208309 seconds
with_genx 0.0535933367509 seconds

  number: 100000
with_list 0.542204280744 seconds
with_genx 0.557837353115 seconds

with psyco
  number: 10000
with_list 0.0286369007033 seconds
with_genx 0.0513424889137 seconds

  number: 100000
with_list 0.335414877839 seconds
with_genx 0.580363490491 seconds

فيما يتعلق بالأداء، لا أستطيع التفكير في أي وقت قد ترغب فيه في استخدام قائمة فوق المولد.

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

على سبيل المثال:

sorted(xrange(5))

لا يقدم أي تحسن على:

sorted(range(5))

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

على سبيل المثال:أنت تقوم بإنشاء قائمة ستقوم بتكرارها عدة مرات لاحقًا في برنامجك.

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

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