PythonGuide/Functions Procedures

من PFWiki

اذهب إلى: تصفح, البحث

محتويات

الفصل الثالث (الدوال والأجراءات)

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

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

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

 
print Python rocks!

فى كل مرة ؟ ولنفرض انى كتبتها 20 مرة هل يعقل انى اذا حبيت اعدل التعبير بدل Python rocks ل Perl rocks انى اعدل فيه 20 مرة؟ من هنا جت اهمية ال Functions وهى تستخدم ل توفير وقت ومجهود وتطبيق مبدأ DRY DRY: Don't Repeat Yourself

كل اللى عليك هو انك تحط الرسالة فى function

>>> def rocks():
	print "Python rocks!"


وتستدعيها كل ماتحب

>>> rocks()
Python rocks!
>>> rocks()
Python rocks!
>>> rocks()
Python rocks!

لاحظ انك اذا حبيت تعدل كلمة Python ل Perl مثلا مش هتحتاج تعدل فى اى شئ غير فى ال rocks function فقط تحولها للتالى

>>> def rocks():
	print "Perl rocks!"


لاحظت الفرق ؟توفير وقت ومجهود ومش كررت نفسك فى مليون سطر طب تمام لكن فيه مشكلة لحد الوقتى وهى اننا اضطرينا نعدل جوا ال function ونستبدل كلمة مكان كلمة وهكذا فعايزين نخليها ابسط فى الإستخدام بحيث انها تطبع اللى إحنا عايزنها تطبعه (ال دالة فيها متغير معين )فالحل هو اننا نعيد تعريفها كالتالى مثلا

>>> def rocks(thing):
	print thing, "rocks!"

كدا هيتم طباعة ال argument اللى هيتمرر + كلمة rocks! كالتالى

>>> rocks("Python")
Python rocks!
>>> rocks("Perl")
Perl rocks!
>>>

جميل نفس الفكرة عايزين نعمل function تجمع 2+3 وتطبع الناتج لينا

>>> def add():
	print 2+3

استخدمها كالتالى

>>> add()
5

معاملات الدوال

لكن هل لاحظت شئ ؟ انها مقيدة بمعنى انى مش قادر استخدم غير 2+3 فقط طب افرض انا عايز احدد ارقام من عندى ايه الحل ؟ همممم نفس فكرة المثال اللى قبله انك تمرر الأرقام اللى تعجبك ك arguments لل add function ودا هيتم الأول 1- انك تعيد تعريف ال function كالتالى مثلا

>>> def add(first, second):
	print first + second

2- تستخدمها

>>> add(2, 3)
5
>>> add(3, 7)
10

ارسال ال arguments للدالة

def printArgs(first, second, third):
    print "First: ", first
    print "Second: ", second
    print "Third: ", third

لاحظ لإستخدام الدالة هنستدعيها كالتالى

printArgs("Hello", "Cruel", "World")
 
#outputFirst:  Hello
Second:  Cruel
Third:  World

معاملات ذات قيمة افتراضية

ولكن على فرض انى عايز احدد قيم اساسية او حتى ادخل الarguments مش بالترتيب!؟ بكل بساطة تقدر تستدعيها كدا

printArgs(third="World", second="Curel", first="Hello")

بحيث انك تحدد قيمة كل عنصر بإستخدام الإسناد (لأنهم متغيرات واضحة للدالة ;) ولتحديد قيم افتراضية ؟ مثلا عايز ادخل قيمتين او قيمة واحدة او حتى مش ادخل اى قيمة!!؟؟ تقدر تحدد دا من خلال تعريف الدالة نفسها مثلا كالتالى

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()

والناتج

First:  Bye
Second:  Cruel
Third:  World
--------------------
First:  Hello
Second:  
Third:  World
--------------------
First:  Hello
Second:  Cruel
Third:  World
--------------------


وهكذا.. دا مفيد فى موضوع ال overloading لل function (بحيث ان يتم تنفيذ اكتر من وظيفه لنفس الfunction إعتمادا على الarguments المرسلة) تابع range

اين القيمة العائدة من الدالة من الدالة

لحد الآن ال Functions غير مفيدة لأنها مش بتعيد قيمة يعنى مش تقدر تستفيد منها فى برنامجك انك تعمل كالتالى مثلا

>>> 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 بالمجموع! كالتالى مثلا

>>> 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) زى ماقلنا هى بتستدعى التالى

eval(raw_input(prompt))


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

abs(number) بتعيد ليك ال Absolute value -القيمة المطلقة- وهى العدد بدون اشارة

>>> abs(10)
10
>>> abs(-10)
10
  • تدريب:

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

max(iterable) هى function بتاخد container فى الغالب -اى شئ ممكن يطبق عليه foreach- وتعيد اكبر قيمة فيه كالتالى مثلا

>>> max([3, 4, 5, 6])
6
>>> max("Ahmed")
'm'


min(iterable) هى العكس من max وهى بتعيد اصغر قيمة

>>> min("Ahmed")
'A'
>>> min([3, 4, 5, 6])
3


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

>>> ord("A")
65
>>> ord("a")
97
>>> chr(65)
'A'
>>> chr(97)
'a'


sum(seq) بتستخدم للحصول على مجموع sequence ما كالتالى

>>> sum([1, 2, 3, 4, 5])
15
  • تدريب اكتب function مشابهه ل sum وبإسم getSum وبتاخد sequence ك argument

oct(num) بتعيد القيمة من النظام الثمانى لل num

>>> oct(15)
'017'

hex(num)

بتعيد القيمة من النظام الست عشرى لل num

>>> hex(15)
'0xf'


len(object) فى الواقع len استخدامها بيختلف حسب نوع ال argument اللى هتتمرر ليها يعنى مثلا إذا كان string هيتم اعادة عدد الحروف وإذا كانت list هيتم إعادة عدد العناصر المكونة ليها وهكذا

>>> len("Ahmed")
5
>>> len([1, 2, 3, 4, 5, 6])
6


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

round(f_num, digits)

هى function بتعمل تقريب ل f_num بعدد معين من الأرقام بيساوى digits كالتالى مثلا

>>> round(2678.367789)
2678.0
>>> round(2678.367789, 4)
2678.3678


copyright()

>>> 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

>>> 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

>>> range(10) #0 to 10
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


range(start, end) بتعيد ليك List من start لحد end بزيادة قيمتها 1

>>> range(1, 5) #1 to 5
[1, 2, 3, 4]

range(start, end, step) بتعيد ليك list من start لحد end بزيادة مقدراها step

>>> range(1, 20, 3) #1 to 20 with step=3
[1, 4, 7, 10, 13, 16, 19]
  • تدريب اكتب function تقوم بعرض جدول ال ASCII

استخدام *args

عنوان عجيب مثال على دالة sum

def mysum(alist):
    total=0
    for i in alist:
        total += i
 
    return total

لإستخدامها هنمرر list من الأرقام الي الدالة ك argument كالتالى

print mysum([1, 2, 3, 4, 5])


مثال بإستخدام *args

def newsum(*args):
    total=0
    for i in args:
        total +=i
    return total


لإستخدامها: هنمرر الأرقام ك arguments للدالة كالتالى

print newsum(1, 2, 3, 4, 5)


انشاء دالة مشابة ل printf

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 بإستخدام بايثون

استخدام **kwargs

بتمرر مفاتيح keys للدالة مثال

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


الناتج

fmt:  This is some FMT
*args:  (1, 2, 3, 4, 5, 6)
**kwargs:  {'use_ssl': False, 'cleanup': True, 'verbose': True}
Verbose...

توثيق الدالة

انك توثق الدالة وبتعمل اية وبتاخد معاملات ايه شئ ممتاز فى اى برنامج لان اهمية التوثيق من اهمية الكود

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__

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


help

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


متغيرات عامة

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

__DEBUG=True
 
def isdebug():
    global __DEBUG
    return __DEBUG
 
print "Debug? ", isdebug()
 
#output: 
Debug?  True


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

او تقدر تستخدم globals() كقاموس للمتغيرات العامة كالتالى مثلا

__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

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

def getName(name):
    return name
 
anonyFunc=lambda name: name
 
print anonyFunc("Mido")
print getName("Mido")
 
#Output:
#Mido
#Mido


مابعد lambda هو ال args ومايليها هو ال return

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 معينة على مجموعة من العناصر

print map(lambda w: w.upper(), ["ahmed", "mostafa", "omar"])

هنا هيتعمل ريترن بنسخة من العناصر بعد التعديل (التحويل للحروف الكبيرة)

['AHMED', 'MOSTAFA', 'OMAR']


استخدام lambda مش واضح بالنسبة ليك مش مشكلة استبدلها كالتالى

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 معينة هنشوف مثال

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

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 (تابع الفصل القادم او فى دالة ب سطر واحد)

→ Python Basics Functions Procedures OOP Basics ←
أدوات شخصية