آموزش برنامه نویسی پایتون#جلسه هفتم

آموزش برنامه نویسی پایتون#جلسه هفتم

بسم الله الرحمن الرحیم

جلسه هفتم_ تابع

تابع چیست؟

تابع، مجموعه‌ای از کدها یا قطعه‌کدی است که با یک نام خاص یا محدودۀ اسمی یکتا شناخته می‌شود. عملیات مشخصی را انجام داده و مقداری را به عنوان نتیجه باز می گرداند. نتیجۀ یک تابع می‌تواند در دفعات مختلف اجرا متفاوت باشد زیرا می توان پارامترهایی را به کد مورد نظر ارسال کرد و نتایج حاصل از آن ورودی مشخص را دریافت کرد.

Pythonlogo

بسم الله الرحمن الرحیم

جلسه هفتم_ تابع در پایتون

تابع چیست؟

تابع، مجموعه‌ای از کدها یا قطعه‌کدی است که با یک نام خاص یا محدودۀ اسمی یکتا شناخته می‌شود. عملیات مشخصی را انجام داده و مقداری را به عنوان نتیجه باز می گرداند. نتیجۀ یک تابع می‌تواند در دفعات مختلف اجرا متفاوت باشد زیرا می توان پارامترهایی را به کد مورد نظر ارسال کرد و نتایج حاصل از آن ورودی مشخص را دریافت کرد.

مزایای استفاده از تابع در پایتون:

·       Reusable code: ساده ترین روش برای قطعه‌بندی منطقی کد به منظور استفادۀ مجدد در زمان و مکانی دیگر استفاده از تابع است. با استفاده از تابع تمام کدهای نوشته شده به‌صورت متوالی و سریع اجرا می‌شوند. با استفاده از توابع می‌توان از بخشی از کد به دفعات استفاده کرد، بدون اینکه نیازی به تعریف مجدد یک قطعه کد باشد. 

·       Easier to maintain: با استفاده از توابع، در صورت نیاز به تغییر بخشی از کد، فقط کافی است کد اصلی مربوط به توابع را تغییر داد و سایر فراخوانی های توابع نیازی به تغییر ندارند.

·       Increase readability: استفاده از توابع، قابلیت خوانده شدن کد را افزایش می دهد.

·       Procedural Analysis: با استفاده از توابع، کل برنامه به رویه‌ها یا بخش‌هایی کوچک و مشخص تجزیه می‌شود و می‌توان به‌صورت جداگانه روی بخش‌های مختلف آن کار کرد. هریک از این بخش‌ها یا توابع کار مشخصی انجام می‌دهند. به عبارتی یک مسئلۀ پیچیده و بزرگ به مسایل کوچک و روشنی تقسیم می شود که هر یک جداگانه پیاده‌سازی می‌شوند.

Built-in Function یا builtins (توابع از پیش ساخته شده)

 تعداد محدودی از فانکشن ها هستند که توسعه دهندگان پایتون به صورت پیش فرض آن ها را برای مفسر پایتون تعریف کرده اند و برنامه نویسان می توانند هر زمان که به این فانکشن ها نیاز داشتند، از آن ها استفاده کنند. برای مثال توابع print() و len()، str()،float() و...جزء توابع پیش فرض پایتون هستند.

علت اصلی تعریف  توابع پیش فرض این است که کاربرد آن ها بسیار زیاد است و تعریف آن ها به صورت پیش فرض به برنامه نویسان کمک می کند تا بدون درگیر شدن با پیچیدگی های کدنویسی، بتوانند در زمان نیاز به راحتی از آن ها استفاده کنند.

توجه داشته باشید با وجود آن که یک تابع می تواند آرگومان های متنوعی را به عنوان ورودی خود بگیرد، باز هم محدودیت هایی روی نوع آرگومان های ورودی آن وجود دارد.

اکثر توابع پیش ساخته پایتون در ماژولی با نام __builtin__ (در پایتون 2)  و یا builtins (در پایتون 3) قرار دارند.

توابع از پیش ساخته علاوه بر آنکه متدهایی را برای زمان طراحی یا اجرای کد ارائه می دهند، وقتی در برنامه استثنایی رخ می دهد و خطاهایی از جمله syntax error، datatype error یا argument error اتفاق می افتد، این توابع اطلاعات بسیار خوبی را در اختیار قرار می دهند.

به توابع پیش ساخته که به صورت" __name__" در پایتون وجود دارند، متدهای "special " یا متدهای "magic " گفته می شود. علت استفاده از علامت "__"(underscore) به همراه نام این متدها برای آن است که از تداخل این نام ها با نامهای تعریف شده توسط کاربر جلوگیری شود.

در مورد توابع پیش ساخته تابع len() مثال خوبی است. برای استفاده از این تابع نام تابع (len()) را به همراه علامت نقطه (.) بعد از نام دنباله ای که از پیش تعریف کرده ایم می آوریم تا تعداد اعضای توالی مورد نظر را نشان دهد. اما در اصل تابع" __len__() " فراخوانی می شود که برای سادگی و کوتاه تر شدن فراخوانی تابع، از len() استفاده می کنیم.

 


>>> a = [1,2,3,4]
>>> a.__len__()
4

Pythonlearning

در مثال زیر ماژول __builtin__ (در پایتون 2)  و یا builtins (در پایتون 3)، import  شده است. سپس تابع dir() لیستی از نام تمام ماژول ها، متغیرهاو فانکشن هایی که در ماژول مربوطه تعریف شده اند را به صورت الفبایی مرتب کرده و نشان می دهد(با توجه به آنکه این تابع یک لیست را نشان می دهد، خروجی در براکت قرار گرفته است.) . برای آنکه در مورد هر یک از فانکشن ها و سایر عناصر موجود در ماژول اطلاعات بیشتری بیابیم، می توان از تابع help استفاده کرد و نام ماژول را به همراه نام عنصر مورد نظر فراخوانی کرد.

 



>>> import __builtin__
>>> dir(__builtin__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
>>> help(__builtin__.len)
Help on built-in function len in module __builtin__:

len(...)
    len(object) -> integer
    
    Return the number of items of a sequence or collection.



>>> __builtin__.__doc__
"Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices."

فضای نامی و تفاوت متد و فانکشن:

متد و فانکشن هر دو بلاک هایی از کد (code block)هستند که برای هدف خاصی نوشته می شوند و خروجی مشخصی را بر می گردانند. اما فانکشن یک بلاک کد تنها است(stand-alone code block) که به طور مستقل فراخوانی می شود، در حالی که یک متد، فانکشنی است که مرتبط با یک شیء (object) است.

برای فراخوای یک متد باید آن را بعد از علامت نقطه " . " بعد از نام شیء ای که قبلا تعریف شده است، آورد. در مثال زیر متد append() برای لیست مورد نظر فراخوانی شده است.

 



>>> mylist = ['a', 1,2]
>>> mylist.append('New element')



در پایتون هر چیزی اعم از عدد، رشته، فانکشن و کلاس یک object می باشد و به هر چیزی حتی متغیرها می توان در پایتون یک نام اختصاص داد. حتی مکن است چندین مقدار از نوع های مختلف به یک نام نسبت داده شوند.

فضای نامی (namespace) فضایی است که مجموعه ای از نام ها را نگه داری می کند به طوری که می توان آنها را مانند لیستی از نام ها در نظر گرفت. فضای نام هر زمان که نیاز باشند، ایجاد می شوند.

ماژول، فایلی شامل کدهای پایتون است. این کد می تواند به فرم کلاس ها، فانکشن ها و یا فقط لیستی از نامهای پایتون باشد. هر ماژول دارای فضاهای نام عمومی (global namespace) خاص خود است. به همین دلیل نمی توان دو کلاس یا دو فانکشن با نام یکسان در یک ماژول داشت که فضای نام آن ماژول را با هم به اشتراک گذاشته باشند (مگر اینکه به صورت تودرتو (nested) باشند).

ممکن است دو ماژول متفاوت هر دو دارای توابعی با نام یکسان باشند. برای مثال ماژول های m1 و m2 دارای فانکشنی به نام T باشند. در این صورت وقتی ماژول را به اسکریپت import کردید، با استفاده از نام ماژول که با علامت نقطه قبل از نام فانکشن می آید می توان منظور از فانکشن مورد نظر را مشخص کرد، برای مثال m1.T یا m2.T

اگر فانکشنی صدا زده شود که ماژول آن در برنامه import نشده است، با خطا مواجه می شوید که آن فانکشن تعریف نشده است.

 



>>> randint(1,10)

Traceback (most recent call last):
  File "", line 1, in 
    randint(1,10)
NameError: name 'randint' is not defined

>>> import random
>>> result = random.randint(1,10)
>>> result
2

 

برای دریافت اطلاعات بیشتر درباره namespace، به سایت https://bytebaker.com/2008/07/30/python-namespaces رجوع شود.

تعریف تابع

برای تعریف یک تابع از کلمه کلیدی def استفاده می شود،(def مخفف define است) سپس نام تابع با یک فاصله پس از آن قرار می گیرد و آرگومان های تابع (در صورت وجود)درون پرانتز جلو آن قرار می گیرند. چندین آرگومان ورودی با کاما از هم جدا می شوند. در نهایت نیز کاراکتر دو نقطه (:)پس از پرانتز قرار می گیرد و کدهای داخل تابع با رعایت کردن تورفتگی، نوشته می‌شوند.

علاوه بر این، برای ارائه توضیحات، علاوه بر "# " می توان از  " Docstring "استفاده کرد تا  توضیح بیشتری درباره کدهای برنامه ارائه دهند.. متن Docstring توسط سه علامت نقل قول  (""" یا ' ' ' )شروع و پایان می‌یابدو معمولا از آن به عنوان نخستین دستور در ماژول، کلاس، تابع و متد استفاده می‌شود. در این شرایط Docstring توسط مفسر نادیده گرفته نمی‌شود و در زمان اجرا با استفاده از صفت "__doc__ " قابل دستیابی است.

 

 


>>> def uc(a):
	'''
return a upper case string
'''
	a = a.upper()
	print a
	return a

>>> res2 = uc('hello')
HELLO
>>> uc.__doc__
'\nreturn a upper case string\n'


برای اطلاعات بیشتر درباره نحوه استفاده از docstring می توانید به" PEP 257" (https://www.python.org/dev/peps/pep-0257/) و  سایت http://sphinx.pocoo.org/ رجوع کنید.

 

آرگومان های تابع در پایتون

می توان یک تابع را به وسیله ی نوع آرگومان های لیست شده در زیر، فراخوانی کنید:

·       آرگومان های الزامی

آرگومان های الزامی، آرگومان هایی هستند که به ترتیب (تعریف شده) به تابع مورد نظر پاس داده می شوند. در اینجا، تعداد آرگومان هایی که در فراخوانی تابع مشخص می شود باید با تعریف تابع منطبق باشد در غیر این صورت خطای نحوی (syntax error) می دهد:

·       آرگومان های keyword

هنگامی که از آرگومان های keyword در فراخوانی تابع استفاده می شود، فراخواننده آرگومان ها را به وسیله ی اسم آن (پارامتر) شناسایی می کند. با این روش ترتیب پارامترها اهمیتی ندارد و می توان ترتیب آنها را تغییر داد، زیرا مفسر پایتون قادر است با استفاده از کلید واژه ، مقادیر را به پارامترها مرتبط سازد. به عبارتی در هنگام فراخوانی علاوه بر مقدار مورد نظر برای آرگومان، نام آرگومان هم قبل از علامت (=) می آید.

 


def namer(fn, ln):
	#return value
	print 'Your name is:', fn, ln
	return

>>> namer(ln = 'Jones', fn = 'Tim')
Your name is: Tim Jones



·       آرگومان پیش فرض:

پایتون این امکان را می دهد که مقادیر پیش فرض برای آرگومان ها تعریف شود، در این صورت اگر تابع بدون آرگومان هایش فراخوانی شود، مقادیر پیش فرض برای آرگومان ها در نظر گرفته می شود و نوشتن نام آن آرگومان ها به هنگام فراخوانی دلخواه می باشد.

 


>>> def namer(fn, ln = 'warner'):
	#return value
	print 'Your name is:', fn, ln
	return

>>> namer('Tim')
Your name is: Tim warner
>>> namer()

Traceback (most recent call last):
  File "", line 1, in 
    namer()
TypeError: namer() takes at least 1 argument (0 given)
>>> namer('Susan', 'Harter')
Your name is: Susan Harter



 

·       آرگومان های با طول متغیر (Variable-length arguments)

گاهی لازم است یک تابع را با آرگومان های بیشتری نسبت به آنچه در زمان تعریف تابع مشخص کردید، پردازش و فراخوانی کنید. این دست از آرگومان ها در اصطلاح آرگومان های با طول متغیر (variable length) خوانده می شوند و برخلاف آرگومان های الزامی و پیش فرض، در تعریف تابع ذکر نمی شوند.


def pr(a, b, *args, **kwargs):
	print 'one of my favorite fruit is: ', a
	print "My friend's favorite fruit is: ", b
	print 'some other fruits I like are: ', args
	return

>>> print pr('banana', 'pineapple', 'cherry', 'apple', 'peach')
one of my favorite fruit is:  banana
My friend's favorite fruit is:  pineapple
some other fruits I like are:  ('cherry', 'apple', 'peach')
None


علامت (*) پیش از اسم متغیر (args) که دارنده ی آرگومان های متغیر nonkeyword است، درج می شود و اگر از دو علامت (**) استفاده شود، به معنای این است که آرگومان ها از نوع keyword می باشند. که البته در این مثال نوشتن "**kwargs "فقط برای نشان دادن نحوه نوشتاری این نوع آرگومان ها می باشد و لازم نبوده است.

مقدار بازگشتی تابع

توابع پایتون نوع داده ای مقدار بازگشتی را مشخص نمی کنند. در صورتی که تابعی بخواهد مقداری را به عنوان نتیجۀ برگشت دهد، از دستور return برای انجام این کار استفاده می شود و در غیر این صورت مقدار None برمی گرداند. به عبارتی توابع پایتون همواره مقدار بازگشتی دارند، حتی اگر این مقدار None باشد.

 یک فانکشن ممکن است یه مقدار (single value) یا چندین مقدار (multi value) را به عنوان خروجی بر گرداند که در این صورت مقادیر را می توان با کاما از هم جدا کرد.

 

 بدون استفاده از دستور return تابع اجرا می شود اما بعد از اجرا، مقدار خروجی که در متغیر ریخته می شود از بین می رود.

 


>>> def uc(a):
	a = a.upper()
	print a

	
>>> uc('python')
PYTHON
>>> result = uc('students')
STUDENTS
>>> result
>>> def uc(a):
	a = a.upper()
	print a
	return a

>>> res2 = uc('hello')
HELLO
>>> res2
'HELLO'
>>> 
>>> type(res2)

 

در مورد توابعی که هیچ آرگومانی دریافت نمی کنند، باید در هنگام فراخوانی پرانتز باز و بسته ای را در جلو نام تابع قرار داد –مانند فراخوانی تابع upper برای رشته ای به نام str که به صورت str.upper() می باشد.

در پایتون ارسال متغییر به توابع از طریق مقداردهی صورت می‌گیرد. این مقداردهی و ارسال آرگومان‌ها به توابع به‌صورت مرجع (reference) است. یعنی همان متغییر- و نه یک کپی از آن -به تابع ارسال می‌شود. پس هر گونه دستکاری آن در داخل تابع باعث تغییر متغییر اصلی خواهد شد.

توجه: None در پایتون یک نوع داده ای ثابت خاص است. این مقدار ثابت برابر با هیچ یک از مقادیر false، صفر (0)، یا رشته تهی نمی باشد و مقایسه آن با هر نوع داده ای دیگر همیشه مقدار False را بر می گرداند. None نوع داده ای خاص خود را دارد (NoneType) و برابر مقدار null می باشد. می توان None را به هر متغیری نسبت داد. متغیرهایی که مقدار آنها برابر None باشند، با هم برابر هستند.

 



>>> type(none)

Traceback (most recent call last):
  File "", line 1, in 
    type(none)
NameError: name 'none' is not defined
>>> type(None)

>>> None == False
False
>>> None == 0
False
>>> x = None
>>> y = None
>>> x == y
True

 

حوزه ی دسترسی متغیر (variable scope)

منظور از حوزه دسترسی یک متغیر به معنای محدوده دیده شدن (visibility) آن در برنامه است. به عبارتی امکان دسترسی به تمامی متغیرهایی که در مکان های مختلف یک برنامه قرار دارند، وجود ندارد. قابلیت دسترسی به یک متغیر درواقع به مکان تعریف متغیر بستگی دارد.

حوزه ی دسترسی یا scope تعیین می کند که در چه قسمت هایی از برنامه می توانید به شناسه ی مورد نظر دسترسی داشته باشید. در کل دو نوع حوزه ی دسترسی در پایتون وجود دارد:

·       متغیرهای سراسری (global)

·       متغیرهای محلی (local)

متغیرهایی که داخل بدنه ی تابع، درون حلقه های تکرار و ... تعریف می شوند، حوزه ی دسترسی آن ها محلی محسوب می شود و تنها در همان محدوده شناخته شده اند در حالی که متغیرهایی که بیرون بدنه یا ساختمان تابع تعریف می شوند، متغیرهای سراسری نامیده می شوند و از تمام بخش های برنامه (توسط تابع) قابل دستیابی می باشد. به هنگام فراخوانی تابع، متغیرهای تعریف شده داخل آن همگی قابل دسترسی می باشند.

استراتژی های ارزیابی متغیرها:

·       Call-by-value : این نوع استراتژی رایج ترین نوع ارزیابی است که در آن آرگومان مورد نظر ارزیابی شده و نتیجه به متغیر مربوطه bound می شود (معمولا با کپی کردن مقدار در یک ناحیه جدید از حافظه). برای مثال وقتی تابع func(a) تعریف می شود و مقداری را بخواهیم به تابع پاس دهیم، یک کپی از داده بیرون تابع به درون تابع انتقال می یابد.

·       Call-by-reference: در این نوع استراتژی، تابع به جای دریافت یک کپی از آرگومان، یک مرجع ضمنی به آرگومان مربوطه دریافت می کند. به این معنا که تابع می تواند آن مقدار آرگومان را تغییر دهد. به همین دلیل call-by-reference از نظر فضا و زمان بهتر عمل می کند زیرا نیازی به کپی شدن آرگومان وجود ندارد.

·       call-by-sharing: پایتون از استراتژی call-by-object یا call-by-sharing استفاده می کند. از نظر معنایی call-by-sharing متفاوت از call-by-reference است. با توجه به آنکه تابع به خود شیء (و نه یک کپی از آن ) دسترسی دارد، تغییراتی که درون تابع بر روی داده انجام می شود، برای فراخواننده قابل مشاهده است که این مفهوم متفاوت از call-by-value می باشد.

به عبارتی می توان گفت در پایتون اگر یک آرگومان از نوع mutable object باشد، پایتون از call-by-reference استفاده می کند، در حالی که اگر از نوع immutable (تغییرناپذیر) باشد، از call-by-value استفاده می کند.

 

 




>>> def changeme(mylist):
	"This changes a passed list into this function"
	mylist.append([1,2,3,4])
	print 'Value inside the function: ', mylist
	return

>>> mylist = [10,20,30]
>>> changeme(mylist)
Value inside the function:  [10, 20, 30, [1, 2, 3, 4]]
>>> print 'Value outside the function: ', mylist
Value outside the function:  [10, 20, 30, [1, 2, 3, 4]]


ساخت ماژول توسط کاربر و استفاده از آن:

 

برای ایجاد ماژول مورد نظر خود، توابع مورد نظر خود را در فایلی بنویسید و آن را با نام دلخواه ذخیره کنید (در مثال زیر نام فایل my_module می باشد.  در این مثال دو تابع با نام های min_2_numbers  و max_2_numbers تعریف شده است.

Python-session7

برای آنکه بتوان از آن در قالب ماژول استفاده کرد، یک کپی از فایل را در مسیر زیر قرار دهید.

وارد محل نصب پایتون (به طور پیش فرض، پایتون در درایو C نصب می شود و متناسب با ورژن پایتون مورد استفاده، در پوشه ای با نام python27، python31، python33 یا ...قرار دارد) شوید و از پوشه Lib، وارد پوشه ای با نام site-packages شده و فایل را در آن ذخیره کنید:

C:\Python27\Lib\site-packages

حال اگر نام ماژول را با import فراخوانی کنید، لیست توابع موجود در آن با زدن کلید tab می آید و می توانید از توابع آنها استفاده کنید.

python-Learning session

توجه داشته باشید  که help نرم افزار پایتون تنها برای توابع و ماژول های از پیش تعریف شده نوشته شده است، و توابع و ماژول هایی که جدید تعریف می شوند در آن وجود ندارند.

 

نظرات یا سوالات خودرا با ما درمیان بگذارید

0912 097 5516 :شماره تماس
0713 625 1757 :شماره تماس