Author Topic: functools, itertools  (Read 440 times)

Ahmed Youssef

  • Helping Freak
  • Administrator
  • Active Member
  • *****
  • Posts: 242
    • View Profile
    • WWW
    • Email
functools, itertools
« on: February 09, 2009, 04:40:57 AM »
Functional Python

هذا الفصل اختيارى.. هنتكلم عن functools و itertools

functools

reduce(function, iterable[, init])
ملحوظة هى هى الدالة reduce
من اسمها "تقليل" الهدف منها هو تقليل sequence لقيمة واحدة
Code: [Select]
#reduce (func, seq[, init])
print reduce((lambda x, y: x+y), [1, 2, 3, 4, 5]) #15
#((((1+2)+3)+4)+5)
print reduce((lambda x, y: x*y), [1, 2, 3, 4, 5]) #120

partial(func, *args, **kwargs)
هدفها هو تغليف دالة ما ومعاملاتها واعادة كائن -مشابه للدوال- يحويها هذا المفهوم يسمى Currying
Code: [Select]
>>> def sayhi(to):
...     print "Hi, ", to

>>> f=lambda to="Ahmed":sayhi(to)
>>> f
<function <lambda> at 0xb7df08b4>
>>> f()
Hi,  Ahmed

نقدر نسهل نفس المثال بإستخدام partial كالتالى
Code: [Select]
>>> part_f=partial(sayhi, "Ahmed")
>>> part_f()
Hi,  Ahmed


تقدر تستخدمها بطريقة انك تغلف دالة ومجموعة معاملات قد تستكمل لاحقا
Code: [Select]
>>> def someparty(*guests):
...     print "Visitors: "
...     for g in guests:
...             print "\t", g

>>> someparty("Ahmed")
Visitors:
Ahmed
>>> someparty("Ahmed", "Mido")
Visitors:
Ahmed
Mido
>>> p=partial(someparty, "Ahmed")
>>> p("Mido")
Visitors:
Ahmed
Mido
>>> p
<functools.partial object at 0xb79d8d74>
>>> p("Mido", "Youssef")
Visitors:
Ahmed
Mido
Youssef


احد الإستخدامات العملية لها فى التعامل مع PyQt4 كالتالى مثلا -لأنك ستواجه صعوبة فى تمرير المتغيرات مع connect لل slot
Code: [Select]
self.connect(btn, SIGNAL("clicked()"),
             partial(self.onClicked, ARG))
طبعا تقدر تستخدم lambda بنفس الكيفية!

هنا مثلا نقوم بربط الإشارة clicked للزر button2 بslot -تغلف self.anyButton اللتى تأخذ معامل واحد اللتى يتم تنفيذها عند محاولة استدعاء الslot- هكذا قد تغلبنا على العملية اليس كذلك ؟


itertools, Anytime!

any(iterable)
عمرك كان عندك مثلا list من مجموعة ارقام وعايز تعرف هل فيها رقم اكبر من 3 مثلا ؟
Code: [Select]
print any(x>3 for x in [1, 3, 4, 5, 6, 7]) #True

all(iterable)
عمرك كان عندك مثلا list من مجموعة ارقام وعايز تعرف هل كلها اكبر من 3 مثلا ؟
Code: [Select]
print all(x>3 for x in [1, 3, 4, 5, 6, 7]) #False

الفكرة هى ان بتنشئ list من True/False ويتم حساب الناتج عن طريقها سواء على قيمة واحدة او كل القيم
لاحظ ان هنا ال iterable انشئناه بإستخدام ال list comprehension ولو اتكلمنا عنها تانى هنختصرها ل LC

repeat(obj, times=None)
بتقوم بعمل iterator يعيد نفس الكائن بعدد times او للأبد اذا كان None
Code: [Select]
>>> list(repeat(10, 3))
[10, 10, 10]

هنلاحظ ان الناتج [10, 10, 10] تم تكرار الكائن10 ل 3 مرات
وهكذا

takewhile(pred, seq)
بتأخذ عناصر من seq كلما يتم تأكيد الشرط المؤكد pred
Code: [Select]
>>> list(takewhile(lambda x: x<3, [0, 1, 2, 3, 4]))
[0, 1, 2]


dropwhile(pred, seq)
العكس بقة بتترك عناصر من seq كلما يتم تأكيد ال pred
Code: [Select]
>>> list(dropwhile(lambda x: x<3, [0, 1, 2, 3, 4, 6, 7]))
[3, 4, 6, 7]


groupby(seq[, key=None])
على فرض عندنا سلسلة من العناصر وعايزين نجمع كل العناصر من seq بإستخدام key function افتراضيا ال key هو العنصر- lambda x: x-
Code: [Select]
>>> list(groupby("111122233344"))

[('1', <itertools._grouper object at 0xb77ef36c>), ('2', <itertools._grouper object at 0xb77ef3ec>), ('3', <itertools._grouper object at 0xb77ef40c>), ('4', <itertools._grouper object at 0xb77ef42c>)]


print [list(i) for (x,i) in itertools.groupby("111122233344")]

الناتج
Code: [Select]
[['1', '1', '1', '1'], ['2', '2', '2'], ['3', '3', '3'], ['4', '4']]

وهكذا
الفكرة ان groupby بتجمع العناصر وبتعيدها فى صورة العنصر وiterator ليه و هكذا) فعشان كدا عملنا list I اذا عايز العناصر فقط مش list  خد قيمة ال x بس

مثال اخر
Code: [Select]
things = [("animal", "bear"), ("animal", "duck"), ("plant", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]
for key, group in groupby(things, lambda x: x[0]):
    for thing in group:
        print "A %s is a %s." % (thing[1], key)
    print " "

الناتج
Code: [Select]
A bear is a animal.
A duck is a animal.
A cactus is a plant.
A speed boat is a vehicle.
A school bus is a vehicle.


مرجع للمثال http://stackoverflow.com/questions/773/how-do-i-use-pythons-itertoolsgroupby

chain(*iters)
ينشئ iterator ليعيد العناصر من اول عنصر يتم تمريره حتى ينتهى فينتقل للعنصر التالى وهكذا
او تقدر تقول بتنشئ سلسلة بين ال iters
Code: [Select]
>>> for el in chain("Hello", "World", range(3)): 
...     print el


H
e
l
l
o
W
o
r
l
d
0
1
2


ifilter(pred, seq)
نفس فكرة filter ..تعيد iterator فى لكل عنصر يقع فى نطاق ال pred
Code: [Select]
>>> for x in ifilter(lambda x: x>3, [3,2, 1, 9, 8]): print x
...
9
8

Code: [Select]
>>> list(ifilter(lambda x: x>3, [3,2, 1, 9, 8]))
[9, 8]



filter=ifilter معادا فى كيفية اعادة الناتج
Code: [Select]
>>> filter(lambda x: x>3, [3, 2, 1, 9, 8])
[9, 8]

حيث تعيد filter ناتج من list بينما تعيد ifilter ناتج من iterator

ifilterfalse(pred, seq)
حيث تعيد iterator لكل عنصر لايقع فى نطاق pred
Code: [Select]
>>> list(ifilterfalse(lambda x: x>3, [3, 2, 1, 9, 8]))
[3, 2, 1]


izip(*iters)
 خمن؟ ايوه صح هى فعلا مشابهه ل zip ولكن بتعيد iterator
Code: [Select]
>>> list(izip("Hell", [1,2,3, 4]))
[('H', 1), ('e', 2), ('l', 3), ('l', 4)]
>>> zip("Hell", [1,2,3,4])
[('H', 1), ('e', 2), ('l', 3), ('l', 4)]


للمزيد راجع وثائق python حولهم

« Last Edit: February 09, 2009, 06:02:36 AM by Ahmed Youssef »
Logged

Life is just a chance to grow a soul. - A. Powell
Weblog: http://ahmedyoussef.wordpress.com/