PythonGuide/Functional Programming
من PFWiki
البرمجة الوظيفية وبايثون
هذا الفصل اختيارى.. هنتكلم عن وحدتى functools و itertools
functools
reduce(function, iterable[, init]) ملحوظة هى هى الدالة reduce من اسمها "تقليل" الهدف منها هو تقليل sequence لقيمة واحدة
#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
>>> def sayhi(to): ... print "Hi, ", to >>> f=lambda to="Ahmed":sayhi(to) >>> f <function <lambda> at 0xb7df08b4> >>> f() Hi, Ahmed
نقدر نسهل نفس المثال بإستخدام partial كالتالى
>>> part_f=partial(sayhi, "Ahmed") >>> part_f() Hi, Ahmed
تقدر تستخدمها بطريقة انك تغلف دالة ومجموعة معاملات قد تستكمل لاحقا
>>> 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
self.connect(btn, SIGNAL("clicked()"), partial(self.onClicked, ARG))
طبعا تقدر تستخدم lambda بنفس الكيفية!
هنا مثلا نقوم بربط الإشارة clicked للزر button2 بslot -تغلف self.anyButton اللتى تأخذ معامل واحد اللتى يتم تنفيذها عند محاولة استدعاء الslot- هكذا قد تغلبنا على العملية اليس كذلك ؟
itertools
any(iterable) عمرك كان عندك مثلا list من مجموعة ارقام وعايز تعرف هل فيها رقم اكبر من 3 مثلا ؟
print any(x>3 for x in [1, 3, 4, 5, 6, 7]) #True
all(iterable) عمرك كان عندك مثلا list من مجموعة ارقام وعايز تعرف هل كلها اكبر من 3 مثلا ؟
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
>>> list(repeat(10, 3)) [10, 10, 10]
هنلاحظ ان الناتج [10, 10, 10] تم تكرار الكائن10 ل 3 مرات وهكذا
takewhile(pred, seq) بتأخذ عناصر من seq كلما يتم تأكيد الشرط المؤكد pred
>>> list(takewhile(lambda x: x<3, [0, 1, 2, 3, 4])) [0, 1, 2]
dropwhile(pred, seq)
العكس بقة بتترك عناصر من seq كلما يتم تأكيد ال pred
>>> 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-
>>> 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")]
الناتج
[['1', '1', '1', '1'], ['2', '2', '2'], ['3', '3', '3'], ['4', '4']]
وهكذا الفكرة ان groupby بتجمع العناصر وبتعيدها فى صورة العنصر وiterator ليه و هكذا) فعشان كدا عملنا list I اذا عايز العناصر فقط مش list خد قيمة ال x بس
مثال اخر
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 " "
الناتج
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
>>> 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
>>> for x in ifilter(lambda x: x>3, [3,2, 1, 9, 8]): print x ... 9 8
>>> list(ifilter(lambda x: x>3, [3,2, 1, 9, 8])) [9, 8]
filter=ifilter معادا فى كيفية اعادة الناتج
>>> filter(lambda x: x>3, [3, 2, 1, 9, 8]) [9, 8]
حيث تعيد filter ناتج من list بينما تعيد ifilter ناتج من iterator
ifilterfalse(pred, seq) حيث تعيد iterator لكل عنصر لايقع فى نطاق pred
>>> list(ifilterfalse(lambda x: x>3, [3, 2, 1, 9, 8])) [3, 2, 1]
izip(*iters)
خمن؟ ايوه صح هى فعلا مشابهه ل zip ولكن بتعيد iterator
>>> 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 حولهم
