درس ۰۷: انواع داده در پایتون: str و bytes

انواع داده در پایتون: رشته

Photo by Kristian Strand

پایتون هر «نوع داده» (Data Type) را توسط یک کلاس ارایه می‌دهد؛ بنابراین هر داده یک نمونه یا یک شی از کلاسی مشخص است. هر چند برنامه‌نویس نیز می‌تواند با تعریف کلاس، نوع دلخواه خود را داشته باشد ولی در این درس می‌خواهیم درباره آن بخشی از انواع داده یا انواع شی‌ای که به شکل آماده (Built-in) در اختیار مفسر زبان پایتون قرار داده شده است صحبت کنیم.

در ادامه شرح «انواع عددی» در پایتون، این بخش به بررسی کامل نوع داده «رشته» (String) و همچنین نوع داده باینری (Binary) در پایتون خواهد پرداخت.

با اینکه تلاش شده است جزییات کامل باشند ولی در برخی بخش‌ها مطالعه اسناد رسمی پایتون می‌تواند اطلاعات کامل‌تری را در اختیار شما قرار دهد. در مواقع بسیاری از تابع‌های آماده پایتون استفاده خواهد شد که ممکن است جزییاتی بیشتر از آنچه در این درس بیان می‌شود را داشته باشند؛ به همین دلیل لینک تعریف آن‌ها در اسناد پایتون نیز ارایه گشته است. نکته مهم در مطالعه این درس بررسی نمونه کدهاست که گاهی درک توضیحی که داده شده است بدون دقت در این نمونه کدها ناممکن خواهد بود.

سطح: مقدماتی



نوع رشته (str)

نوع «رشته» (String) در پایتون با قرار گرفتن دنباله‌ای از کاراکترها درون یک جفت نماد نقل قول (Quotation) تکی ' ' یا دو تایی " " ایجاد می‌شود؛ به مانند "Python Strings" یا 'Python Strings' که تفاوتی با یکدیگر از نظر نوع ندارند:

>>> a = "Python Strings"

>>> type(a)
<class 'str'>

>>> a
'Python Strings'

>>> print(a)
Python Strings

>>> import sys
>>> sys.getsizeof(a)
63

بیشتر مواقع در حالت تعاملی نیازی به استفاده از تابع print نمی‌باشد ولی باید توجه داشته باشیم که حالت تعاملی بر بدون ابهام بودن این خروجی‌ها توجه دارد بنابراین آن‌ها را با جزییات نمایش می‌دهد که مناسب برنامه‌نویس است؛ برای نمونه حتما به چگونگی نمایش انواع دسیمال و کسری توجه کرده‌اید یا در نمونه کد بالا مشاهده می‌شود که نوع رشته به همراه نماد نقل قول نمایش داده شده است یا اگر متن رشته شامل کاراکترهای Escape باشد، آن‌ها را بدون تفسیر به همان شکل به خروجی می‌فرستد. اما print توجه بر خوانایی خروجی خود دارد و تا حد امکان جزییات را پنهان می‌کند؛ در نتیجه متن تمیزتری را نمایش می‌دهد که بیشتر مناسب کاربر نهایی است.

در پایتون برخلاف برخی از زبان‌ها نوع کاراکتر یا char وجود ندارد؛ در این زبان یک کاراکتر چیزی جز یک رشته با طول یک نیست.

در پایتون می‌توان از نمادهای نقل قول در داخل یکدیگر نیز بهره برد؛ در این شرایط تنها می‌بایست نماد نقل قول داخلی با بیرونی متفاوت باشد. چنانچه می‌خواهید از نماد نقل قول یکسانی استفاده نمایید، باید از کاراکترهای Escape کمک بگیرید که در ادامه بررسی خواهند شد:

>>> "aaaaaa 'bbb'"
"aaaaaa 'bbb'"

>>> 'aaaaaa "bbb"'
'aaaaaa "bbb"'

>>> "I'm cold!"
"I'm cold!"
>>> 'I\'m cold!'
"I'm cold!"

از درس پیش با Docstring آشنا شده‌ایم؛ در کاربردی دیگر از سه نماد نقل قول """ یا ''' برای ایجاد شی رشته نیز استفاده می‌شود. مزیت این نوع رشته در این است که می‌توان متن آن را به سادگی در چند سطر و با هر میزان تورفتگی دلخواه نوشت؛ این موضوع در زمان‌هایی که قصد استفاده از کدهای خاص به مانند HTML در برنامه خود داشته باشیم، بسیار مفید خواهد بود:

>>> a = """Python"""
>>> a
'Python'
>>> html = """
... <!DOCTYPE html>
... <html>
...     <head>
...         <title>Page Title</title>
...     </head>
...     <body>
...         <h1>This is a Heading.</h1>
...         <p>This is a paragraph.</p>
...     </body>
... </html>
... """
>>> print(html)

<!DOCTYPE html>
<html>
    <head>
        <title>Page Title</title>
    </head>
    <body>
        <h1>This is a Heading.</h1>
        <p>This is a paragraph.</p>
    </body>
</html>

>>>

رشته به عنوان دنباله‌ (Sequence)

برخی از انواع شی پایتون به مانند رشته، توپِل (tuple)، لیست (list) و... با عنوان دنباله (Sequence) نیز شناخته می‌شوند. دنباله ویژگی‌هایی دارد که در اینجا به کمک نوع رشته بررسی خواهیم کرد. رشته در واقع یک دنباله از کاراکترهاست در نتیجه می‌توان هر یک از اعضای این دنباله را با استفاده از اندیس (Index) موقعیت آن، دستیابی نمود؛ اندیس اعضا از سمت چپ با عدد صفر شروع و به سمت راست یک واحد یک واحد افزایش می‌یابد. به عنوان نمونه برای شی 'Python Strings' می‌توانیم شمای اندیس‌گذاری را به صورت پایین در نظر بگیریم:

P y t h o n   S t r i n g s
- - - - - - - - - - - - - -
0 1 2 3 4 5 6 7  ...      13

برای دستیابی اعضای یک دنباله با نام seq از الگو [seq[i که i اندیس عضو مورد نظر است؛ استفاده می‌شود:

>>> a = "Python Strings"
>>> a[0]
'P'
>>> a[7]
'S'
>>> a[6]
' '

چند نکته:

  • الگو [seq[-i اعضا دنباله را از سمت راست پیمایش می کند؛ اندیس سمت راست ترین عضو 1- است و به ترتیب به سمت چپ یک واحد یک واحد کاهش می‌یابد.

  • الگو [seq[i:j اعضایی از دنباله را که در بازه‌ای از اندیس i تا قبل از اندیس j هستند را دستیابی می‌کند. برای بیان نقاط «از ابتدا» و «تا انتها» می‌توان به ترتیب i و j را ذکر نکرد.

  • الگو [seq[i:j:k همانند قبلی است با این تفاوت که k اندازه گام پیمایش اعضا را تعیین می‌کند.

  • با استفاده از تابع ()len می‌توان تعداد اعضای یک دنباله را به دست آورد [اسناد پایتون].

>>> a = "Python Strings"

>>> len(a)
14

>>> a[-2]
'g'

>>> a[2:4]
'th'

>>> a[4:-4]
'on Str'

>>> a[7:]
'Strings'

>>> a[:6]
'Python'

>>> a[:-1]
'Python String'

>>> a[-6:]
'trings'

>>> a[2:12:3]
'tntn'

>>> a[:6:2]
'Pto'

>>> a[7::4]
'Sn'

>>> a[-1]
's'

>>> a[len(a) - 1]
's'

باید توجه داشت که یک شی رشته جزو انواع immutable پایتون است و مقدار (یا اعضا دنباله) آن را نمی‌توان تغییر داد؛ برای مثال نمی‌توان شی 'Python Strings' به 'Python-Strings' تغییر داد - برای این کار تنها می‌بایست یک شی جدید ایجاد کرد:

>>> a = "Python Strings"
>>> a[6] = "-"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

عملگرها برای رشته

با رشته‌ها نیز می‌توان از عملگرهای + (برای پیوند رشته‌ها) و * (برای تکرار رشته‌ها) بهره برد:

>>> a = "Python" + " " + "Strings"
>>> a
'Python Strings'

>>> "-+-" * 5
'-+--+--+--+--+-'

برای پیوند می‌توان از عملگر + صرف نظر کرد و تنها با کنار هم قرار دادن رشته‌ها، آن‌ها را پیوند داد:

>>> "Python " "Programming " "Language"
'Python Programming Language'
>>> a, b, c = "Python ", "Programming ", "Language"
>>> a + b + c
'Python Programming Language'
>>> name = "Python"
>>> version = 3.11
>>> name + version
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "float") to str

برای بررسی برابر بودن مقدار دو رشته مانند دیگر اشیا می‌توان از عملگر == استفاده کرد:

>>> a = "py"
>>> b = "PY"    # Uppercase
>>> a == b
False

از عملگرهای عضویت هم می‌توان برای بررسی وجود کاراکتر یا رشته‌ای درون رشته‌ای دیگر استفاده کرد:

>>> "n" in "python"
True
>>> "py" not in "python"
False

کمی جلوتر خواهید دید که از عملگر % نیز برای قالب‌بندی رشته‌ها استفاده می‌گردد.

کاراکترهای Escape

به صورت پیش‌فرض تعدادی کاراکتر خاص تعریف شده است که می‌توان آن‌ها را درون رشته‌ها بکار برد. تمام این کاراکترها با یک \ آغاز می‌شوند به همین دلیل گاهی نیز به نام Backslash Characters خوانده می‌شوند [ویکی‌پدیا]. در واقع این کاراکترها امکانی برای درج برخی دیگر از کاراکترها هستند که نمی‌توان آن‌ها را به سادگی توسط صفحه‌کلید وارد کرد. برای نمونه یکی از کاراکترهای Escape رایج n\ است که بیانگر کاراکتری با کد اسکی 10 (LF) به نام newline می‌باشد؛ n\ در هر جایی از رشته (یا متن) که درج گردد در هنگام چاپ سطر جاری را پایان می‌دهد و ادامه رشته (یا متن) از سطر جدید آغاز می‌‌شود:

>>> a = "Python\nProgramming\nLanguage"

>>> a
'Python\nProgramming\nLanguage'

>>> print(a)
Python
Programming
Language
>>>

برخی از این کاراکترها به شرح پایین است:

  • n\ - پایان سطر جاری و رفتن به سطر جدید

  • t\ - برابر کد اسکی 9 (TAB): درج هشت فاصله (کلید Space)

  • uxxxx\ - درج یک کاراکتر یونیکد 16 بیتی با استفاده از مقدار هگزادسیمال (پایه شانزده) آن : "u067E\"

  • Uxxxxxxxx\ - درج یک کاراکتر یونیکد 32 بیتی با استفاده از مقدار هگزادسیمال (پایه شانزده) آن : "U0001D11E\"

  • ooo\ - درج یک کاراکتر با استفاده از مقدار اُکتال (پایه هشت) آن : "123\"

  • xhh\ - درج یک کاراکتر با استفاده از مقدار هگزادسیمال (پایه شانزده) آن : "x53\"

  • '\ - درج یک کاراکتر '

  • "\ - درج یک کاراکتر "

  • \\ - درج یک کاراکتر \

این ویژگی رشته‌ها گاهی موجب مشکل می‌شود؛ فرض کنید می‌خواهیم آدرس فایلی از سیستم عامل ویندوز را چاپ نماییم:

>>> fpath = "C:\new\text\sample.txt"

>>> print(fpath)
C:
ew        ext\sample.txt

برای حل مشکل نمونه کد بالا می‌توان هر جا که نیاز به \ است از \\ استفاده کرد: "C:\\new\\text\\sample.txt". ولی راهکار جامع‌تر ایجاد «رشته‌های خام» (Raw Strings) است؛ در این نوع رشته‌، کاراکترهای Escape بی‌اثر هستند. رشته خام با افزوده شدن یک حرف r یا R به ابتدای یک رشته معمولی ایجاد می‌گردد:

>>> fpath = r"C:\new\text\sample.txt"
>>> print(fpath)
C:\new\text\sample.txt

تبدیل کد به کاراکتر و برعکس

می‌دانیم برای اینکه کامپیوتر بتواند کاراکتر‌ها را درک کند نیاز به سیستم‌هایی است که آن‌ها را برای تبدیل به کدهای پایه دو کدگذاری کند؛ به مانند سیستم اَسکی (ASCII) یا سیستم‌های جامع‌تری مانند UTF-8 که تحت استاندارد یونیکد (Unicode) در دسترس است. گاهی نیاز است به این کدها دسترسی داشته باشیم و با کاراکترها بر اساس آن‌ها کار کنیم؛ برای این منظور در پایتون می‌توان از دو تابع ()ord (تبدیل کد به کاراکتر) [اسناد پایتون] و ()chr (تبدیل کاراکتر به کد) [اسناد پایتون] استفاده کرد. تابع ()ord یک رشته تک کاراکتری را گرفته و یک عدد (در پایه ده) که بیانگر کد کاراکتر مورد نظر می‌باشد را برمی‌گرداند. تابع ()chr نیز کد کاراکتری (که می‌بایست عددی در پایه ده باشد) را گرفته و کاراکتر مربوط به آن را برمی‌گرداند:

>>> # Python 3.x - GNU/Linux

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

>>> int("067E", 16)   # Hexadecimal to Decimal
1662
>>> chr(1662)         # Unicode Character:  1662 -> 067E -> 'پ'
'پ'
>>> ord(_)            # _ is result of the last executed statement  = 'پ'
1662

>>> ord("\U0001D11E")
119070
>>> chr(_)
'𝄞'

تبدیل به نوع رشته

برای تبدیل اشیایی از نوع دیگر به نوع رشته؛ کلاس ()str [اسناد پایتون] و تابع ()repr [اسناد پایتون] وجود دارد. کلاس ()str یک نمونه غیر رسمی (informal) از نوع شی رشته را برمی‌گرداند؛ غیر رسمی از این جهت که توسط آن جزییات شی رشته پنهان می‌شود. اما تابع ()repr یک نمونه رسمی (official) از نوع رشته پایتون را برمی‌گرداند. کمی قبل‌تر راجب تفاوت خروجی print و حالت تعاملی صحبت کردیم؛ در واقع خروجی ()str مناسب برای چاپ است و همانند print جزییات این نوع شی را ارایه نمی‌دهد در حالی که ()repr به مانند حالت تعاملی یک ارايه (representation) کامل از شی رشته را برمی‌گرداند:

>>> str(14)
'14'
>>> repr(14)
'14'

>>> str(True)
'True'
>>> repr(False)
'False'
>>> a = "Python Strings"

>>> str(a)
'Python Strings'
>>> repr(a)
"'Python Strings'"

>>> print(str(a))
Python Strings
>>> print(repr(a))
'Python Strings'

همچنین به جای این دو می‌توانید از متدهای ()__str__ و ()__repr__ استفاده نمایید:

>>> a = 10
>>> a.__str__()
'10'

قالب‌بندی رشته‌ (String Formatting)

قالب‌بندی امکانی برای جایگزین کردن یک یا چند مقدار (به بیان بهتر: شی) - گاهی همراه با اعمال تغییر دلخواه - درون یک رشته است که به چند روش در پایتون پیاده‌سازی می‌گردد:

  • روش قدیمی و با استفاده از الگوی (s..." % (values%..."

  • فراخوانی متد ()format - با الگو (format(values."...{}..."

  • f-string

قالب‌بندی به روش قدیم

از دو بخش تشکیل شده است؛ بخش سمت چپ عملگر %، رشته‌ای را مشخص می‌کند که شامل یک یا چند کد جایگذاری شی می‌باشد - کدهای جایگذاری همگی با یک کاراکتر % شروع می‌شوند؛ مانند: s% - و در سمت راست آن شی‌هایی برای جایگزین شدن در رشته، داخل پرانتز قرار دارد؛ این اشیا به ترتیب از سمت چپ درون رشته جایگذاری می‌گردند:

>>> "Python is %s to learn if you know %s to start!" % ("easy", "where")
'Python is easy to learn if you know where to start!'

برخی از کدهای جایگذاری به شرح پایین است:

  • s% - جایگزینی در قالب یک رشته به شکل خروجی کلاس ()str

  • r% - جایگزینی در قالب یک رشته به شکل خروجی تابع ()repr

  • c% - جایگزینی در قالب یک کاراکتر: یک عدد صحیح که نشانگر کد کاراکتر می‌باشد را به کاراکتر یونیکد تبدیل کرده و درون رشته قرار می دهد.

>>> "%r is a %s language." % ("Python", "programming")
"'Python' is a programming language."

>>> er = 1427
>>> "Error %s!" % (er)
'Error 1427!'

>>> "A, B, C, ... Y, %c" % (90)
'A, B, C, ... Y, Z'
  • d% یا i% - جایگزینی در قالب یک عدد صحیح در پایه ده

  • o% - جایگزینی در قالب یک عدد صحیح در پایه هشت

  • x% - جایگزینی در قالب یک عدد صحیح در پایه شانزده با حروف کوچک

  • X% - جایگزینی در قالب یک عدد صحیح در پایه شانزده با حروف بزرگ

>>> "4 + 4 == %d" % (2*4)
'4 + 4 == 8'

>>> "%d" % (0b0110)
'6'

>>> "%d" % (12.6)
'12'

>>> "int('%o', 8) == %d" % (0o156, 0o156)
"int('156', 8) == 110"

>>> "15 == %X in HEX" % (15)
'15 == F in HEX'
  • f% - جایگزینی در قالب یک عدد ممیز شناور (دقت پیش‌فرض: ۶) در پایه ده

  • F% - همانند f% ؛ با این تفاوت که nan و inf را به شکل NAN و INF درج می‌کند.

  • e% - جایگزینی در قالب یک عدد ممیز شناور به شکل نماد علمی با حرف کوچک

  • E% - جایگزینی در قالب یک عدد ممیز شناور به شکل نماد علمی با حرف بزرگ

>>> "%f" % (12.526)
'12.526000'

>>> "%f" % (122e-3)
'0.122000'

>>> "%E" % (12.526)
'1.252600E+01'

همچنین این الگو را می‌توان با استفاده از یک شی دیکشنری - این نوع شی توسط درس هشتم بررسی می‌گردد - پیاده‌سازی نمود. در این شیوه اشیا با استفاده از کلید جایگذاری می‌گردند و دیگر ترتیب آن‌ها اهمیتی ندارد. به نمونه کد پایین توجه نمایید:

>>> '%(qty)d more %(product)s' % {'product': 'book', 'qty': 1}
'1 more book'


>>> reply = """
... Greetings...
... Hello %(name)s!
... Your age is %(age)s
... """
>>> values = {'name': 'Bob', 'age': 40}
>>> print(reply % values)

Greetings...
Hello Bob!
Your age is 40

>>>

در اصل می‌توان برای بخش سمت چپ این قالب، ساختاری مانند پایین را در نظر گرفت:

%[(keyname)][flags][width][.precision]typecode
  • در هر استفاده وجود هر یک از [ ] ها اختیاری است یا بستگی به مورد استفاده دارد.

  • (keyname) - درج کلید داخل پرانتز - در مواقع استفاده از شی دیکشنری آورده می‌شود.

  • flags - می‌تواند یکی از سه نماد +، و 0 باشد. + موجب درج علامت عدد می‌شود (علامت اعداد منفی به صورت پیش‌فرض درج می‌گردد؛ این علامت بیشتر برای درج علامت اعداد مثبت به کار می‌رود)، موجب چپ‌چین شدن مقدار می‌گردد (حالت پیش‌فرض راست‌چین است) و 0 تعیین می‌کند که فضای خالی اضافی با صفر پر گردد (در حالت پیش‌فرض Space گذاشته می‌شود).

  • width - اندازه رشته را تعیین می‌کند؛ در مواردی که اندازه تعیین شده بیشتر از اندازه واقعی مقدار باشد، فضای اضافی را می‌توان با صفر یا فضای خالی (Space) پر کرد و البته زمانی که کمتر تعیین گردد، این گزینه نادیده گرفته می‌شود.

  • precision. - در مورد اعداد ممیز شناور، دقت یا تعداد ارقام بعد از ممیز را تعیین می‌کند (دقت پیش‌فرض: ۶). در مواردی که تعداد تعیین شده کمتر از تعداد واقعی ارقام بعد ممیز باشد، عدد گِرد می‌گردد. به وجود . پیش از آن توجه نمایید.

  • typecode - بیانگر همان حرف تعیین کننده نوع کد جایگذاری می‌باشد.

  • به جای width و precision. می توان از * استفاده کرد که در این صورت عدد مربوط به آن‌ها نیز در بخش سمت راست آورده می‌شود و شی جایگزینی می‌بایست درست پس از آن ذکر گردد. این گزینه در مواقعی که لازم است این اعداد در طول اجرای برنامه تعیین گردند کاربرد دارد.

    >>> "%6d" % (256)    # typecode='d' width='6'
    '   256'
    
    >>> "%-6d" % (256)   # typecode='d' width='6' flags='-'
    '256   '
    
    >>> "%06d" % (256)   # typecode='d' width='6' flags='0'
    '000256'
    
    >>> "%+d" % (256)    # typecode='d' flags='+'
    '+256'
    
    >>> "%10f" % (3.141592653589793)      # typecode='f' width='10'
    '  3.141593'
    
    >>> "%10.4f" % (3.141592653589793)    # typecode='f' precision='4' width='10'
    '    3.1416'
    
    >>> "%10.8f" % (3.141592653589793)    # typecode='f' precision='8' width='10'
    '3.14159265'
    
    >>> "%-10.0f" % (3.141592653589793)   # typecode='f' precision='0' width='10' flags='-'
    '3         '
    
    >>> "%*d" % (5, 32)                                  # typecode='d' width='5'
    '   32'
    
    >>> "%d %*d %d" % (1, 8, 8231, 3)
    '1     8231 3'
    
    >>> "%f, %.2f, %.*f" % (1/3.0, 1/3.0, 4, 1/3.0)
    '0.333333, 0.33, 0.3333'
    
    >>> n = """
    ... %15s : %-10s
    ... %15s : %-10s
    ... """
    >>> v = ("First name", "Richard", "Last name",  "Stallman")
    >>> print(n % v)
    
         First name : Richard
          Last name : Stallman
    
    >>>
    

قالب‌بندی با متد format

در این قالب اشیا، آرگومان‌های یک متد مشخص هستند و با استفاده اندیس موقعیت‌ یا نام آن‌ها داخل {} در رشته جایگذاری می‌گردند:

>>> '{0} {1} {2}'.format("Python", "Programming", "Language")
'Python Programming Language'
>>> reply = """
... Greetings...
... Hello {name}!
... Your age is {age}
... """
>>> print(reply.format(age=40, name='Bob'))

Greetings...
Hello Bob!
Your age is 40

>>>
>>> "{0} version {v}".format("Python", v="3.4")
'Python version 3.4'

ملاحظه

همانطور که در درس تابع‌ خواهیم آموخت؛ بدون نیاز به رعایت ترتیب می‌توان آرگومان‌ها را با انتساب مقدار مورد نظر به آن‌ها ارسال نمود.

با هر ترتیبی می‌توان اشیا را جایگذاری نمود:

>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'

چنانچه بخواهیم اشیا به ترتیبی که در آرگومان متد قرار دارد جایگذاری شوند؛ نیازی به ذکر اندیس یا نام آرگومان نمی‌باشد:

>>> '{}, {}, {}'.format('a', 'b', 'c')
'a, b, c'

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

>>> '{2}, {1}, {0}'.format(*'abc')
'c, b, a'

>>> '{2}, {1}, {0}'.format(*'python')
't, y, p'

>>> '{2}, {1}, {0}'.format('z', *'abc')
'b, a, z'

بخش درون رشته این قالب نیز ساختاری مشابه پایین دارد:

{fieldname !conversionflag :formatspec}
  • fieldname - اندیس یا نام آرگومان است.

  • conversionflag! - می‌تواند یکی از حروف r و s باشد که به ترتیب ()repr و ()str را بر روی شی فراخوانی می‌کنند. توجه داشته باشید که این حروف با ! شروع می‌شوند:

    >>> "repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2')
    "repr() shows quotes: 'test1'; str() doesn't: test2"
    
  • formatspec: - چگونگی درج شی در رشته را تعیین می‌کند. با : شروع می‌شود و خود ساختاری به مانند پایین دارد:

    [[fill]align][sign][#][0][width][,][.precision][typecode]
    
  • در هر استفاده وجود هر یک از [ ] ها اختیاری است یا بستگی به مورد استفاده دارد.

  • fill - می‌تواند هر کاراکتر قابل چاپی باشد - از این گزینه برای پر کردن فضای خالی که توسط width ایجاد گردیده، استفاده می‌شود.

  • align - می‌تواند یکی از کاراکترهای <، > یا ^ باشد که به ترتیب بیانگر حالت راست‌چین، چپ‌چین و وسط‌چین می‌باشند. width نیز پس از آن‌ها آورده می‌شود که میزان اندازه رشته را تعیین می‌کند.

    >>> '{0:<30}'.format('left aligned')     # align='<' width='30'
    'left aligned                  '
    
    >>> '{0:>30}'.format('right aligned')    # align='>' width='30'
    '                 right aligned'
    
    >>> '{0:^30}'.format('centered')         # align='^' width='30'
    '           centered           '
    
    >>> '{0:*^30}'.format('centered')        # align='^' width='30' fill='*'
    '***********centered***********'
    
  • sign - برای نمایش علامت اعداد کاربرد دارد و می‌تواند یکی از نمادهای +، یا یک فضا خالی (Space) باشد. به این صورت که: + علامت تمام اعداد مثبت و منفی را درج می‌کند و نیز تنها موجب درج علامت اعداد منفی می‌شود. در صورت استفاده از فضای خالی، علامت اعداد منفی درج شده ولی به جای علامت اعداد مثبت یک کاراکتر فضای خالی وارد می‌شود.

    >>> '{0:+f}; {1:+f}'.format(3.14, -3.14)   # typecode='f' sign='+'
    '+3.140000; -3.140000'
    
    >>> '{0:-f}; {1:-f}'.format(3.14, -3.14)   # typecode='f' sign='-'
    '3.140000; -3.140000'
    
    >>> '{0: f}; {1: f}'.format(3.14, -3.14)   # typecode='f' sign=' '
    ' 3.140000; -3.140000'
    
  • برخلاف قالب قبلی، می‌توان تبدیل پایه دو را هم داشته باشیم. تبدیل پایه در این قالب با استفاده از حروف b (پایه دو)، o (حرف اُ کوچک - پایه هشت) و x یا X (پایه شانزده) انجام می‌شود. چنانچه یک نماد # به پیش از آن‌ها افزوده شود، پیشوند پایه نیز درج می‌گردد:

    >>> "int: {0:d};  hex: {0:x};  oct: {0:o};  bin: {0:b}".format(42)
    'int: 42;  hex: 2a;  oct: 52;  bin: 101010'
    
    >>> "int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}".format(42)
    'int: 42;  hex: 0x2a;  oct: 0o52;  bin: 0b101010'
    
  • با استفاده از یک , (کاما Comma) می‌توان یک عدد را سه رقم سه رقم از سمت راست جدا نمود:

    >>> '{0:,}'.format(1234567890)
    '1,234,567,890'
    
  • بخش‌هایی از قالب قبلی در این قالب نیز تعریف شده‌ است. گزینه‌های precision ،typecode. و width به همان صورتی هستند که در قالب قبلی بیان گشته است. البته موارد typecode کمی کمتر است؛ به عنوان نمونه در این قالب کد i وجود ندارد و تنها می‌توان از d برای اعداد صحیح در پایه ده استفاده کرد:

    >>> '{0:06.2f}'.format(3.14159)    # width='6' precision='.2' typecode='f'  and [0]
    '003.14'
    >>> '{0:^8.2f}'.format(3.14159)    # align='^'
    '  3.14  '
    
  • برای بیان درصد می‌توان از % به جای f استفاده کرد:

    >>> points = 19.5
    >>> total = 22
    >>> 'Correct answers: {0:.2%}'.format(points/total)
    'Correct answers: 88.64%'
    
  • در قالب قبلی با استفاده از * می‌توانستیم گزینه‌های خود را در طرف دیگر مقداردهی نماییم؛ در قالب جدید برای این منظور می‌توان مانند کاری که برای جایگذاری اشیا انجام می‌دادیم، از { } استفاده کرده و مقدار گزینه‌ها را در جایگاه آرگومان متد تعریف نماییم:

    >>> text = "Right"
    >>> align = ">"
    >>> '{0:{fill}{align}16}'.format(text, fill=align, align=align)
    '>>>>>>>>>>>Right'
    

قالب‌بندی به روش f-string

از نسخه پایتون 3.6 یک امکان جدید و بسیار جالب در بحث قالب‌بندی رشته‌ها ارايه شده است که با عنوان f-string شناخته می‌شود [PEP 498].

ساختار همان ساده شده حالت ()str.format می‌باشد:

>>> name = "Saeid"
>>> age = 32
>>> f"Hello, {name}. You are {age}."
'Hello, Saeid. You are 32.'
>>>

یعنی اگر در ابتدای یک متن، حرف f یا F قرار دهیم، آنگاه می‌توانیم متغیرها یا عبارات خود را مستقیم در داخل آن - با استفاده از {} - قرار بدهیم:

>>> f"{2 * 37}"
'74'

بدیهی است که متغیرها (- یا نتیجه حاصل عبارات) یا اشیای مورد استفاده در شیوه f-string در نهایت برای قرار گرفتن درون متن یا رشته مورد نظر می‌بایست به نوع رشته تبدیل شوند. در این شیوه به صورت پیش‌فرض متد ()__str__ برای تبدیل به نوع رشته فراخوانی می‌شود ولی می‌توان با قرار دادن نشانگر r! در انتهای شی مورد نظر، تعیین کرد که متد ()__repr__ فراخوانی شود:

>>> name = 'Saeid'
>>> print(f'My name is {name}')
My name is Saeid
>>> print(f'My name is {name!r}')
My name is 'Saeid'
>>>

در این شیوه می‌توان از نماد {} در خارج از اصول قالب‌بندی استفاده کرد ولی باید توجه داشت که هر دو نماد {{}} به عنوان یک {} در نظر گرفته می‌شود. وجود سه {{{}}} نیز در حکم همان دو تا می‌باشد:

>>> f'{{{{32}}}}'
'{{32}}'
>>> f'{{{32}}}'
'{32}'
>>> f'{{32}}'
'{32}'
>>> f'{32}'
'32'
>>> print(f'{{My name}} is {name}')
{My name} is Saeid

>>> print(f'{{My name}} is {{name}}')  # NOTE!
{My name} is {name}

>>> print(f'{{My name}} is {{{name}}}')
{My name} is {Saeid}

>>> print(f'{{My name}} is {{{{name}}}}')  # NOTE!
{My name} is {{name}}

در نمونه کد پایین یک تابع را مستقیم در داخل متن موجود فراخوانی می‌کنیم:

>>> def to_lowercase(input):
...     return input.lower()
...
>>>
>>> name = "Eric Idle"
>>>
>>> f"{to_lowercase(name)} is funny."
'eric idle is funny.'
>>> f"{name.lower()} is funny."
'eric idle is funny.'
>>>

همچنین می‌توانیم هر یک از اشیا مورد استفاده در درون متن را با شیوه خاص آن شی، با قرار دادن یک : به صورت جداگانه قالب‌بندی نماییم:

>>> a_float_number = 5.236501
>>> print(f'{a_float_number:.4f}')
5.2365
>>> print(f'{a_float_number:.2f}')
5.24
>>>
>>> a_int_number = 16
>>> print(f'{a_int_number:05d}')
00016
>>>
>>> import datetime
>>> now = datetime.datetime.now()
>>> print(f'{now:%Y-%m-%d %H:%M}')
2019-10-20 10:37

در درس بیست و پنجم در مورد ماژول datetime صحبت خواهیم کرد. [اسناد پایتون]

برخی از متدهای کاربردی یک شی رشته

  • ()strip [اسناد پایتون] - یک کپی از رشته که کارکترهای فضای خالی (whitespace) را از ابتدا و انتهای رشته حذف شده است را بر می‌گرداند:

    >>> a = "      python string methods           "
    >>> a.strip()
    'python string methods'
    

    همچنین می‌توان با استفاده از این متد، کاراکترهای دیگری نیز بنابر نیاز خود از ابتدا یا انتهای یک رشته حذف کنیم:

    >>> a = "python string methods"
    >>> a.strip('sdyp')
    'thon string metho'
    

    دو متد [lstrip] و [rstrip] نیز عملکردی مشابه دارند با این تفاوت که عملیات حذف را تنها در سمت چپ (left) یا راست (right) به انجام می‌رسانند.

  • ()capitalize [اسناد پایتون] - یک کپی از رشته که نخستین حرف آن به صورت بزرگ (Capital) نوشته شده است را برمی‌گرداند:

    >>> a = "python string methods"
    >>> a.capitalize()
    'Python string methods'
    
  • (center(width [اسناد پایتون] - یک عدد صحیح که تعیین کننده اندازه رشته است گرفته و رشته را به صورت وسط‌چین شده درون این بازه برمی‌گرداند. در صورتی که اندازه تعیین شده کوچکتر از اندازه واقعی رشته (len(string باشد؛ رشته بدون تغییر بازگردانده می‌شود. این متد یک آرگومان اختیاری هم دارد که توسط آن می‌توان کاراکتری را برای پر کردن فضای خالی تعیین نمود:

    >>> a = "python"
    
    >>> a.center(25)
    '          python         '
    
    >>> a.center(25, "-")
    '----------python---------'
    

    دو متد مشابه دیگر با الگو (rjust(width [اسناد پایتون] و (ljust(width [اسناد پایتون] نیز هستند که به ترتیب برای راست‌چین و چپ‌چین کردن متن رشته استفاده می‌شوند:

    >>> a.rjust(25)
    '                   python'
    
    >>> a.ljust(25, ".")
    'python...................'
    
  • (count(sub [اسناد پایتون] - یک رشته را گرفته و تعداد وقوع آن در رشته اصلی را برمی‌گرداند. این متد دو آرگومان اختیاری نیز دارد که می‌توان نقطه شروع و پایان عمل این متد را مشخص نمود:

    >>> a = "python string methods"
    
    >>> a.count("t")
    3
    >>> a.count("tho")
    2
    >>> a.count("tho", 15)              # start=15
    1
    >>> a.count("tho", 0, len(a) - 1)   # start=0, end=20
    2
    
  • (endswith(suffix [اسناد پایتون] - یک رشته را گرفته و چنانچه رشته اصلی با آن پایان یافته باشد مقدار True و در غیر این صورت False را برمی‌گرداند. این متد دو آرگومان اختیاری نیز دارد که می‌توان نقطه شروع و پایان عمل این متد را مشخص نمود:

    >>> a = "Wikipedia, the free encyclopedia."
    
    >>> a.endswith(",")
    False
    >>> a.endswith(",", 0 , 10)    # start=0, end=10
    True
    >>> a.endswith("pedia.", 14)   # start=14
    True
    
  • (find(sub [اسناد پایتون] - یک رشته را گرفته و اندیس شروع آن را برای نخستین وقوع درون رشته اصلی برمی‌گرداند؛ در صورتی که آرگومان دریافتی در رشته اصلی یافت نشود مقدار 1- برگردانده می‌شود. این متد دو آرگومان اختیاری نیز دارد که می‌توان نقطه شروع و پایان عمل این متد را مشخص نمود:

    >>> a = "python programming language"
    
    >>> a.find("language")
    19
    >>> a.find("p")
    0
    >>> a.find("p", 6)               # start=6
    7
    >>> a.find("g", 18, len(a)-1)    # start=18, end=27-1
    22
    >>> a.find("saeid")
    -1
    

    متد مشابه دیگری نیز با الگو (rfind(sub [اسناد پایتون] وجود دارد؛ ولی با این تفاوت که اندیس شروع آرگومان دریافتی را برای آخِرین وقوع درون رشته اصلی برمی‌گرداند:

    >>> a.rfind("p")
    7
    >>> a.rfind("p", 6)
    7
    >>> a.rfind("g", 18, len(a)-1)
    25
    >>> a.rfind("saeid")
    -1
    

    در صورتی که نیازی به اندیس ندارید و تنها می‌خواهید وجود یک رشته را درون رشته‌ای مشخص بررسی نمایید؛ از عملگر in استفاده کنید:

    >>> "language" in a
    True
    >>> "p" in a
    True
    >>> "saeid" in a
    False
    
  • (index(sub [اسناد پایتون] - همانند متد (find(sub است با این تفاوت که اگر آرگومان دریافتی در رشته اصلی یافت نشود یک خطا ValueError را گزارش می‌دهد:

    >>> a = "python programming language"
    
    >>> a.index("python")
    0
    >>> a.index("python", 6)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: substring not found
    

    متد دیگری نیز با الگو (rindex(sub [اسناد پایتون] وجود دارد که مانند (rfind(sub عمل می‌کند ولی با این تفاوت که اگر آرگومان دریافتی در رشته اصلی یافت نشود یک خطا ValueError را گزارش می‌دهد:

    >>> a.rindex("g", 18, len(a)-1)
    25
    
  • (join(iterable [اسناد پایتون] - یک دنباله با اعضایی تمام از نوع رشته را به صورت آرگومان دریافت می‌کند و با استفاده از رشته اصلی اعضای آن‌ را به یکدیگر پیوند داده و برمی‌گرداند:

    >>> a = "-*-"
    
    >>> a.join("python")
    'p-*-y-*-t-*-h-*-o-*-n'
    
    >>> a.join(['p', 'y', 't', 'h', 'o', 'n'])   # get a list of strings
    'p-*-y-*-t-*-h-*-o-*-n'
    
  • (split(sep [اسناد پایتون] - یک کاراکتر را دریافت کرده و رشته را بر اساس آن از هم جدا کرده و به صورت یک شی لیست (list) برمی‌گرداند. این متد یک آرگومان اختیاری نیز دارد که می توان تعداد عمل جداسازی را تعیین نمود:

    >>> a = "p-y-t-h-o-n"
    
    >>> a.split()
    ['p-y-t-h-o-n']
    
    >>> a.split("-")
    ['p', 'y', 't', 'h', 'o', 'n']
    
    >>> a.split("-", 2)
    ['p', 'y', 't-h-o-n']
    
    >>> '1,2,,3,'.split(',')
    ['1', '2', '', '3', '']
    

    متد مشابه دیگری نیز با الگو (rsplit(sep [اسناد پایتون] وجود دارد ولی با این تفاوت که رشته را از سمت راست پیمایش می‌کند:

    >>> a.rsplit("-")
    ['p', 'y', 't', 'h', 'o', 'n']
    
    >>> a.rsplit("-", 2)
    ['p-y-t-h', 'o', 'n']
    
  • (replace(old, new [اسناد پایتون] - دو رشته به صورت آرگومان دریافت می‌کند؛ در تمام رشته اصلی بخش‌هایی که برابر مقدار آرگومان old هستند را با آرگومان new جایگزین می‌کند و سپس رشته جدید را برمی‌گرداند. این متد یک آرگومان اختیاری نیز دارد که می‌توان تعداد عمل جایگزینی را تعیین نمود:

    >>> a = "He has a blue house and a blue car!"
    
    >>> a.replace("blue", "red")
    'He has a red house and a red car!'
    
    >>> a.replace("blue", "red", 1)
    'He has a red house and a blue car!'
    
  • ()lower [اسناد پایتون] - تمام حروف الفبا انگلیسی موجود در رشته را به حرف کوچک تبدیل می‌کند و برمی‌گرداند:

    >>> "CPython-3.4".lower()
    'cpython-3.4'
    

    برعکس؛ متد ()upper [اسناد پایتون] تمام حروف الفبا انگلیسی موجود در رشته را به حرف بزرگ تبدیل می‌کند و برمی‌گرداند:

    >>> "CPython-3.4".upper()
    'CPYTHON-3.4'
    
  • ()islower [اسناد پایتون] - اگر رشته حداقل شامل یکی از حروف الفبا انگلیسی بوده و تمام حروف الفبا آن به صورت کوچک باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python".islower()
    True
    >>> "python-3.4".islower()
    True
    >>> "Python".islower()
    False
    

    برعکس؛ متد ()isupper [اسناد پایتون] اگر رشته حداقل شامل یکی از حروف الفبا انگلیسی بوده و تمام حروف الفبا آن به صورت بزرگ باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python".isupper()
    False
    >>> "Python".isupper()
    False
    >>> "PYTHON".isupper()
    True
    >>> "PYTHON-3.4".isupper()
    True
    
  • ()isalpha [اسناد پایتون] - اگر رشته حداقل شامل یک کاراکتر بوده و تمام کاراکترهای آن تنها یکی از حروف الفبا انگلیسی (کوچک یا بزرگ) باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python".isalpha()
    True
    >>> "python34".isalpha()
    False
    >>> "python 34".isalpha()
    False
    
  • ()isalnum [اسناد پایتون] - اگر رشته حداقل شامل یک کاراکتر بوده و تمام کاراکترهای آن تنها یکی از عددهای 0 تا 9 یا حروف الفبا انگلیسی (کوچک یا بزرگ) باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python34".isalnum()
    True
    >>> "python3.4".isalnum()
    False
    >>> "python-34".isalnum()
    False
    
  • ()isdigit [اسناد پایتون] - اگر رشته حداقل شامل یک کاراکتر بوده و تمام کاراکترهای آن تنها یکی از عددهای 0 تا 9 باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python34".isdigit()
    False
    >>> "34".isdigit()
    True
    >>> "3.4".isdigit()
    False
    

نوع داده باینری (bytes)

نوع داده دیگری که در پایتون فراهم آمده است، bytes بوده که معرف یک دنباله از بایت‌ها می‌باشد. از این نوع داده برای تعریف تمامی داده‌های باینری در پایتون استفاده می‌شود. داده‌هایی مانند یک فایل تصویر یا داده‌هایی که بر روی لایه شبکه (Network) تبادل می‌شوند، همگی در پایتون با این نوع داده قابل پردازش هستند.

ساده‌ترین راه برای ارایه مثال، تبدیل نوع متنی یا همان str پایتون به نوع bytes است:

>>> a = "python"
>>> type(a)
<class 'str'>

>>> a = b"python"
>>> type(a)
<class 'bytes'>

در پایتون برای ایجاد نوع bytes می‌توان از حرف b در ابتدای رشته یا از کلاس ()bytes [اسناد پایتون] استفاده کرد. در استفاده از کلاس، لازم است که سیستم کدگذاری آن را نیز مشخص نماییم و بهتر است داده‌های عددی را نیز به شکل یک شی لیست ارسال نماییم:

>>> b = b"python"
>>> b
b'python'
>>> b = bytes("python", "utf-8")
>>> b
b'python'

>>> c = bytes([97])
>>> c
b'a'

اکنون برای تبدیل نوع bytes به str نیاز به کدگشایی یا Decode کردن داده‌ها داریم؛ این کار را می‌توان با استفاده از متد ()decode یا کلاس ()str با مشخص کردن سیستم کدگشایی به انجام رساند:

>>> type(b)
<class 'bytes'>

>>> print(b)
b'python'

>>> b.decode("utf-8")
'python'

>>> str(b, "utf-8")
'python'

همانند کلاس ()bytes این بار برای ایجاد نوع bytearray از کلاس ()bytearray [اسناد پایتون] استفاده می‌شود:

>>> b = bytearray("python", "utf-8")

>>> b
bytearray(b'python')

>>> print(b)
bytearray(b'python')

>>> b[0]
112
>>> b[0] = 106           # 106='j'

>>> b.decode("utf-8")
'jython'
>>> str(b, "utf-8")
'jython'

بنابراین به صورت کلی در پایتون:

  • رشته‌های معمولی (حاوی کاراکترهای اَسکی و یونیکد) که تا این لحظه با آن‌ها کار می‌کردیم همگی توسط نوع str در پایتون معرفی شده‌اند. در واقع یک شی از کلاس str در پایتون هستند.

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

  • نوع تغییرپذیر (Mutable) برای داده‌های باینری، bytearray است. این نوع در واقع یک دنباله تغییرپذیر از نوع bytes را تعریف می‌کند.



😊 امیدوارم مفید بوده باشه