برنامه نویسی شبکه با پایتون بخش نهم

برنامه‌نویسی شبکه با پایتون، بخش نهم : مجموعه های تغییر پذیر در پایتون

مجموعه های تغییر پذیر Mutable Sequences از سری تغییر ناپذیر در پایتون متمایز هستند. اساسی‌ترین تمایز در اینجا آن است که مجموعه های تغییرپذیر در بعد از زمان ساخت قابل تغییر هستند.

دو مجموعه تغییر پذیر در پایتون شامل آرایه‌های بیتی و لیست‌ها هستند.

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

لیست ها در مجموعه های تغییر پذیر در پایتون پایتون

لیست ها (List) جزو مجموعه های تغییر پذیر در پایتون هستند . آن‌ها شبیه به تاپل‌ها عمل می‌کنند، اما محدودیت‌های تغییر ناپذیر بودن را ندارند.

لیست ها معمولا برای ذخیره‌سازی آیتم‌های همگون به کار می‌روند. اما هیچ محدودیتی هم در استفاده از آیتم های غیر همگون در آن‌ها وجود ندارد. لیست ها می‌توانند به شکل‌های گوناگون ساخته شده‌اند.

مثال‌های زیر را ببینید:

>>> [] # empty list

[]

>>> list() # same as []

[]

>>> [1, 2, 3] # as with tuples, items are comma separated

[1, 2, 3]

>>> [x + 5 for x in [2, 3, 4]] # Python is magic

[7, 8, 9]

>>> list((1, 3, 5, 7, 9)) # list from a tuple

[1, 3, 5, 7, 9]

>>> list('hello') # list from a string

['h', 'e', 'l', 'l', 'o']

 

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

یکی از مهمترین مواردی که در زمینه لیست ها وجود دارد، جامعیت لیست ها (List Comprehension) است که در مقالات مرتبط این موضوع را به صورت کامل برای شما شرح خواهم داد.

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

>>> a = [1, 2, 1, 3]

>>> a.append(13) # we can append anything at the end

>>> a

[1, 2, 1, 3, 13]

>>> a.count(1) # how many `1` are there in the list?

2>

>> a.extend([5, 7]) # extend the list by another (or sequence)

>>> a

[1, 2, 1, 3, 13, 5, 7]

>>> a.index(13) # position of `13` in the list (0-based indexing)

4>

>> a.insert(0, 17) # insert `17` at position 0

>>> a

[17, 1, 2, 1, 3, 13, 5, 7]

>>> a.pop() # pop (remove and return) last element

7>

>> a.pop(3) # pop element at position 3

1>

>> a

[17, 1, 2, 3, 13, 5]

>>> a.remove(17) # remove `17` from the list

>>> a

[1, 2, 3, 13, 5]

>>> a.reverse() # reverse the order of the elements in the list

>>> a

[5, 13, 3, 2, 1]

>>> a.sort() # sort the list

>>> a

[1, 2, 3, 5, 13]

>>> a.clear() # remove all elements from the list

>>> a

[]

 

در مثال بالایی مجموعه ای از متدها و شیوه‌های که بر روی لیست ها به کار برده می‌شود را به همراه نحوه استفاده از آن را مشاهده می‌کنید.

برای درک بهتر مطلب من اکنون می‌خواهم از extends در یک مثال استفاده کنم. شما می‌توانید لیست ها را با استفاده از هر نوع دیتاتایپی را ایجاد کرده و یا توسعه دهید. در این مثال این موضوع را آن را بررسی کردیم:

>>> a = list('hello') # makes a list from a string

>>> a

['h', 'e', 'l', 'l', 'o']

>>> a.append(100) # append 100, heterogeneous type

>>> a

['h', 'e', 'l', 'l', 'o', 100]

>>> a.extend((1, 2, 3)) # extend using tuple

>>> a

['h', 'e', 'l', 'l', 'o', 100, 1, 2, 3]

>>> a.extend('...') # extend using string

>>> a

['h', 'e', 'l', 'l', 'o', 100, 1, 2, 3, '.', '.', '.']

 

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

>>> a = [1, 3, 5, 7]

>>> min(a) # minimum value in the list

1>

>> max(a) # maximum value in the list

7>

>> sum(a) # sum of all values in the list

16

>>> len(a) # number of elements in the list

4

>>> b = [6, 7, 8]

>>> a + b # `+` with list means concatenation

[1, 3, 5, 7, 6, 7, 8]

>>> a * 2 # `*` has also a special meaning

[1, 3, 5, 7, 1, 3, 5, 7]

 

دو خط آخر این کد جالب توجه هستند، زیرا آنها مفهوم «اضافه کار عملگر یا Operator Overloading» را به ما نشان می‌دهند.

مفهوم اضافه کار عملگر به معنای آن است که عملگرهایی مانند +، *، -، %  و غیره می توانند بر حسب بافت معادله به شکل دیگری عمل کرده و کار اضافه‌تری را انجام دهند.  برای مثال عملگر + سبب اجتماع دو لیست می‌گردد و به همین شکل عملگر ضرب *  برای ایجاد یک لیست به تعداد عدد سمت راست عملگر * به کار می‌رود. دو خط آخر مثال بالا را با دقت ببینید. لیست (a) در اینجا دوبار تکرار شده است.

اکنون که با این مفهوم اولیه آشنا شدیم. می‌توانیم به سراغ مطالب جالب‌تری هم برویم. در این بخش من می‌خواهم شما را با متد Sort آشنا کنیم. این متد در زبان پایتون می‌تواند کارهایی را برای شما انجام دهد که در زبان های برنامه‌نویسی دیگر باید با تلاش زیادی آن‌ها را انجام دهید.

>>> from operator import itemgetter

>>> a = [(5, 3), (1, 3), (1, 2), (2, -1), (4, 9)]

>>> sorted(a)

[(1, 2), (1, 3), (2, -1), (4, 9), (5, 3)]

>>> sorted(a, key=itemgetter(0))

[(1, 3), (1, 2), (2, -1), (4, 9), (5, 3)]

>>> sorted(a, key=itemgetter(0, 1))

[(1, 2), (1, 3), (2, -1), (4, 9), (5, 3)]

>>> sorted(a, key=itemgetter(1))

[(2, -1), (1, 2), (5, 3), (1, 3), (4, 9)]

>>> sorted(a, key=itemgetter(1), reverse=True)

[(4, 9), (5, 3), (1, 3), (1, 2), (2, -1)]

 

کدی که در این مثال به کار برده‌ایم نیازمند کمی توضیح است. در ابتدا لیست (a) یک مجموعه از تاپل‌ها را در خود جای داده است. این به معنای آن است که هر آیتم از لیست a یک تاپل دو عضوی است.

هنگامی که ما از متد stored(some_list)  را فراخوان می‌کنیم، ما یک نسخه مرتب شده از لیست های مورد نظر را دریافت می‌کنیم. در این جا تاپل‌های ما با توجه به اولین عضو تاپل‌ها (عضو سمت چپ) مرتب شده‌اند.

پایتون این امکان را به ما می‌دهد که بتوانیم عضوی که باید برای مرتب کردن در نظر گرفته شود را مشخص کنیم. با استفاده از آرگومان key=itemgetter(0) می‌توانید ایندکس عضو مورد نظر را به جای صفر وارد کنید. به یاد داشته باشید که تاپل‌ها آرایه‌ها و لیست‌ها همگی از صفر شمارش می‌شوند، سپس  عدد صفر در اینجا به عضو اول تاپل‌ها اشاره دارد. عضو یک به عضو دوم و به همین شکل تا آخر به پیش می‌رود.

در اینجا می‌توانید نگاهی به آیتم key=itemgetter(1) بیندازید که تمام تاپل‌ها با توجه به عضو دوم مرتب شده‌اند.

اگر از key=itemgetter(0,1) استفاده کنید، ترتیب مرتب‌سازی به شیوه پیش فرض خواهد بود. برای کامل شدن موضوع بحث در اینجا از کلیدrevers=True استفاده کرده‌‌ایم. این کار سبب می شود که مرتب‌سازی به شیوه‌ای معکوس انجام گیرد. در آخرین خط کد مثال بالا ما از این شیوه استفاده کرده‌ایم.

الگوریتم مرتب‌سازی پایتون بسیار قوی است. این الگوریتم توسط شخصی به نام Tim Peters نوشته شده است.

الگوریتم مرتب‌سازی لیست ها به نام TimSort نامگذاری شده است و از تریب دو روش Merg و Insertion با بهترین عملکرد زمانی ایجاد شده است و به نسب زبان‌های برنامه‌نویسی دیگر عملگر خوبی دارند.

الگوریتم TimeSort یک الگوریتم برای مرتب‌سازی لیست هاست و در زمانی که چند رکورد دارای یک کلید کیسان هستد، ترتیب اصلی آن‌ها را حفظ می‌کند. نتیجه این الگوریتم را می‌توانید در زمان استفاده از متد sorted(a , key=(itemgetter(0)) مشاهده کنید. نتیجه آن برای دو تاپلی که عضو اولیه آن‌ها یکی است قابل مشاهده است. ترتیب چینش این تاپل‌ها با توجه به ترتیب اصلی چینش آن‌ها است. در حالی که بقیه تاپل‌ها از کوچک به بزرگ ترتیب دهی شده‌اند.

آرایه‌‌های بیتی درمجموعه های تغییر پذیر در پایتون پایتون

اکنون وقت آن رسیده است که به سراغ آرایه‌های بیتی ByteArrays برویم و آن‌ها را بررسی کنیم. آرایه‌های بیتی جزو مجموعه‌های تغیرناپذیر در پایتون هستند. البته در اینجا لازم است کمی آرایه‌های بیتی را توضیح دهیم.

اساسا آرایه‌های بیتی نسخه تغییر ناپذیر از آبجکت های Bytes را نشان می‌دهند. آرایه‌های بیتی مجموعه‌ای از متدهایی که برای مجموعه های تغییر پذیر و آبجکت‌های Bytes کاربرد دارند را در اختیار کاربران می‌گذارند. آیتم‌هایی که در آرایه‌های بیتی به کار برده می‌شوند باید بین رنج [0,256] باشند.

نکته:

هنگامی که بحث بازه‌ها به میان می‌آید، من از مفهوم استاندارد برای باز و بستن بازه‌ها استفاده می‌کنم. یک براکت [] در انتهای هر بازه به معنای آن است که مقدار قبل یا بعد آن براکت جزو مجموعه ما است. اما اگر از پرانتز () استفاده شود، به معنای آن است که اعداد قبل و بعد از پرانتز جزو مجموعه ما نیستند.

دانه‌بندی (Granularity) معمولا با مفهوم لبه‌های یک بازه اشتباه گرفته می‌شوند. برای مثال بازه [3,7] به معنای بازه اعداد بین 3 و 7 است که خود سه و هفت هم عضو این مجموعه هستند.

اما در بازه (3,7)، مجموعه ما شامل اعداد بین سه و هفت می‌شود، اما دو عدد سه و هفت عضو این مجموعه نیستند.

در آرایه های بیتی ما از [0, 256) استفاده کرده‌ایم که به معنای آن است که مقدار صفر جزو مجموعه است ولی عدد 256 عضو این مجموعه نیست. یکی از دلایلی که ما از این شیوه استفاده می‌کنیم آن است که این شیوه کار ما را برای کدنوبسی راحت‌تر می‌کند. در واقع ما می‌توانیم از آرایه‌های بیتی به شکل زیر استفاده کنیم.

الگوریتم های timsort در مجموعه های تغییر پذیر پایتون

مقدارهای یکه با k نشان داده شده‌اند، هنگامی که در انتهای یک بازه قرار داشته باشند، جزو آن بازه نیستند، ولی هنگامی که در ابتدای یک بازه باشند، عضور آن بازه محسوب می‌شوند. این تعریف جداسازی و ترکیب بازه‌های گوناگون را برای ما تسهیل می‌کند.

بیایید یک مثال از آرایه های بیتی را ببنیم که مطلب را بهتر درک کنیم:

>>> bytearray() # empty bytearray object

bytearray(b'')

>>> bytearray(10) # zero-filled instance with given length

bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')

>>> bytearray(range(5)) # bytearray from iterable of integers

bytearray(b'\x00\x01\x02\x03\x04')

>>> name = bytearray(b'Lina') #A - bytearray from bytes

>>> name.replace(b'L', b'l')

bytearray(b'lina')

>>> name.endswith(b'na')

True

>>> name.upper()

bytearray(b'LINA')

>>> name.count(b'L')

1

 

همانطور که در اینجا مشاهده می‌کنید، چند راه برای ساختن یک آبجکت آرایه بیتی وجود دارد. این شیوه‌‌ها هر کدام در موقعیت خودشان سودمند هستند. برای مثال در زمانی که شما دیتا ها را از یک سوکت دریافت می‌کنید، آن ها نیاز به ترکیب داده را در زمان ارسال کم می‌کنند.

دز اینجا می‌توانید علت اصلی این موضوع را درک کنید. درکدها بالا در خط #A من یک آرایه بیتی را با استفاده از name از طریق b\Lina’ مجموعه‌ها و رشته را به شیوه بسیار راحت به کار می برید. اگر دقت کنید، متوجه می‌شوید که آن‌ها می توانند به عنوان یک رشته تغییر ناپذیر در نظر گرفته شوند.

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

اگر پرسشی برای شما درباره مطالب ذکر شده ایجاد شده است، می‌توانید آن را با من در پایین همین پست به اشتراک بگذارید. من به تمام سوالات شما پاسخ خواهم داد. پیش به سوی کشف دنیای شگفت انگیز پایتون…!

No votes yet.
Please wait...

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

منو اصلی

question