Programming Freaks  | دورات ومقالات برمجيه

Please login or register.

Login with username, password and session length
Advanced search  

News:

Please Read our FAQ

Author Topic: Functions/Procedures  (Read 1585 times)

Striky

  • Helping Freak
  • Administrator
  • Posting Freak
  • *****
  • Posts: 252
    • View Profile
    • WWW
    • Email
Functions/Procedures
« on: October 26, 2008, 04:21:19 AM »
Chapter 4(Functions & Procedures)

ال Functions واستخدامها اتسمى عليها paradigm كامل Functional Programming او Procedural Programming وكان/مازال شائع جدا للآن
لغات مثل السى وباسكال بتعتمد على الFunctions كحجر اساس

ايه هى ال Function  او ال Procedure ؟
هى بلوك من الأكواد اتكتب لإمكانية استخدامه اكثر من مرة

مثلا عايزين نطبع رسالة كالتالى
Python rocks!
لأكتر من مرة فى برنامجنا لسبب ما.. هل يعقل انى اكتب
Code: [Select]
Code: [Select]
print Python rocks! 

فى كل مرة ؟ ولنفرض انى كتبتها 20 مرة هل يعقل انى اذا حبيت اعدل التعبير بدل Python rocks ل Perl rocks انى اعدل فيه 20 مرة؟
من هنا جت اهمية ال Functions وهى تستخدم ل
توفير وقت ومجهود وتطبيق مبدأ DRY
DRY: Don't Repeat Yourself
 
كل اللى عليك هو انك تحط الرسالة فى function
Code: [Select]
>>> def rocks():
print "Python rocks!"


وتستدعيها كل ماتحب
Code: [Select]
>>> rocks()
Python rocks!
>>> rocks()
Python rocks!
>>> rocks()
Python rocks!

لاحظ انك اذا حبيت تعدل كلمة Python ل Perl مثلا مش هتحتاج تعدل فى اى شئ غير فى ال rocks function فقط تحولها للتالى
Code: [Select]
>>> def rocks():
print "Perl rocks!"


لاحظت الفرق ؟توفير وقت ومجهود ومش كررت نفسك فى مليون سطر
طب تمام لكن فيه مشكلة لحد الوقتى وهى اننا اضطرينا نعدل جوا ال function ونستبدل كلمة مكان كلمة وهكذا فعايزين نخليها ابسط فى الإستخدام بحيث انها تطبع اللى إحنا عايزنها تطبعه (ال دالة فيها متغير معين )فالحل هو اننا نعيد تعريفها كالتالى مثلا
Code: [Select]
>>> def rocks(thing):
print thing, "rocks!"

كدا هيتم طباعة ال argument اللى هيتباصى  + كلمة rocks!  كالتالى
Code: [Select]
>>> rocks("Python")
Python rocks!
>>> rocks("Perl")
Perl rocks!
>>>

جميل نفس الفكرة عايزين نعمل function تجمع 2+3 وتطبع الناتج لينا
Code: [Select]
>>> def add():
print 2+3

استخدمها كالتالى
Code: [Select]
>>> add()
5

لكن هل لاحظت شئ ؟ انها مقيدة بمعنى انى مش قادر استخدم غير 2+3 فقط طب افرض انا عايز احدد ارقام من عندى ايه الحل ؟
همممم نفس فكرة المثال اللى قبله انك تباصى الأرقام اللى تعجبك ك arguments لل add function ودا هيتم الأول
1- انك تعيد تعريف ال function كالتالى مثلا
Code: [Select]
>>> def add(first, second):
print first + second

2- تستخدمها
Code: [Select]
>>> add(2, 3)
5
>>> add(3, 7)
10

ارسال ال arguments للدالة
Code: [Select]
def printArgs(first, second, third):
    print "First: ", first
    print "Second: ", second
    print "Third: ", third

لاحظ لإستخدام الدالة هنستدعيها كالتالى
Code: [Select]
printArgs("Hello", "Cruel", "World")

#outputFirst:  Hello
Second:  Cruel
Third:  World



ولكن على فرض انى عايز احدد قيم اساسية او حتى ادخل الarguments مش بالترتيب!؟
بكل بساطة تقدر تستدعيها كدا
Code: [Select]
printArgs(third="World", second="Curel", first="Hello")

بحيث انك تحدد قيمة كل عنصر بإستخدام الإسناد (لأنهم متغيرات واضحة للدالة ;)
ولتحديد قيم افتراضية ؟ مثلا عايز ادخل قيمتين او قيمة واحدة او حتى مش ادخل اى قيمة!!؟؟
تقدر تحدد دا من خلال تعريف الدالة نفسها مثلا كالتالى
Code: [Select]
def printArgs(first="Hello", second="Cruel", third="World"):
    print "First: ", first
    print "Second: ", second
    print "Third: ", third
    print "-"*20

printArgs("Bye") #Changes the first..
printArgs(second="") #only the second is set to “”
printArgs()

والناتج
Code: [Select]
First:  Bye
Second:  Cruel
Third:  World
--------------------
First:  Hello
Second: 
Third:  World
--------------------
First:  Hello
Second:  Cruel
Third:  World
--------------------


وهكذا.. دا مفيد فى موضوع ال overloading لل function (بحيث ان يتم تنفيذ اكتر من وظيفه لنفس الfunction إعتمادا على الarguments المرسلة) تابع range
لحد الآن ال Functions غير مفيدة لأنها مش بتعيد قيمة يعنى مش تقدر تستفيد منها فى برنامجك انك تعمل كالتالى مثلا
Code: [Select]
>>> val=add(2, 3)
5
>>> print val
None


*ايه دا ؟ انا كنت متوقع ان val هتكون قيمتها 5!
دا هيتم فى حالة واحدة ان الطرف اليمين من الexpression تكون قيمته 5 لكن add(2, 3) قيمته None لأنه بيعمل print لمجموع الرقمين لكن مش بيعمل بيهم return


*ايه None ؟
None=null=nil=Nothing


جميل طب ازاى اخلى قيمة ال Function تساوى مجموع الرقمين ؟
بسيطة اعمل return بالمجموع!
كالتالى مثلا
Code: [Select]
>>> def add(first, second):
return first+second

>>> val=add(2, 3)
>>> print val
5


هنا return عبرت عن قيمة الFunction

كتير للأسف مش يعرف الفرق بين ال Functions وال Procedures
على كل حال اعتبرها كالتالى
ال Procedure هو اى Function مش ليها return

--لمبرمجى السى/++ والجافا اى Function ال return بتاعها void يبقة اسمها Procedure

بايثون بتقدم ليك العديد من ال Functions الجاهزة مثل
raw_input(prompt)
للحصول على الداتا من المستخدم
input(prompt)
زى ماقلنا هى بتستدعى التالى
Code: [Select]
eval(raw_input(prompt))


eval(expression)
بتحقق قيمة ال expression

abs(number)
بتعيد ليك ال Absolute value -القيمة المطلقة- وهى العدد بدون اشارة
Code: [Select]
>>> abs(10)
10
>>> abs(-10)
10

*تدريب:
اكتب Function بإسم getABS وبتاخد argument واحدة بإسم number ومشابهه ل abs

max(iterable)
هى function بتاخد container فى الغالب -اى شئ ممكن يطبق عليه foreach- وتعيد اكبر قيمة فيه كالتالى مثلا
Code: [Select]
>>> max([3, 4, 5, 6])
6
>>> max("Ahmed")
'm'


min(iterable)
هى العكس من max وهى بتعيد اصغر قيمة
Code: [Select]
>>> min("Ahmed")
'A'
>>> min([3, 4, 5, 6])
3


ملحوظة: اصغر قيمة للأحرف بتم بناء على قيمتها فى ASCII وتقدر تحصل عليها من خلال ord
وللحصول على الحرف من خلال القيمة بنستخدم chr
ord(char)

Code: [Select]
>>> ord("A")
65
>>> ord("a")
97
>>> chr(65)
'A'
>>> chr(97)
'a'


sum(seq)
بتستخدم للحصول على مجموع sequence ما كالتالى
Code: [Select]
>>> sum([1, 2, 3, 4, 5])
15

*تدريب اكتب function مشابهه ل sum وبإسم getSum وبتاخد sequence ك argument

oct(num)
بتعيد القيمة من النظام الثمانى لل num
Code: [Select]
>>> oct(15)
'017'

hex(num)

بتعيد القيمة من النظام الست عشرى لل num
Code: [Select]
>>> hex(15)
'0xf'


len(object)
فى الواقع len استخدامها بيختلف حسب نوع ال argument اللى هتتباصى ليها يعنى مثلا إذا كان string هيتم اعادة عدد الحروف وإذا كانت list هيتم إعادة عدد العناصر المكونة ليها وهكذا
Code: [Select]
>>> len("Ahmed")
5
>>> len([1, 2, 3, 4, 5, 6])
6


هنتعلم قريب ازاى نحدد الطريقة اللى هتتعامل بيها len مع ال objects بتاعتنا :D

round(f_num, digits)

هى function بتعمل تقريب ل f_num بعدد معين من الأرقام بيساوى digits كالتالى مثلا
Code: [Select]
>>> round(2678.367789)
2678.0
>>> round(2678.367789, 4)
2678.3678


copyright()
Code: [Select]
>>> copyright()
Copyright (c) 2001-2008 Python Software Foundation.
All Rights Reserved.

Copyright (c) 2000 BeOpen.com.
All Rights Reserved.

Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.

Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved.

بتعرضلك ل copyright الخاص ببيثون
credits()
بتعرضلك ال credits
Code: [Select]
>>> credits()
    Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
    for supporting Python development.  See www.python.org for more information.

range(end)
بتعيد ليك list من 0 لحد end بزيادة قيمتها 1
Code: [Select]
>>> range(10) #0 to 10
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


range(start, end)
بتعيد ليك List من start لحد end بزيادة قيمتها 1
Code: [Select]
>>> range(1, 5) #1 to 5
[1, 2, 3, 4]

range(start, end, step)
بتعيد ليك list من start لحد end بزيادة مقدراها step
Code: [Select]
>>> range(1, 20, 3) #1 to 20 with step=3
[1, 4, 7, 10, 13, 16, 19]

*تدريب اكتب function تقوم بعرض جدول ال ASCII


To *args or not to *args
عنوان عجيب
مثال على دالة sum
Code: [Select]
def mysum(alist):
    total=0
    for i in alist:
        total += i

    return total

لإستخدامها هنباصى list من الأرقام الي الدالة ك argument كالتالى
Code: [Select]
print mysum([1, 2, 3, 4, 5])


مثال بإستخدام *args
Code: [Select]
def newsum(*args):
    total=0
    for i in args:
        total +=i
    return total


لإستخدامها: هنباصى الأرقام ك arguments للدالة كالتالى
Code: [Select]
print newsum(1, 2, 3, 4, 5)


انشاء دالة مشابة ل printf
Code: [Select]
def printf(fmt, *args):
    print fmt%args

printf("Name: %s, Age: %d", "Ahmed", 20)
#converted to  print "Name %s, Age: %d"%("Ahmed", 20)

لاحظ ان هيتم التحويل *args إلى دالة print لإستبدال ال place holders  (%s, %d) بالقيم المدخلة
*تدريب "اكتب sprintf بإستخدام بايثون

To **kwargs or not to **kwargs
بتباصى مفاتيح keys للدالة مثال
Code: [Select]
def newprintf(fmt, *args, **kwargs):
    print "fmt: ", fmt
    print "*args: ", args
    print "**kwargs: ", kwargs
    #do something usefu
    if kwargs.has_key("verbose"):
        print "Verbose..."


newprintf("This is some FMT", 1, 2, 3, 4, 5, 6, verbose=True, cleanup=True, use_ssl=False


الناتج
Code: [Select]
fmt:  This is some FMT
*args:  (1, 2, 3, 4, 5, 6)
**kwargs:  {'use_ssl': False, 'cleanup': True, 'verbose': True}
Verbose...


Going global

انك توثق الدالة وبتعمل اية وبتاخد معاملات ايه شئ ممتاز فى اى برنامج لان اهمية التوثيق من اهمية الكود
Code: [Select]
def newprintf(fmt, *args, **kwargs):
    """Simple function to learn out howto use *, ** trick in functions."""
    print "fmt: ", fmt
    print "*args: ", args
    print "**kwargs: ", kwargs
    #do something usefu
    if kwargs.has_key("verbose"):
        print "Verbose..."

لاحظ ان اول سطر بعد التعريف بيعبر عن ال doc او وثيقة الدالة (ملف المساعدة بتاعها:d )

تقدر تستدعى ال .__doc__ من الدالة ليعرضلك جزئية المساعدة الخاصة بيها او تستدعى دالة help عليها
.__doc__

Code: [Select]
print newprintf.__doc__ #STR

#output:
Simple function to learn out howto use *, ** trick in functions.
Help on function newprintf in module __main__:


help
Code: [Select]
help(newprintf)

#output
newprintf(fmt, *args, **kwargs)
    Simple function to learn out howto use *, ** trick in functions.


على فرض ان عندنا متغيرات عامة فى الملف بتاعنا ومتاجين نستخدمها فى دالة معينة هنعمل اية ؟
استخدم global كالتالى

Code: [Select]
__DEBUG=True

def isdebug():
    global __DEBUG
    return __DEBUG

print "Debug? ", isdebug()

#output:
Debug?  True



كل المطلوب انك تعرف الدالة اللى هتستدعى فيها متغيرك العام بإنه global بإستخدام global ويليها اسم المتغير

او تقدر تستخدم globals() كقاموس للمتغيرات العامة كالتالى مثلا
Code: [Select]
__DEBUG=False

def isdebug():
    x, y, z=range(3)
    print locals()
    return globals()["__DEBUG"]

print isdebug()

#output:
#{'y': 1, 'x': 0, 'z': 2}
#False





لاحظ استخدام locals() هنا بتعيد قاموس ايضا بيعبر عن المتغيرات المحلية فى سياقها مثل x,y,z محليين فى السياق الموجودة فيه وهو الدالة isdebug

Lambda/Anonymous Functions

قراءتك لهذه الجزئية اختيارية

بايثون بتتيحلك استخدام الدوال المجهولة ودا باستخدام lambda مستعارة من لغة lisp

Code: [Select]
def getName(name):
    return name

anonyFunc=lambda name: name

print anonyFunc("Mido")
print getName("Mido")

#Output:
#Mido
#Mido


مابعد lambda هو ال args ومايليها هو ال return
Code: [Select]
def getSum(*args):
    return sum(args)

anonySum=lambda *args: sum(args)

print getSum(1, 2, 3, 4, 5)
print anonySum(1, 2, 3, 4, 5)

#Output:
15
15


map
بتطبق function معينة على مجموعة من العناصر
Code: [Select]
print map(lambda w: w.upper(), ["ahmed", "mostafa", "omar"])

هنا هيتعمل ريترن بنسخة من العناصر بعد التعديل (التحويل للحروف الكبيرة)
Code: [Select]
['AHMED', 'MOSTAFA', 'OMAR']


استخدام lambda مش واضح بالنسبة ليك مش مشكلة استبدلها كالتالى
Code: [Select]
def toupper(w):
    return w.upper()

users=["ahmed", "mostafa", "omar"]
print map(toupper, users)

#output:
#['AHMED', 'MOSTAFA', 'OMAR']


صحيح ايه ال w اللى كانت فى lambda وموجود فى toupper ك parameter دى ؟
ال w دى بتعبر عن كل عنصر فى ال sequence هتطبق عليه الدالة


filter
بنستخدمها لتصفية sequence معينة هنشوف مثال
Code: [Select]
numbers=range(20)
print filter(lambda i: i&1, numbers) #odds.
print filter(lambda i: not i&1, numbers) #evens

#output:
#[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
#[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

لاحظ هنا فى المثال عندنا مجموعة ارقام من 0 ل 19
هنستخدم قاعدة n & 1 لإختبار هل الرقم فردى او زوجى (او اى طريقة تعجبك) زى ماشايفين فى المثال بإستخدام lambda وبالفعل بيتم التصفية بناءا على القاعدة اللى حاطينها فى الfunction

المثال بدون استخدام lambda
Code: [Select]
def isodd(i):
    if i&1:
        return True
    return False

def iseven(i):
    return not isodd(i)

print filter(isodd, numbers) #odds
print filter(iseven, numbers)#evens

#output:
#[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
#[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]


اماكن استخدام lambda ؟ يفضل تستخدمها مع ال properties كبديل لل getters (تابع الفصل القادم او فى دالة ب سطر واحد)



« Last Edit: October 28, 2008, 02:01:15 AM by Ahmed Youssef »
Logged

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