تازههای پایتون 2.0¶
- نویسنده:
A.M. Kuchling و Moshe Zadka
مقدمه¶
نسخه جدیدی از پایتون، نسخه 2.0، در تاریخ ۱۶ اکتبر ۲۰۰۰ منتشر شد. این مقاله ویژگیهای جدید و هیجانانگیز 2.0 را پوشش میدهد، برخی دیگر از تغییرات مفید را برجسته میکند و به چند تغییر ناسازگار که ممکن است بازنویسی کد را ضروری کنند اشاره میکند.
توسعه پایتون هرگز میان نسخهها بهطور کامل متوقف نمیشود و همیشه جریانی پیوسته از رفع اشکالها و بهبودها در حال ارسال است. تعداد زیادی اصلاح جزئی، چند بهینهسازی، رشتههای مستند اضافی و پیامهای خطای بهتر وارد نسخه 2.0 شدند؛ فهرستکردن همهی آنها غیرممکن است، اما قطعاً مهم هستند. اگر میخواهید فهرست کامل را ببینید، به گزارشهای CVS که بهصورت عمومی در دسترس هستند مراجعه کنید. این پیشرفت به دلیل پنج توسعهدهندهای است که برای PythonLabs کار میکنند و اکنون دستمزد میگیرند تا روزهای خود را صرف رفع اشکال کنند، و همچنین به دلیل ارتباط بهتر ناشی از انتقال به SourceForge است.
پایتون 1.6 چطور؟¶
میتوان پایتون 1.6 را نسخهی پایتونِ تعهدات قراردادی در نظر گرفت. پس از آنکه تیم توسعهدهندگان هسته در مه ۲۰۰۰ CNRI را ترک کرد، CNRI درخواست کرد که نسخهی 1.6 ایجاد شود که تمام کارهای انجامشده روی پایتون در CNRI را در بر بگیرد. بنابراین پایتون 1.6 نمایانگر وضعیت درخت CVS در مه ۲۰۰۰ است و مهمترین ویژگی جدید آن پشتیبانی از یونیکد است. البته توسعه پس از مه نیز ادامه یافت، بنابراین درخت 1.6 چند اصلاح دریافت کرد تا اطمینان حاصل شود که با پایتون 2.0 سازگار رو به جلو (forward-compatible) است. در نتیجه، 1.6 بخشی از سیر تحول پایتون است، نه شاخهای جانبی.
پس، آیا باید به پایتون 1.6 علاقهی زیادی نشان دهید؟ احتمالاً نه. نسخههای 1.6final و 2.0beta1 در یک روز (۵ سپتامبر ۲۰۰۰) منتشر شدند و برنامه این بود که پایتون 2.0 طی حدود یک ماه نهایی شود. اگر برنامههایی برای نگهداری دارید، چندان منطقی به نظر نمیرسد که با مهاجرت به 1.6 چیزها را خراب کنید، آنها را تعمیر کنید و سپس ظرف یک ماه با مهاجرت به 2.0 دور دیگری از خرابی را تجربه کنید؛ بهتر است مستقیم به 2.0 بروید. بیشترِ ویژگیهای واقعاً جالبی که در این سند توصیف شدهاند فقط در 2.0 هستند، زیرا کارهای زیادی بین ماه مه و سپتامبر انجام شد.
فرایند توسعهی جدید¶
شاید مهمترین تغییر در پایتون 2.0 اصلاً در کد نباشد، بلکه در نحوه توسعه پایتون باشد: در ماه مه ۲۰۰۰، توسعهدهندگان پایتون استفاده از ابزارهایی را که SourceForge برای ذخیرهسازی کد منبع، پیگیری گزارشهای باگ و مدیریت صف ارسال وصلها فراهم کرده بود، آغاز کردند. برای گزارش باگها یا ارسال وصلها برای پایتون 2.0، از ابزارهای پیگیری باگ و مدیریت وصل موجود در صفحه پروژه پایتون، که در https://sourceforge.net/projects/python/ قرار دارد، استفاده کنید.
مهمترین خدمت از میان خدمتهایی که اکنون در SourceForge میزبانی میشوند، درخت CVS پایتون است؛ مخزن کنترل نسخهای که کد منبع پایتون را در بر دارد. پیش از این، حدود ۷ نفر یا کمی بیشتر به درخت CVS دسترسی نوشتن داشتند و همهی وصلها باید توسط یکی از افراد این فهرست کوتاه بررسی و ثبت میشدند. بدیهی است که این وضعیت چندان مقیاسپذیر نبود. با انتقال درخت CVS به SourceForge، امکان اعطای دسترسی نوشتن به افراد بیشتری فراهم شد؛ تا سپتامبر ۲۰۰۰، ۲۷ نفر قادر به ثبت تغییرات بودند؛ افزایشی چهار برابر. این امر تغییرات بزرگمقیاس را ممکن میسازد؛ تغییراتی که اگر قرار بود از صافی گروه کوچک توسعهدهندگان هسته عبور داده شوند، هرگز برای انجام آنها اقدام نمیشد. برای مثال، یک روز پیتر اشنایدر-کامپ تصمیم گرفت سازگاری با K&R C را کنار بگذارد و کد منبع C پایتون را به ANSI C تبدیل کند. پس از دریافت تأیید در فهرست پستی python-dev، او به موجی از ثبتهای پیاپی دست زد که حدود یک هفته طول کشید؛ توسعهدهندگان دیگر نیز برای کمک پیوستند و کار به پایان رسید. اگر تنها ۵ نفر دسترسی نوشتن داشتند، احتمالاً آن کار «خوب است، اما ارزش صرف زمان و تلاش لازم را ندارد» تلقی میشد و هرگز انجام نمیشد.
انتقال به استفاده از خدمات SourceForge به افزایش چشمگیری در سرعت توسعه منجر شده است. اکنون وصلها ارسال میشوند، دربارهشان نظر داده میشود، توسط افرادی غیر از ارسالکننده اصلی بازبینی میشوند و میان افراد رفتوبرگشت میکنند تا زمانی که وصل شایسته ثبت در مخزن تشخیص داده شود. اشکالها در یک مکان مرکزی پیگیری میشوند و میتوان آنها را برای رفع به یک شخص مشخص اختصاص داد، و میتوانیم تعداد اشکالهای باز را برای سنجش پیشرفت بشماریم. این دستاورد بدون هزینه به دست نیامد: توسعهدهندگان اکنون ایمیلهای بیشتری برای رسیدگی دارند، باید فهرستهای پستی بیشتری را دنبال کنند، و ابزارهای خاصی باید برای محیط جدید نوشته میشد. برای مثال، SourceForge پیامهای ایمیل پیشفرض برای اطلاعرسانی وصل و اشکال را ارسال میکند که کاملاً بیفایدهاند؛ از این رو Ka-Ping Yee یک اسکرپر صفحه (screen-scraper) HTML نوشت که پیامهای مفیدتری ارسال میکند.
سهولت افزودن کد در ابتدا چندین دردِ رشد ایجاد کرد؛ مانند اینکه کدی پیش از آماده شدن یا بدون کسب توافق روشن از گروه توسعهدهندگان در مخزن ثبت میشد. فرایند تأییدی که شکل گرفته است، تا حدی مشابه فرایند مورد استفادهی گروه Apache است. توسعهدهندگان میتوانند روی یک وصل رأی +1، +0، -0 یا -1 بدهند؛ +1 و -1 به معنای پذیرش یا رد هستند، در حالی که +0 و -0 به این معناست که توسعهدهنده نسبت به تغییر عمدتاً بیتفاوت است، هرچند با گرایشی خفیف به سمت مثبت یا منفی. مهمترین تفاوت نسبت به الگوی Apache این است که رأیگیری اساساً مشورتی است و به Guido van Rossum، که دارای عنوان «دیکتاتور خیرخواه مادامالعمر» است، میفهماند که نظر عموم چیست. او همچنان میتواند نتیجهی یک رأیگیری را نادیده بگیرد و تغییری را حتی اگر کامیونیتی با او مخالف باشد، تأیید یا رد کند.
تولید یک وصل واقعی، آخرین گام در افزودن یک قابلیت جدید است و معمولاً در مقایسه با وظیفهی پیشینِ دستیافتن به یک طراحی خوب، آسان است. بحثهای مربوط به قابلیتهای جدید اغلب میتوانند به رشتههای طولانی فهرست پستی تبدیل شوند و پیگیری بحث را دشوار کنند؛ هیچکس نیز نمیتواند تمام پستهای ارسالی به python-dev را بخواند. بنابراین، فرایندی نسبتاً رسمی برای نگارش پیشنهادهای بهبود پایتون (PEPها) ایجاد شده است که از فرایند RFC اینترنت الگو گرفته است. PEPها اسناد پیشنویسی هستند که یک قابلیت جدید پیشنهادی را توصیف میکنند و بهطور مداوم بازنگری میشوند تا زمانی که کامیونیتی به اجماع برسد و پیشنهاد را بپذیرد یا رد کند. به نقل از مقدمهی PEP 1، «هدف و رهنمودهای PEP»:
PEP مخفف پیشنهاد بهبود پایتون (Python Enhancement Proposal) است. یک PEP سند طراحی است که اطلاعاتی را به کامیونیتی پایتون ارائه میدهد، یا قابلیت جدیدی را برای پایتون توصیف میکند. PEP باید مشخصات فنی مختصری از قابلیت و دلیل آن قابلیت را ارائه کند.
ما در نظر داریم که PEPها سازوکارهای اصلی برای پیشنهاد قابلیتهای جدید، برای جمعآوری نظرات کامیونیتی دربارهی یک مسئله و برای مستندسازی تصمیمهای طراحیای که در پایتون به کار رفتهاند، باشند. نویسندهی PEP مسئول ایجاد اجماع در کامیونیتی و مستندسازی نظرات مخالف است.
برای جزئیات فرایند ویرایشی، سبک و قالب PEPها، بقیهی PEP 1 را بخوانید. PEPها در درخت CVS پایتون روی SourceForge نگهداری میشوند، هرچند بخشی از توزیع Python 2.0 نیستند، و بهصورت HTML نیز از https://peps.python.org/ در دسترس هستند. تا سپتامبر ۲۰۰۰، ۲۵ PEP وجود دارد، از PEP 201 با عنوان «Lockstep Iteration» تا PEP 225 با عنوان «Elementwise/Objectwise Operators».
یونیکد¶
بزرگترین ویژگی جدید در پایتون 2.0، یک نوع داده بنیادی جدید است: رشتههای یونیکد. یونیکد بهجای عدد ۸ بیتی که اسکی از آن استفاده میکند، از اعداد ۱۶ بیتی برای نمایش نویسهها بهره میگیرد؛ به این معنا که میتوان از ۶۵٬۵۳۶ نویسه متمایز پشتیبانی کرد.
رابط نهایی پشتیبانی از یونیکد از راه بیشمار بحثهای اغلب تند و تیز در فهرست پستی python-dev به دست آمد و عمدتاً توسط Marc-André Lemburg، بر پایهی پیادهسازی نوع رشتهی یونیکد از سوی Fredrik Lundh، پیادهسازی شد. توضیح مفصلی از این رابط در قالب PEP 100 با عنوان «Python Unicode Integration» نوشته شد. این مقاله صرفاً مهمترین نکات دربارهی رابطهای یونیکد را پوشش میدهد.
در کد منبع پایتون، رشتههای یونیکد به صورت u"string" نوشته میشوند. نویسههای دلخواه یونیکد را میتوان با استفاده از دنبالهی گریز جدید \uHHHH نوشت، که در آن HHHH عددی ۴ رقمی در مبنای شانزده از 0000 تا FFFF است. از دنبالهی گریز موجود \xHH نیز میتوان استفاده کرد، و دنبالههای خنثیسازی در مبنای هشت را میتوان برای نویسههایی تا U+01FF به کار برد، که با \777 نمایش داده میشود.
رشتههای یونیکد، همانند رشتههای معمولی، یک نوع دنبالهی تغییرناپذیر هستند. میتوان آنها را اندیسگذاری و اسلایس کرد، اما نمیتوان آنها را درجا تغییر داد. رشتههای یونیکد یک متد encode( [encoding] ) دارند که یک رشتهی ۸-بیتی را با کدگذاری موردنظر برمیگرداند. کدگذاریها با رشتهها نامگذاری میشوند، مانند 'ascii'، 'utf-8'، 'iso-8859-1' یا هر چیز دیگری. یک API کدک برای پیادهسازی و ثبت کدگذاریهای جدید تعریف شده است که سپس در سراسر یک برنامهی پایتون در دسترس هستند. اگر کدگذاریای مشخص نشده باشد، کدگذاری پیشفرض معمولاً اسکی ۷-بیتی است، هرچند میتوان آن را برای نصب پایتون شما با فراخوانی تابع sys.setdefaultencoding(encoding) در نسخهی سفارشیشدهی site.py تغییر داد.
ترکیب رشتههای ۸-بیتی و یونیکد همیشه با استفاده از کدگذاری پیشفرض اسکی بهصورت ضمنی به یونیکد تبدیل میشود؛ نتیجهی 'a' + u'bc' برابر u'abc' است.
توابع توکار جدیدی افزوده شدهاند و توابع توکار موجود برای پشتیبانی از یونیکد تغییر یافتهاند:
unichr(ch)یک رشته یونیکد به طول ۱ نویسه برمیگرداند که حاوی نویسه ch است.ord(u)، که در آن u یک رشتهی معمولی یا یونیکدی تکنویسهای است، شمارهی نویسه را به صورت یک عدد صحیح برمیگرداند.unicode(string [, encoding] [, errors] )یک رشته یونیکد از یک رشته ۸-بیتی میسازد.encodingرشتهای است که نام کدگذاری مورد استفاده را مشخص میکند. پارامترerrorsنحوه برخورد با نویسههایی را مشخص میکند که برای کدگذاری فعلی نامعتبرند؛ ارسال'strict'به عنوان مقدار باعث میشود در صورت هرگونه خطای کدگذاری استثنا ایجاد شود، در حالی که'ignore'باعث میشود خطاها بیصدا نادیده گرفته شوند و'replace'در صورت هرگونه مشکل از U+FFFD، نویسه جایگزین رسمی، استفاده میکند.دستور
execو توابع توکار مختلفی مانندeval()وgetattr()وsetattr()نیز علاوه بر رشتههای معمولی، رشتههای یونیکد را میپذیرند. (ممکن است در فرایند رفع این مشکل، برخی توابع توکار از قلم افتاده باشند؛ اگر تابع توکاری را یافتید که رشتهها را میپذیرد اما رشتههای یونیکد را بههیچوجه نمیپذیرد، لطفاً آن را بهعنوان یک اشکال گزارش کنید.)
یک ماژول جدید، unicodedata، رابطی برای ویژگیهای نویسههای یونیکد فراهم میکند. برای مثال، unicodedata.category(u'A') رشتهی ۲ نویسهای 'Lu' را برمیگرداند که در آن 'L' نشان میدهد که این نویسه یک حرف است و 'u' یعنی اینکه بزرگ است. unicodedata.bidirectional(u'\u0660') مقدار 'AN' را برمیگرداند که به این معناست که U+0660 یک عدد عربی است.
ماژول codecs شامل توابعی برای جستجوی کدگذاریهای موجود و ثبت کدگذاریهای جدید است. مگر اینکه بخواهید کدگذاری جدیدی را پیادهسازی کنید، بیشتر اوقات از تابع codecs.lookup(encoding) استفاده خواهید کرد که یک تاپل ۴ عنصری برمیگرداند: (encode_func, decode_func, stream_reader, stream_writer).
encode_func تابعی است که یک رشته یونیکد را دریافت میکند و یک تاپل دوتایی
(string, length)برمیگرداند. string یک رشته ۸ بیتی است که بخشی (شاید همه) از رشته یونیکد تبدیلشده به کدگذاری دادهشده را در بر میگیرد، و length به شما میگوید چه مقدار از رشته یونیکد تبدیل شده است.decode_func برعکس encode_func است؛ یک رشته هشتبیتی را دریافت میکند و یک تاپل دوتایی
(ustring, length)برمیگرداند که از رشته یونیکد حاصل ustring و عدد صحیح length تشکیل شده است؛ length مشخص میکند چه مقدار از رشته هشتبیتی مصرف شده است.stream_reader کلاسی است که کدگشایی ورودی از یک جریان را پشتیبانی میکند. stream_reader(file_obj) شیئی را برمیگرداند که متدهای
read()،readline()وreadlines()را پشتیبانی میکند. همهی این متدها از کدگذاری دادهشده ترجمه میکنند و رشتههای یونیکد برمیگردانند.stream_writer، بهطور مشابه، کلاسی است که از کدگذاری خروجی به یک جریان پشتیبانی میکند. stream_writer(file_obj) شیئی را برمیگرداند که از متدهای
write()وwritelines()پشتیبانی میکند. این متدها رشتههای یونیکد دریافت میکنند و آنها را در خروجی به کدگذاری دادهشده تبدیل میکنند.
برای مثال، کد زیر یک رشته یونیکد را در یک پرونده مینویسد و آن را بهصورت UTF-8 کدگذاری میکند:
import codecs
unistr = u'\u0660\u2000ab ...'
(UTF8_encode, UTF8_decode,
UTF8_streamreader, UTF8_streamwriter) = codecs.lookup('UTF-8')
output = UTF8_streamwriter( open( '/tmp/output', 'wb') )
output.write( unistr )
output.close()
سپس کد زیر ورودی UTF-8 را از پرونده میخواند:
input = UTF8_streamreader( open( '/tmp/output', 'rb') )
print repr(input.read())
input.close()
عبارتهای باقاعدهی آگاه از یونیکد از طریق ماژول re در دسترس هستند؛ این ماژول پیادهسازی زیربنایی جدیدی به نام SRE دارد که توسط Fredrik Lundh از شرکت Secret Labs AB نوشته شده است.
گزینهی خط فرمان -U افزوده شد که باعث میشود کامپایلر پایتون همهی مقادیر لفظی رشته را بهعنوان مقادیر لفظی رشتهی یونیکد تفسیر کند. این گزینه برای استفاده در آزمودن و آمادهسازی کد پایتون شما برای آینده در نظر گرفته شده است، زیرا ممکن است نسخهای از پایتون در آینده از پشتیبانی رشتههای ۸-بیتی دست بردارد و تنها رشتههای یونیکد ارائه کند.
درک فهرستی¶
فهرستها نوع دادهای پرکاربرد در پایتون هستند و بسیاری از برنامهها در مقطعی فهرستی را دستکاری میکنند. دو عملیات رایج روی فهرستها عبارتاند از پیمایش آنها با حلقه، و سپس یا انتخاب عناصری که معیار معینی را برآورده میکنند، یا اعمال تابعی بر هر عنصر. برای نمونه، با داشتن فهرستی از رشتهها، ممکن است بخواهید همهی رشتههایی را که حاوی زیررشتهی معینی هستند بیرون بکشید، یا فضای سفید انتهایی را از هر سطر حذف کنید.
توابع موجود map() و filter() میتوانند برای این منظور استفاده شوند، اما آنها به یک تابع بهعنوان یکی از آرگومانهایشان نیاز دارند. اگر تابع توکاری موجود باشد که بتوان آن را مستقیماً پاس داد، این اشکالی ندارد، اما اگر چنین تابعی وجود نداشته باشد، باید تابع کوچکی بسازید تا کار مورد نیاز را انجام دهد، و اگر آن تابع کوچک به اطلاعات اضافی نیاز داشته باشد، قواعد محدودهبندی پایتون نتیجه را زشت میکند. مثال اول در پاراگراف قبلی را در نظر بگیرید، یعنی یافتن تمام رشتههای موجود در فهرست که حاوی زیررشتهی معینی هستند. برای انجام این کار میتوانید چنین بنویسید:
# Given the list L, make a list of all strings
# containing the substring S.
sublist = filter( lambda s, substring=S:
string.find(s, substring) != -1,
L)
به دلیل قواعد محدودهی پایتون، از یک آرگومان پیشفرض استفاده میشود تا تابع بینامی که توسط عبارت lambda ایجاد میشود، بداند جستجو برای چه زیررشتهای انجام میشود. درکهای فهرستی این کار را تمیزتر میکنند:
sublist = [ s for s in L if string.find(s, S) != -1 ]
درکهای فهرستی به شکل زیر هستند:
[ expression for expr in sequence1
for expr2 in sequence2 ...
for exprN in sequenceN
if condition ]
بندهای for...in شامل دنبالههایی هستند که باید پیمایش شوند. دنبالهها لازم نیست طول یکسانی داشته باشند، زیرا آنها بهصورت موازی پیمایش نمیشوند، بلکه از چپ به راست پیمایش میشوند؛ این موضوع در پاراگرافهای بعدی با وضوح بیشتری توضیح داده شده است. المانهای فهرست تولیدشده مقادیر متوالی عبارت خواهند بود. بند پایانی if اختیاری است؛ در صورت وجود، عبارت تنها زمانی ارزیابی و به نتیجه افزوده میشود که شرط درست باشد.
برای اینکه معناشناسی کاملاً روشن باشد، درک فهرستی معادل کد پایتون زیر است:
for expr1 in sequence1:
for expr2 in sequence2:
...
for exprN in sequenceN:
if (condition):
# Append the value of
# the expression to the
# resulting list.
این بدان معناست که وقتی چندین بند for...in وجود دارد، فهرست حاصل برابر با حاصلضرب طول همهی دنبالهها خواهد بود. اگر دو فهرست به طول ۳ داشته باشید، فهرست خروجی ۹ عنصر خواهد داشت:
seq1 = 'abc'
seq2 = (1,2,3)
>>> [ (x,y) for x in seq1 for y in seq2]
[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('b', 3), ('c', 1),
('c', 2), ('c', 3)]
برای جلوگیری از ایجاد ابهام در سینتکس پایتون، اگر عبارت در حال ایجاد یک تاپل باشد، باید درون پرانتز قرار گیرد. نخستین درک فهرستی در زیر یک خطای نحوی است، در حالی که دومی صحیح است:
# Syntax error
[ x,y for x in seq1 for y in seq2]
# Correct
[ (x,y) for x in seq1 for y in seq2]
ایدهی درک فهرستی در اصل از زبان برنامهنویسی تابعی Haskell (https://www.haskell.org) سرچشمه گرفته است. Greg Ewing مؤثرترین استدلال را برای افزودن آنها به پایتون ارائه داد و وصل اولیهی درک فهرستی را نوشت؛ این وصل سپس در فهرست پستی python-dev برای مدتی بهظاهر بیپایان مورد بحث قرار گرفت و Skip Montanaro آن را بهروز نگه میداشت.
انتساب افزوده¶
عملگرهای انتساب افزوده (augmented assignment)، قابلیت دیگری که مدتها بود درخواست میشد، به پایتون 2.0 اضافه شدهاند. عملگرهای انتساب افزوده شامل +=، -=, *= و غیره هستند. برای نمونه، دستور a += 2 مقدار متغیر a را ۲ واحد افزایش میدهد که معادل دستور کمی طولانیتر a = a + 2 است.
فهرست کامل عملگرهای انتساب پشتیبانیشده عبارت است از +=، -=, *=, /=, %=, **=, &=, |=, ^=, >>= و <<=. کلاسهای پایتون میتوانند عملگرهای انتساب افزوده را با تعریف متدهایی به نام __iadd__()، __isub__() و غیره بازنویسی کنند. برای مثال، کلاس Number زیر یک عدد را ذخیره میکند و از استفاده از += برای ایجاد نمونهای جدید با مقدار افزایشیافته پشتیبانی میکند.
class Number:
def __init__(self, value):
self.value = value
def __iadd__(self, increment):
return Number( self.value + increment)
n = Number(5)
n += 3
print n.value
متد ویژهی __iadd__() با مقدار افزایش فراخوانی میشود و باید نمونهی جدیدی را برگرداند که مقدارش بهشکل مناسب تغییریافته باشد؛ این مقدار بازگشتی بهعنوان مقدار جدید متغیر سمت چپ مقید میشود.
عملگرهای انتساب افزوده نخستینبار در زبان برنامهنویسی C معرفی شدند و بیشتر زبانهای مشتقشده از C، مانند awk، C++، Java، Perl و PHP نیز از آنها پشتیبانی میکنند. وصل انتساب افزوده توسط Thomas Wouters پیادهسازی شد.
متدهای رشته¶
تا پیش از این، قابلیتهای دستکاری رشته در ماژول string قرار داشت که معمولاً فرانتاند (front-end) ماژول strop نوشتهشده به زبان C بود. افزودن یونیکد برای ماژول strop دشواریای ایجاد کرد، زیرا تمام توابع باید بازنویسی میشدند تا بتوانند رشتههای ۸-بیتی یا یونیکد را بپذیرند. برای توابعی مانند string.replace() که ۳ آرگومان رشتهای میگیرد، این به معنای هشت جایگشت ممکن و به همان نسبت کد پیچیده است.
در عوض، پایتون 2.0 مسئله را به دوش نوع رشته میاندازد و قابلیت دستکاری رشته را از طریق متدها هم روی رشتههای ۸-بیتی و هم روی رشتههای یونیکد در دسترس قرار میدهد.
>>> 'andrew'.capitalize()
'Andrew'
>>> 'hostname'.replace('os', 'linux')
'hlinuxtname'
>>> 'moshe'.find('sh')
2
چیزی که تغییر نکرده است — بهرغم یک شوخی قابل توجه روز دروغ آوریل — این است که رشتههای پایتون تغییرناپذیر هستند. بنابراین، متدهای رشته رشتههای جدیدی برمیگردانند و رشتهای را که بر روی آن عمل میکنند، تغییر نمیدهند.
ماژول قدیمی string همچنان برای سازگاری با نسخههای پیشین موجود است، اما عمدتاً بهعنوان فرانتاندی برای متدهای جدید رشته عمل میکند.
دو متدی که در نسخههای پیش از 2.0 هیچ نظیری نداشتند، هرچند که مدتها در JPython وجود داشتند، startswith() و endswith() هستند. s.startswith(t) معادل s[:len(t)] == t است، در حالی که s.endswith(t) معادل s[-len(t):] == t است.
متد دیگری که ارزش ذکر ویژهای دارد، join() است. متد join() یک رشته، یک پارامتر دریافت میکند که دنبالهای از رشتههاست، و با ترتیب معکوس آرگومانها، معادل تابع string.join() از ماژول قدیمی string است. به عبارت دیگر، s.join(seq) معادل string.join(seq, s) قدیمی است.
زبالهروبی چرخهها¶
پیادهسازی C پایتون از شمارش ارجاع برای پیادهسازی زبالهروبی استفاده میکند. هر شیء پایتون شمارشی از تعداد ارجاعهای اشارهکننده به خود را نگه میدارد و این شمارش را با ایجاد یا نابود شدن ارجاعها تنظیم میکند. هنگامی که شمارش ارجاع به صفر برسد، شیء دیگر دسترسیپذیر نیست، زیرا برای دسترسی به یک شیء باید ارجاعی به آن داشته باشید، و اگر شمارش صفر باشد، دیگر هیچ ارجاعی وجود ندارد.
شمارش ارجاع چند ویژگی خوشایند دارد: درک و پیادهسازی آن آسان است و پیادهسازی حاصل، قابل حمل و نسبتاً سریع است و با کتابخانههای دیگری که طرحوارههای مدیریت حافظهی خود را پیادهسازی میکنند، بهخوبی سازگار است. مشکل اصلی شمارش ارجاع این است که گاهی متوجه نمیشود که اشیاء دیگر دسترسیپذیر نیستند، که این امر به نشت حافظه منجر میشود. این وضعیت زمانی رخ میدهد که چرخههایی از ارجاعها وجود داشته باشند.
سادهترین چرخهی ممکن را در نظر بگیرید، نمونهای از کلاس که ارجاعی به خود دارد:
instance = SomeClass()
instance.myself = instance
پس از اجرای دو سطر کد بالا، شمارش ارجاع instance برابر با ۲ است؛ یک ارجاع از متغیری با نام 'instance' است و ارجاع دیگر از ویژگی myself نمونه است.
اگر خط بعدی کد del instance باشد، چه اتفاقی میافتد؟ شمارش ارجاع instance یک واحد کاهش مییابد، بنابراین شمارش ارجاع آن برابر ۱ است؛ ارجاع موجود در ویژگی myself همچنان وجود دارد. با این حال، این نمونه دیگر از طریق کد پایتون دسترسیپذیر نیست و میتوان آن را حذف کرد. اگر چندین شیء به یکدیگر ارجاع داشته باشند، میتوانند در یک چرخه شرکت کنند و این امر باعث نشت همهی این اشیاء میشود.
پایتون 2.0 با اجرای دورهای یک الگوریتم تشخیص چرخه که به دنبال چرخههای دسترسناپذیر میگردد و اشیاء درگیر را حذف میکند، این مشکل را برطرف میکند. ماژول جدید gc توابعی برای انجام زبالهروبی، به دست آوردن آمار اشکالزدایی و تنظیم پارامترهای جمعکننده فراهم میکند.
اجرای الگوریتم تشخیص چرخه کمی زمان میبرد و بنابراین مقداری سربار اضافی به همراه خواهد داشت. امید است که پس از کسب تجربه در جمعآوری چرخه با استفاده از نسخه 2.0، پایتون 2.1 بتواند با تنظیم دقیق، این سربار را به حداقل برساند. هنوز مشخص نیست چه مقدار کارایی از دست میرود، زیرا بنچمارک کردن این مورد دشوار است و به میزان تکرار ساخت و نابودی اشیاء توسط برنامه بستگی حیاتی دارد. اگر حتی نمیتوانید کوچکترین افت سرعت را تحمل کنید یا گمان میبرید که جمعآوری چرخه دچار اشکال است، میتوانید با تعیین سوییچ --without-cycle-gc هنگام اجرای اسکریپت configure، تشخیص چرخهها را در زمان کامپایل پایتون غیرفعال کنید.
چندین نفر به این مسئله پرداختند و در یافتن راهحل مشارکت داشتند. یک پیادهسازی اولیه از رویکرد تشخیص چرخه توسط Toby Kelsey نوشته شد. الگوریتم فعلی را Eric Tiedemann در جریان بازدیدی از CNRI پیشنهاد کرد و Guido van Rossum و Neil Schemenauer دو پیادهسازی متفاوت نوشتند که بعداً توسط Neil یکپارچه شدند. بسیاری از افراد دیگر نیز در طول مسیر پیشنهادهایی ارائه کردند؛ آرشیوهای مارس ۲۰۰۰ فهرست پستی python-dev بیشتر بحثهای مرتبط را در بر میگیرند، بهویژه در گفتگوهایی با عنوان «Reference cycle collection for Python» و «Finalization again».
سایر تغییرات هسته¶
تغییرهای جزئی گوناگونی در سینتکس و توابع توکار پایتون اعمال شده است. هیچیک از این تغییرها دامنهی بسیار گستردهای ندارند، اما امکانات کاربردی و مفیدی به شمار میروند.
تغییرات جزئی زبان¶
سینتکس جدید، فراخوانی یک تابع معین را با تاپلی از آرگومانها و/یا دیکشنریای از آرگومانهای کلیدواژهای آسانتر میکند. در پایتون 1.5 و نسخههای پیش از آن، شما از تابع توکار apply() استفاده میکردید: apply(f, args, kw) تابع f() را با تاپل آرگومانهای args و آرگومانهای کلیدواژهای موجود در دیکشنری kw فراخوانی میکند. apply() در نسخهی 2.0 نیز همان است، اما به لطف وصلی از سوی گرگ ایوینگ، f(*args, **kw) راهی کوتاهتر و شفافتر برای رسیدن به همان نتیجه است. این سینتکس با سینتکس تعریف توابع متقارن است:
def f(*args, **kw):
# args is a tuple of positional args,
# kw is a dictionary of keyword args
...
اکنون میتوان با قرار دادن >> file پس از print، خروجی دستور print را به یک شیء شبهپرونده هدایت کرد؛ این کار مشابه عملگر تغییر مسیر (redirection) در پوستههای یونیکس است. پیش از این، شما یا باید از متد write() شیء شبهپرونده استفاده میکردید (که راحتی و سادگی print را ندارد)، یا میتوانستید مقدار جدیدی به sys.stdout انتساب کنید و سپس مقدار قبلی را بازگردانید. برای ارسال خروجی به خطای استاندارد، نوشتن این کد بسیار آسانتر است:
print >> sys.stderr, "Warning: action field not supplied"
اکنون میتوان هنگام ایمپورت کردن ماژولها، با استفاده از سینتکس import module as name یا from module import name as othername نام آنها را تغییر داد. این وصله توسط Thomas Wouters ارسال شد.
یک سبک قالببندی جدید هنگام استفاده از عملگر % در دسترس است؛ '%r' خروجی repr() آرگومان خود را درج میکند. این مورد نیز با توجه به ملاحظات تقارن افزوده شد، این بار برای تقارن با سبک قالببندی موجود '%s' که خروجی str() آرگومان خود را درج میکند. برای مثال، '%r %s' % ('abc', 'abc') رشتهای شامل 'abc' abc را برمیگرداند.
پیش از این هیچ راهی برای پیادهسازی کلاسی وجود نداشت که عملگر توکار in پایتون را بازنویسی کند و نسخهی سفارشی آن را پیادهسازی کند. obj in seq در صورتی مقدار true برمیگرداند که obj در دنبالهی seq موجود باشد؛ پایتون این را صرفاً با امتحان کردن تکتک اندیسهای دنباله محاسبه میکند تا زمانی که یا obj پیدا شود یا IndexError رخ دهد. Moshe Zadka وصلی ارائه کرد که متد جادویی __contains__() را برای فراهم کردن پیادهسازی سفارشی برای in اضافه میکند. علاوه بر این، اشیاء توکار جدیدی که به زبان C نوشتهشدهاند میتوانند از طریق یک جایگاه جدید در پروتکل دنباله تعریف کنند که in برای آنها به چه معناست.
نسخههای قدیمیتر پایتون از یک الگوریتم بازگشتی برای حذف اشیاء استفاده میکردند. ساختارهای دادهی عمیقاً تودرتو میتوانستند باعث شوند مفسر پشتهی C را پر کند و فروپاشی کند؛ Christian Tismer منطق حذف را برای رفع این مشکل بازنویسی کرد. در موضوعی مرتبط، مقایسهی اشیاء بازگشتی بهطور بینهایت بازگشتی ادامه مییافت و منجر به فروپاشی میشد؛ Jeremy Hylton این کد را بازنویسی کرد تا دیگر فروپاشی نکند و در عوض نتیجهی مفیدی تولید کند. برای مثال، پس از این کد:
a = []
b = []
a.append(a)
b.append(b)
مقایسهی a==b مقدار درست را برمیگرداند، زیرا این دو ساختار دادهی بازگشتی همریخت هستند. برای دیدن بحثی که به این پیادهسازی انجامید و برخی پیوندهای مرتبط مفید، به رشتهی "trashcan and PR#7" در آرشیوهای آوریل ۲۰۰۰ فهرست پستی python-dev مراجعه کنید. توجه داشته باشید که مقایسهها اکنون میتوانند استثنا نیز ایجاد کنند. در نسخههای پیشین پایتون، یک عملیات مقایسه مانند cmp(a,b) همیشه پاسخی تولید میکرد، حتی اگر متد __cmp__() تعریفشده توسط کاربر با خطایی روبهرو میشد، چرا که استثنای حاصل صرفاً بهصورت بیصدا بلعیده میشد.
کارهایی برای پورت کردن پایتون به ویندوز ۶۴ بیتی روی پردازندهی Itanium انجام شده است که عمدتاً حاصل کار Trent Mick از ActiveState است. (سردرگمکننده است که sys.platform روی Win64 همچنان 'win32' است، زیرا ظاهراً برای سهولت پورت کردن، MS Visual C++ کد را روی Itanium ۳۲ بیتی در نظر میگیرد.) PythonWin همچنین از Windows CE پشتیبانی میکند؛ برای اطلاعات بیشتر، صفحهی Python CE در https://pythonce.sourceforge.net/ را ببینید.
Darwin/MacOS X یک پلتفرم جدید دیگر است؛ پشتیبانی اولیه از آن در پایتون 2.0 ارائه شده است. اگر "configure --with-dyld --with-suffix=.x" را مشخص کنید، بارگذاری پویا کار میکند. برای دستورالعملهای بیشتر، به README موجود در توزیع کد منبع پایتون مراجعه کنید.
تلاشی برای کاهش یکی از عیبهای پایتون انجام شده است: استثنای NameError که اغلب سبب سردرگمی میشود و هنگامی رخ میدهد که کد پیش از آنکه مقداری به متغیر محلی انتساب داده شود، به آن ارجاع میکند. برای مثال، کد زیر در هر دو نسخهی 1.5.2 و 2.0 روی دستور print استثنایی ایجاد میکند؛ در نسخهی 1.5.2 استثنای NameError ایجاد میشود، در حالی که نسخهی 2.0 استثنای جدید UnboundLocalError را ایجاد میکند. UnboundLocalError زیرکلاسی از NameError است، بنابراین هر کد موجودی که انتظار دارد NameError ایجاد شود، همچنان باید کار کند.
def f():
print "i=",i
i = i + 1
f()
دو استثنای جدید، TabError و IndentationError، معرفی شدهاند. هر دو زیرکلاسهایی از SyntaxError هستند و زمانی ایجاد میشوند که کد پایتون تورفتگی نامناسبی داشته باشد.
تغییرات در توابع توکار¶
یک توکار جدید، zip(seq1, seq2, ...)، اضافه شده است. zip() فهرستی از تاپلها را برمیگرداند که در آن هر تاپل شامل i-اُمین عنصر از هر یک از دنبالههای آرگومان است. تفاوت بین zip() و map(None, seq1, seq2) این است که map() در صورتی که طول همهی دنبالهها یکسان نباشد، دنبالهها را با None پُر میکند، در حالی که zip() فهرست بازگرداندهشده را به طول کوتاهترین دنبالهی آرگومان قطع میکند.
توابع int() و long() اکنون زمانی که آرگومان اول یک رشته باشد، پارامتر اختیاری «base» را میپذیرند. int('123', 10) مقدار 123 را برمیگرداند، در حالی که int('123', 16) مقدار 291 را برمیگرداند. int(123, 16) استثنای TypeError را با پیام "can't convert non-string with explicit base" ایجاد میکند.
متغیر جدیدی که اطلاعات دقیقتری از نسخه در خود نگه میدارد، به ماژول sys اضافه شده است. sys.version_info یک تاپل (major, minor, micro, level, serial) است. برای مثال، در نسخهی فرضی 2.0.1beta1، sys.version_info برابر (2, 0, 1, 'beta', 1) خواهد بود. level رشتهای است مانند "alpha"، "beta" یا "final" برای انتشار نهایی.
دیکشنریها متد جدید عجیبی به نام setdefault(key, default) دارند که رفتاری مشابه متد موجود get() دارد. با این حال، اگر کلید موجود نباشد، setdefault() هم مانند get() مقدار default را برمیگرداند و هم آن را بهعنوان مقدار key در دیکشنری درج میکند. بنابراین، سطرهای کد زیر:
if dict.has_key( key ): return dict[key]
else:
dict[key] = []
return dict[key]
میتواند به یک دستور return dict.setdefault(key, []) کاهش یابد.
مفسر یک حداکثر عمق بازگشت تعیین میکند تا بازگشت مهارگسیخته را پیش از آنکه پشتهی C را پر کند و موجب برونریزی هسته یا خطای حفاظت عمومی (GPF) شود، رهگیری کند. پیشتر این حد هنگام کامپایل پایتون ثابت بود، اما در نسخهی 2.0 میتوان حداکثر عمق بازگشت را با استفاده از sys.getrecursionlimit() و sys.setrecursionlimit() خواند و تغییر داد. مقدار پیشفرض ۱۰۰۰ است و میتوان مقدار حداکثری تقریبی برای یک سکوی مشخص را با اجرای اسکریپت جدید Misc/find_recursionlimit.py یافت.
انتقال به 2.0¶
نسخههای جدید پایتون تلاش زیادی میکنند تا با نسخههای قبلی سازگار باشند، و کارنامهی این امر نیز بسیار خوب بوده است. با این حال، برخی تغییرات — معمولاً به این دلیل که تصمیمات طراحی اولیهای را که در عمل کاملاً اشتباه از آب درآمده بودند اصلاح میکنند — به اندازهای مفید تلقی میشوند که همیشه نمیتوان از شکستن سازگاری با نسخههای قبلی اجتناب کرد. این بخش تغییراتی در پایتون 2.0 را فهرست میکند که ممکن است باعث از کار افتادن کدهای قدیمی پایتون شوند.
تغییری که احتمالاً بیشترین خرابی را در کدها ایجاد میکند، سختگیرانهتر شدن آرگومانهای پذیرفتهشده توسط برخی متدهاست. برخی متدها چندین آرگومان میگرفتند و با آنها مانند یک تاپل رفتار میکردند، بهویژه متدهای مختلف فهرست مانند append() و insert(). در نسخههای پیشین پایتون، اگر L یک فهرست باشد، L.append( 1,2 ) تاپل (1,2) را به فهرست اضافه میکند. در پایتون 2.0 این کار باعث برپا شدن استثنای TypeError با پیام «append requires exactly 1 argument; 2 given» میشود. راهحل، بهسادگی افزودن یک جفت پرانتز دیگر برای ارسال هر دو مقدار بهعنوان یک تاپل است: L.append( (1,2) ).
نسخههای پیشین این متدها آسانگیرتر بودند، زیرا برای تجزیه آرگومانهای خود از یک تابع قدیمی در رابط C پایتون استفاده میکردند؛ نسخه 2.0 آنها را مدرنسازی میکند تا از PyArg_ParseTuple()، تابع فعلی تجزیه آرگومان، استفاده کنند که پیامهای خطای مفیدتری ارائه میدهد و فراخوانیهای چندآرگومانی را به عنوان خطا در نظر میگیرد. اگر واقعاً ناچارید از نسخه 2.0 استفاده کنید اما نمیتوانید کد خود را اصلاح کنید، میتوانید Objects/listobject.c را ویرایش کنید و نماد پیشپردازنده NO_STRICT_LIST_APPEND را تعریف کنید تا رفتار قدیمی حفظ شود؛ این کار توصیه نمیشود.
برخی از توابع ماژول socket همچنان به این شیوه سهلگیر هستند. برای مثال، socket.connect( ('hostname', 25) ) شکل درست است و تاپلِ نمایانگرِ نشانی IP را ارسال میکند، اما socket.connect('hostname', 25) نیز کار میکند. socket.connect_ex و socket.bind بهطور مشابه آسانگیر هستند. نسخهی 2.0alpha1 این توابع را سختگیرانهتر کرد، اما از آنجا که مستندات در واقع از شکل نادرست چندآرگومانی استفاده میکرد، بسیاری از افراد کدی نوشتند که با بررسی سختگیرانهتر میشکست. GvR در مواجهه با واکنش عمومی، این تغییرات را پس گرفت؛ بنابراین برای ماژول socket، مستندات اصلاح شد و شکل چندآرگومانی صرفاً بهعنوان منسوخ علامتگذاری شده است؛ در نسخهای آینده از پایتون دوباره سختگیرانهتر خواهد شد.
گریز \x در رشتههای لفظی اکنون دقیقاً ۲ رقم مبنای شانزده دریافت میکند. پیشتر، این گریز تمام ارقام مبنای شانزدهای را که پس از 'x' میآمدند مصرف میکرد و پایینترین ۸ بیت نتیجه را برمیداشت، بنابراین \x123456 معادل \x56 بود.
استثناهای AttributeError و NameError پیام خطای دوستانهتری دارند که متن آن چیزی شبیه به 'Spam' instance has no attribute 'eggs' یا name 'eggs' is not defined خواهد بود. پیشتر، پیام خطا فقط نام ویژگی مفقود eggs بود و کدی که با بهرهگیری از این واقعیت نوشتهشده باشد، در نسخهی 2.0 از کار خواهد افتاد.
کارهایی انجام شده است تا اعداد صحیح و اعداد صحیح بلند کمی بیشتر با هم قابل تعویض باشند. در نسخهی 1.5.2، پشتیبانی از پروندههای بزرگ برای سولاریس اضافه شد تا امکان خواندن پروندههای بزرگتر از ۲ گیبیبایت فراهم شود؛ این امر باعث شد متد tell() اشیاء پرونده بهجای عدد صحیح معمولی، عدد صحیح بلند برگرداند. برخی کدها دو آفست پرونده را از هم کم میکردند و تلاش میکردند از نتیجه برای ضرب یک دنباله یا اسلایس کردن یک رشته استفاده کنند، اما این کار باعث ایجاد TypeError میشد. در نسخهی 2.0، میتوان از اعداد صحیح بلند برای ضرب یا اسلایس کردن یک دنباله استفاده کرد و رفتار آن همان چیزی خواهد بود که بهطور شهودی انتظار دارید؛ 3L * 'abc' مقدار 'abcabcabc' را تولید میکند و (0,1,2,3)[2L:4L] مقدار (2,3) را تولید میکند. همچنین میتوان از اعداد صحیح بلند در زمینههای مختلفی که پیشتر تنها اعداد صحیح در آنها پذیرفته میشدند استفاده کرد؛ مانند متد seek() اشیاء پرونده و قالبهایی که عملگر % از آنها پشتیبانی میکند (%d، %i، %x و غیره). برای مثال، "%d" % 2L**64 رشتهی 18446744073709551616 را تولید خواهد کرد.
از میان همهی تغییرات اعداد صحیح بلند، ظریفترین آنها این است که str() یک عدد صحیح بلند دیگر نویسهی 'L' انتهایی ندارد، هرچند repr() همچنان آن را در بر میگیرد. نویسهی 'L' برای بسیاری از کسانی که میخواستند اعداد صحیح بلند را طوری چاپ کنند که دقیقاً مانند اعداد صحیح معمولی به نظر برسند، آزاردهنده بود، زیرا ناچار بودند زحمت اضافی بکشند تا آن نویسه را حذف کنند. این مشکل در 2.0 دیگر وجود ندارد، اما کدی که str(longval)[:-1] را انجام میدهد و فرض میکند 'L' وجود دارد، اکنون رقم آخر را از دست خواهد داد.
گرفتن repr() از یک عدد اعشاری اکنون از دقت قالببندی متفاوتی نسبت به str() استفاده میکند. repr() برای sprintf() در زبان C از رشته قالببندی %.17g استفاده میکند، در حالی که str() مانند قبل از %.12g استفاده میکند. نتیجه این است که repr() ممکن است برای برخی اعداد، گاهی ارقام اعشار بیشتری نسبت به str() نمایش دهد. برای مثال، عدد 8.1 را نمیتوان بهطور دقیق بهصورت دودویی نمایش داد، بنابراین repr(8.1) برابر '8.0999999999999996' است، در حالی که str(8.1) برابر '8.1' است.
گزینهی خط فرمان -X که تمام استثناهای استاندارد را بهجای کلاسها به رشته تبدیل میکرد، حذف شده است؛ استثناهای استاندارد از این پس همیشه کلاس خواهند بود. ماژول exceptions که شامل استثناهای استاندارد است، از پایتون به یک ماژول C توکار ترجمه شد که توسط بری وارساو و فردریک لوند نوشته شده است.
تغییرات توسعه/تعبیه¶
برخی از تغییرات در پسزمینهاند و تنها برای افرادی که ماژولهای توسعهای C مینویسند یا مفسر پایتون را در یک برنامهی بزرگتر تعبیه میکنند، آشکار خواهند بود. اگر با C API پایتون سروکار ندارید، میتوانید این بخش را با خیال راحت نادیده بگیرید.
شماره نسخهی API زبان C پایتون افزایش یافت، بنابراین افزونههای C که برای 1.5.2 کامپایل شدهاند باید مجدداً کامپایل شوند تا با 2.0 کار کنند. در ویندوز، به دلیل نحوهی کار DLLهای ویندوز، پایتون 2.0 نمیتواند افزونهی شخص ثالثی را که برای پایتون 1.5.x ساخته شده است ایمپورت کند، بنابراین پایتون یک استثنا ایجاد میکند و ایمپورت شکست میخورد.
کاربران ماژول ExtensionClass جیم فولتون خوشحال خواهند شد که بدانند قلابهایی اضافه شدهاند تا ExtensionClasses اکنون توسط isinstance() و issubclass() پشتیبانی شوند. این بدان معناست که دیگر لازم نیست به یاد داشته باشید کدی مانند if type(obj) == myExtensionClass بنویسید، بلکه میتوانید از if isinstance(obj, myExtensionClass) که طبیعیتر است، استفاده کنید.
پروندهی Python/importdl.c که تودهای از #ifdefs برای پشتیبانی از بارگذاری پویا در پلتفرمهای مختلف بود، توسط Greg Stein پاکسازی و بازآرایی شد. importdl.c اکنون بسیار کوچک است و کدهای خاص پلتفرم به تعدادی پروندهی Python/dynload_*.c منتقل شدهاند. پاکسازی دیگر: تعدادی پروندهی my*.h نیز در پوشهی Include/ وجود داشتند که حاوی ترفندهای گوناگون قابلیت حمل بودند؛ این پروندهها در یک پروندهی واحد، Include/pyport.h، ادغام شدهاند.
بازسازی malloc ولادیمیر مارانگوزوف که مدتها مورد انتظار بود، تکمیل شد تا بهسادگی بتوان مفسر پایتون را واداشت که بهجای malloc() استاندارد C از تخصیصدهنده سفارشی استفاده کند. برای مستندات، کامنتهای موجود در Include/pymem.h و Include/objimpl.h را بخوانید. برای مباحثات طولانیای که طی آنها این رابط شکل گرفت، به آرشیوهای وب فهرستهای 'patches' و 'python-dev' در python.org مراجعه کنید.
نسخههای اخیر محیط توسعه GUSI برای MacOS از نخهای POSIX پشتیبانی میکنند. بنابراین، پشتیبانی نخبندی POSIX پایتون اکنون روی Macintosh کار میکند. پشتیبانی نخبندی با استفاده از کتابخانه فضای کاربر GNU pth نیز مشارکت داده شد.
پشتیبانی از نخبندی در ویندوز نیز بهبود یافت. ویندوز از قفلهای نخ پشتیبانی میکند که تنها در صورت وجود تزاحم (contention) از اشیاء هسته استفاده میکنند؛ در حالت رایجی که تزاحمی وجود ندارد، این قفلها از توابع سادهتری استفاده میکنند که یک مرتبه بزرگی سریعتر هستند. نسخهی نخدار پایتون 1.5.2 روی NT دو برابر کندتر از نسخهی بدون نخ است؛ با تغییرات نسخهی 2.0، این تفاوت تنها ۱۰ درصد است. این بهبودها توسط یاکوف مارکوویچ ارائه شدهاند.
کد منبع Python 2.0 اکنون فقط از پیشنمونههای ANSI C استفاده میکند، بنابراین کامپایل کردن پایتون اکنون نیازمند کامپایلر ANSI C است و دیگر نمیتوان آن را با کامپایلری که فقط از K&R C پشتیبانی میکند انجام داد.
پیشتر، ماشین مجازی پایتون در بایتکد خود از اعداد ۱۶ بیتی استفاده میکرد که اندازهی پروندههای منبع را محدود میساخت. بهطور خاص، این موضوع بر حداکثر اندازهی فهرستها و دیکشنریهای لفظی در کد منبع پایتون تأثیر میگذاشت؛ گاهی اوقات افرادی که کد پایتون تولید میکردند به این محدودیت برمیخوردند. وصل چارلز جی. والدمن این محدودیت را از 2**16 به 2**32 افزایش میدهد.
سه تابع کمکی جدید برای افزودن ثابتها به دیکشنری یک ماژول در زمان مقداردهی اولیه ماژول اضافه شد: PyModule_AddObject()، PyModule_AddIntConstant() و PyModule_AddStringConstant(). هر یک از این توابع یک شیء ماژول، یک رشته C پایانیافته با نویسه تهی حاوی نامی که باید افزوده شود، و یک آرگومان سوم برای مقداری که باید به آن نام انتساب داده شود را میگیرد. این آرگومان سوم به ترتیب یک شیء پایتون، یک long از C یا یک رشته C است.
یک API پوششی برای هندلرهای سیگنال به سبک یونیکس اضافه شد. PyOS_getsig() یک هندلر سیگنال را دریافت میکند و PyOS_setsig() هندلر جدیدی را تنظیم میکند.
Distutils: آسان کردن نصب ماژولها¶
پیش از پایتون 2.0، نصب ماژولها کاری خستهکننده بود -- هیچ راهی وجود نداشت تا بهطور خودکار مشخص شود پایتون کجا نصب شده است، یا اینکه برای ماژولهای توسعهای باید از چه گزینههای کامپایلر استفاده کرد. نویسندگان نرمافزار ناچار بودند آیین طاقتفرسای ویرایش Makefileها و پروندههای پیکربندی را از سر بگذرانند؛ پروندههایی که در واقع تنها بر روی یونیکس کار میکنند و ویندوز و مکاواس را بدون پشتیبانی رها میکنند. کاربران پایتون با دستورالعملهای نصبی مواجه میشدند که بین بستههای توسعهای مختلف بهشدت متفاوت بودند؛ امری که مدیریت یک نصب پایتون را تا حدی به کاری پرزحمت تبدیل میکرد.
گروه علاقهمندی ویژه (SIG) برای ابزارهای توزیع، به سرپرستی گرگ وارد، Distutils را ایجاد کرده است؛ سیستمی که نصب بستهها را بسیار آسانتر میکند. این ابزارها بسته distutils را تشکیل میدهند که بخشی جدید از کتابخانه استاندارد پایتون است. در بهترین حالت، نصب یک ماژول پایتون از کد منبع به همان مراحل نیاز خواهد داشت: ابتدا شما بهسادگی بسته tar (tarball) یا آرشیو zip را استخراج میکنید و سپس «python setup.py install» را اجرا میکنید. پلتفرم بهطور خودکار تشخیص داده خواهد شد، کامپایلر شناسایی خواهد شد، ماژولهای توسعهای C کامپایل خواهند شد و توزیع در پوشه مناسب نصب خواهد شد. آرگومانهای اختیاری خط فرمان کنترل بیشتری بر فرایند نصب فراهم میکنند و بسته distutils جایگاههای بسیاری برای نادیده گرفتن مقادیر پیشفرض ارائه میدهد -- از جمله جداسازی ساخت از نصب، ساخت یا نصب در پوشههای غیرپیشفرض و موارد دیگر.
برای استفاده از Distutils، باید یک اسکریپت setup.py بنویسید. در حالت ساده که نرمافزار تنها شامل پروندههای .py است، یک setup.py حداقلی میتواند تنها چند سطر باشد:
from distutils.core import setup
setup (name = "foo", version = "1.0",
py_modules = ["module1", "module2"])
اگر نرمافزار از چند بسته تشکیل شده باشد، پروندهی setup.py بسیار پیچیدهتر نیست:
from distutils.core import setup
setup (name = "foo", version = "1.0",
packages = ["package", "package.subpackage"])
یک افزونه C میتواند پیچیدهترین حالت باشد؛ در اینجا مثالی برگرفته از بسته PyXML آورده شده است:
from distutils.core import setup, Extension
expat_extension = Extension('xml.parsers.pyexpat',
define_macros = [('XML_NS', None)],
include_dirs = [ 'extensions/expat/xmltok',
'extensions/expat/xmlparse' ],
sources = [ 'extensions/pyexpat.c',
'extensions/expat/xmltok/xmltok.c',
'extensions/expat/xmltok/xmlrole.c', ]
)
setup (name = "PyXML", version = "0.5.4",
ext_modules =[ expat_extension ] )
Distutils همچنین میتواند ایجاد توزیعهای منبع و دودویی را بر عهده بگیرد. دستور «sdist» که با «python setup.py sdist» اجرا میشود، یک توزیع منبع مانند foo-1.0.tar.gz میسازد. افزودن دستورهای جدید دشوار نیست؛ دستورهای «bdist_rpm» و «bdist_wininst» بهترتیب برای ایجاد یک توزیع RPM و یک نصبکننده ویندوز برای نرمافزار، پیشتر اهدا شدهاند. دستورهایی برای ایجاد قالبهای توزیع دیگر مانند بستههای دبیان و پروندههای .pkg سولاریس، در مراحل مختلف توسعه قرار دارند.
همه این موارد در راهنمای جدیدی با عنوان توزیع ماژولهای پایتون که به مجموعه پایه مستندات پایتون میپیوندد، مستند شدهاند.
ماژولهای XML¶
پایتون 1.5.2 یک پارسر XML ساده در قالب ماژول xmllib در بر داشت که توسط Sjoerd Mullender ارائه شده بود. از زمان انتشار نسخهی 1.5.2، دو رابط متفاوت برای پردازش XML رایج شدهاند: SAX2 (نسخهی 2 از API ساده برای XML) رابطی مبتنی بر رویداد ارائه میدهد که شباهتهایی به xmllib دارد، و DOM (مدل شیء سند) رابطی مبتنی بر درخت ارائه میدهد که سند XML را به درختی از گرهها تبدیل میکند که میتوان آنها را پیمایش کرد و تغییر داد. پایتون 2.0 یک رابط SAX2 و یک رابط DOM سادهشده را بهعنوان بخشی از بستهی xml در بر دارد. در اینجا مروری کوتاه بر این رابطهای جدید ارائه خواهیم کرد؛ برای جزئیات کامل به مستندات پایتون یا کد منبع مراجعه کنید. Python XML SIG نیز در حال کار روی بهبود مستندات است.
پشتیبانی از SAX2¶
SAX یک رابط رویدادمحور برای تجزیهی XML تعریف میکند. برای استفاده از SAX، باید یک کلاس هندلر SAX بنویسید. کلاسهای هندلر از کلاسهای گوناگونی که SAX فراهم میکند به ارث میبرند و متدهای مختلفی را بازنویسی میکنند که سپس توسط پارسر XML فراخوانی خواهند شد. برای مثال، متدهای startElement() و endElement() برای هر تگ آغازین و تگ پایانی که پارسر با آن مواجه میشود فراخوانی میشوند، متد characters() برای هر بخش از دادههای نویسهای فراخوانی میشود، و غیره.
مزیت رویکرد رویدادمحور این است که کل سند لازم نیست در هیچ لحظهای در حافظه مقیم باشد، که این موضوع هنگام پردازش اسناد واقعاً عظیم اهمیت دارد. با این حال، اگر بخواهید ساختار سند را به شکلی مفصل تغییر دهید، نوشتن کلاس هندلر SAX میتواند بسیار پیچیده شود.
برای مثال، این برنامهی نمونهی کوچک یک هندلر تعریف میکند که برای هر برچسب آغاز و پایان یک پیام چاپ میکند، و سپس پروندهی hamlet.xml را با استفاده از آن تجزیه میکند:
from xml import sax
class SimpleHandler(sax.ContentHandler):
def startElement(self, name, attrs):
print 'Start of element:', name, attrs.keys()
def endElement(self, name):
print 'End of element:', name
# Create a parser object
parser = sax.make_parser()
# Tell it what handler to use
handler = SimpleHandler()
parser.setContentHandler( handler )
# Parse a file!
parser.parse( 'hamlet.xml' )
برای اطلاعات بیشتر، به مستندات پایتون یا راهنمای عملی XML در https://pyxml.sourceforge.net/topics/howto/xml-howto.html مراجعه کنید.
پشتیبانی از DOM¶
مدل شیء سند (DOM) نمایشی مبتنی بر درخت برای یک سند XML است. یک نمونهی Document در سطح بالا ریشهی درخت است و تنها یک فرزند دارد که همان نمونهی Element در سطح بالاست. این Element گرههای فرزندی دارد که دادههای نویسهای و هر زیرالمانی را نشان میدهند؛ این گرهها نیز ممکن است خود فرزندان بیشتری داشته باشند و به همین ترتیب. با استفاده از DOM میتوانید درخت حاصل را به هر روشی که بخواهید پیمایش کنید، به مقادیر المانها و ویژگیها دسترسی داشته باشید، گرهها را درج و حذف کنید و درخت را دوباره به XML تبدیل کنید.
DOM برای تغییر اسناد XML مفید است، زیرا میتوانید یک درخت DOM بسازید، آن را با افزودن گرههای جدید یا بازآرایی زیردرختها تغییر دهید و سپس یک سند XML جدید بهعنوان خروجی تولید کنید. همچنین میتوانید یک درخت DOM را بهصورت دستی بسازید و آن را به XML تبدیل کنید، که میتواند راهی انعطافپذیرتر برای تولید خروجی XML نسبت به صرفاً نوشتن <tag1>...</tag1> در یک پرونده باشد.
پیادهسازی DOM که همراه پایتون ارائه میشود، در ماژول xml.dom.minidom قرار دارد. این یک پیادهسازی سبکوزن از DOM Level 1 با پشتیبانی از فضاهای نام XML است. توابع کمکی parse() و parseString() برای تولید درخت DOM فراهم شدهاند:
from xml.dom import minidom
doc = minidom.parse('hamlet.xml')
doc یک نمونه از Document است. Document همانند تمام کلاسهای دیگر DOM نظیر Element و Text، زیرکلاسی از کلاس پایهی Node است. بنابراین تمام گرههای یک درخت DOM از تعدادی متد مشترک پشتیبانی میکنند، مانند toxml() که رشتهای حاوی بازنمایی XML گره و فرزندانش را برمیگرداند. هر کلاس همچنین متدهای ویژه خود را دارد؛ برای مثال، نمونههای Element و Document متدی دارند که تمام عناصر فرزند با نام تگ مشخص را پیدا میکند. ادامه از مثال ۲ سطری قبلی:
perslist = doc.getElementsByTagName( 'PERSONA' )
print perslist[0].toxml()
print perslist[1].toxml()
برای پروندهی XML هملت، چند سطر بالا خروجی زیر را تولید میکنند:
<PERSONA>CLAUDIUS, king of Denmark. </PERSONA>
<PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA>
عنصر ریشهی سند بهصورت doc.documentElement در دسترس است و میتوان فرزندان آن را با حذف، افزودن یا جدا کردن گرهها بهسادگی تغییر داد:
root = doc.documentElement
# Remove the first child
root.removeChild( root.childNodes[0] )
# Move the new first child to the end
root.appendChild( root.childNodes[0] )
# Insert the new first child (originally,
# the third child) before the 20th child.
root.insertBefore( root.childNodes[0], root.childNodes[20] )
دوباره، برای فهرست کامل کلاسهای مختلف Node و متدهای گوناگون آنها، شما را به مستندات پایتون ارجاع میدهم.
رابطه با PyXML¶
گروه علاقهمندی ویژهی XML (SIG) مدتی است که روی کدهای پایتونی مرتبط با XML کار میکند. توزیع کد آن، که PyXML نام دارد، در صفحات وب SIG به آدرس https://www.python.org/community/sigs/current/xml-sig در دسترس است. توزیع PyXML نیز از نام بستهی xml استفاده میکرد. اگر برنامههایی نوشتهاید که از PyXML استفاده میکردند، احتمالاً در مورد سازگاری آن با بستهی xml نسخهی 2.0 سؤال دارید.
پاسخ این است که بستهی xml پایتون 2.0 با PyXML سازگار نیست، اما با نصب نسخهی جدید PyXML میتوان آن را سازگار کرد. بسیاری از برنامهها میتوانند با پشتیبانی XML گنجاندهشده در پایتون 2.0 بسنده کنند، اما برنامههای پیچیدهتر به نصب بستهی کامل PyXML نیاز خواهند داشت. پس از نصب، نسخههای 0.6.0 یا بالاترِ PyXML جایگزین بستهی xml همراه پایتون میشوند و ابرمجموعهی اکیدی از بستهی استاندارد به شمار میروند که تعدادی قابلیت اضافی نیز به آن میافزایند. برخی از قابلیتهای اضافی PyXML عبارتاند از:
4DOM، یک پیادهسازی کامل DOM از شرکت FourThought, Inc.
پارسر اعتبارسنج xmlproc، نوشتهی لارس ماریوس گارشول.
ماژول شتابدهندهی پارسر
sgmlop، نوشتهشده توسط Fredrik Lundh.
تغییرات ماژولها¶
بهبودها و رفع اشکالهای فراوانی در کتابخانه استاندارد گستردهی پایتون انجام شد؛ برخی از ماژولهای متأثر عبارتاند از readline، ConfigParser، cgi، calendar، posix، readline، xmllib، aifc، chunk، wave، random، shelve و nntplib. برای جزئیات دقیق وصل به وصل، به گزارشهای CVS مراجعه کنید.
Brian Gallew پشتیبانی OpenSSL را برای ماژول socket فراهم کرد. OpenSSL یک پیادهسازی از لایه سوکت امن (Secure Socket Layer) است که دادههای ارسالشده از طریق یک سوکت را رمزگذاری میکند. هنگام کامپایل پایتون، میتوانید Modules/Setup را ویرایش کنید تا پشتیبانی از SSL در آن گنجانده شود؛ این کار تابعی اضافی به ماژول socket میافزاید: socket.ssl(socket, keyfile, certfile) که یک شیء سوکت میگیرد و یک سوکت SSL برمیگرداند. ماژولهای httplib و urllib نیز تغییر کردند تا از نشانیهای https:// پشتیبانی کنند، هرچند هیچکس FTP یا SMTP را روی SSL پیادهسازی نکرده است.
ماژول httplib توسط گرگ استاین بازنویسی شده است تا از HTTP/1.1 پشتیبانی کند.
سازگاری با نسخهی 1.5 از httplib فراهمشده است، هرچند استفاده از قابلیتهای HTTP/1.1 مانند پایپلاین (pipelining) نیازمند بازنویسی کد برای استفاده از مجموعهای متفاوت از رابطها خواهد بود.
ماژول Tkinter اکنون از Tcl/Tk نسخههای 8.1، 8.2 یا 8.3 پشتیبانی میکند و پشتیبانی از نسخههای قدیمیتر 7.x حذف شده است. ماژول Tkinter اکنون از نمایش رشتههای یونیکد در ابزارکهای Tk پشتیبانی میکند. همچنین، Fredrik Lundh یک بهینهسازی ارائه کرده است که عملیاتی مانند create_line و create_polygon را بسیار سریعتر میکند، بهویژه هنگام استفاده از تعداد زیادی مختصات.
ماژول curses با آغاز از نسخه بهبودیافته Oliver Andrich، بهطور چشمگیری توسعه یافته است تا توابع اضافی بسیاری از ncurses و SYSV curses مانند رنگ، پشتیبانی از مجموعه نویسههای جایگزین، پدها (pads) و پشتیبانی از ماوس را فراهم کند. این بدان معناست که این ماژول دیگر با سیستمعاملهایی که فقط BSD curses دارند سازگار نیست، اما به نظر نمیرسد هیچ سیستمعاملی که در حال حاضر نگهداری میشود در این دسته قرار داشته باشد.
همانطور که در بحث پیشین دربارهی پشتیبانی یونیکد در 2.0 اشاره شد، پیادهسازی زیربنایی عبارتهای باقاعدهای که ماژول re ارائه میدهد، تغییر کرده است. SRE، موتور جدید عبارت باقاعده که Fredrik Lundh آن را نوشته و تا حدی توسط Hewlett Packard تأمین مالی شده است، از تطبیق با هم رشتههای ۸-بیتی و هم رشتههای یونیکد پشتیبانی میکند.
ماژولهای جدید¶
تعدادی ماژول جدید افزوده شدند. ما آنها را صرفاً با توضیحات مختصر فهرست میکنیم؛ برای جزئیات یک ماژول خاص، به مستندات 2.0 مراجعه کنید.
atexit: برای ثبت توابعی که باید پیش از خروج مفسر پایتون فراخوانی شوند. کدی که در حال حاضرsys.exitfuncرا مستقیماً تنظیم میکند، باید تغییر کند تا به جای آن از ماژولatexitاستفاده کند؛ به این صورت کهatexitرا ایمپورت کرده وatexit.register()را بههمراه تابعی که باید هنگام خروج فراخوانی شود، فراخوانی میکند. (با مشارکت Skip Montanaro.)codecs،encodings،unicodedata: به عنوان بخشی از پشتیبانی جدید یونیکد افزوده شدند.filecmp: جایگزین ماژولهای قدیمیcmp،cmpcacheوdircmpشده است که اکنون منسوخ شدهاند. (ارائهشده توسط Gordon MacMillan و Moshe Zadka.)gettext: این ماژول با ارائهی رابطی به کتابخانه کاتالوگ پیام GNU gettext، پشتیبانی از بینالمللیسازی (I18N) و بومیسازی (L10N) را برای برنامههای پایتون فراهم میکند. (یکپارچهشده توسط Barry Warsaw، از مشارکتهای جداگانهی Martin von Löwis، Peter Funk و James Henstridge.)linuxaudiodev: پشتیبانی از دستگاه/dev/audioدر لینوکس، همتای ماژول موجودsunaudiodev. (ارائهشده توسط Peter Bosch، با اصلاحاتی از Jeremy Hylton.)mmap: رابطی برای پروندههای نگاشتشده به حافظه، هم در Windows و هم در Unix. محتوای یک پرونده میتواند مستقیماً به حافظه نگاشت شود؛ در این حالت، پرونده مانند یک رشته تغییرپذیر رفتار میکند و در نتیجه میتوان محتوای آن را خواند و تغییر داد. حتی میتوان آنها را به توابعی که انتظار رشتههای معمولی را دارند ارسال کرد، مانند ماژولre. (مشارکت Sam Rushing، با برخی توسعهها از سوی A.M. Kuchling.)pyexpat: رابطی برای پارسر XML اکسپت (Expat). (مشارکتشده توسط Paul Prescod.)robotparser: تجزیهی یک پروندهیrobots.txtکه برای نوشتن خزندههای وبی که مؤدبانه از بخشهای خاصی از یک وبسایت اجتناب میکنند، استفاده میشود. پارسر محتویات یک پروندهیrobots.txtرا میپذیرد، از آن مجموعهای از قواعد میسازد و سپس میتواند به پرسشهایی دربارهی دریافتپذیری (fetchability) یک URL مشخص پاسخ دهد. (ارائهشده توسط Skip Montanaro.)tabnanny: ماژول/اسکریپتی برای بررسی تورفتگیهای مبهم در کد منبع پایتون. (ارائهشده توسط Tim Peters.)UserString: کلاس پایهای که برای مشتقگیری اشیایی که مانند رشتهها رفتار میکنند، مفید است.webbrowser: ماژولی که راهی مستقل از پلتفرم برای راهاندازی مرورگر وب روی یک URL مشخص فراهم میکند. برای هر پلتفرم، مرورگرهای مختلف به ترتیب مشخصی امتحان میشوند. کاربر میتواند با تنظیم متغیر محیطی BROWSER تعیین کند که کدام مرورگر راهاندازی شود. (در ابتدا از وصل اریک اس. ریموند بهurllibالهام گرفته شد که قابلیتی مشابه اضافه کرده بود، اما ماژول نهایی از کدی میآید که در اصل توسط فرد دریک درTools/idle/BrowserControl.pyپیادهسازی شده بود و توسط فرد برای کتابخانه استاندارد تطبیق داده شد.)_winreg: رابطی برای رجیستری ویندوز._winregاقتباسی از توابعی است که از سال ۱۹۹۵ بخشی از PythonWin بودهاند، اما اکنون به توزیع اصلی افزوده شده و برای پشتیبانی از یونیکد بهبود یافته است._winregتوسط Bill Tutt و Mark Hammond نوشته شده است.zipfile: ماژولی برای خواندن و نوشتن آرشیوهای با قالب ZIP. اینها آرشیوهایی هستند که توسط PKZIP در DOS/Windows یا zip در یونیکس تولید میشوند و نباید با پروندههای با قالب gzip(که توسط ماژولgzipپشتیبانی میشوند) اشتباه گرفته شوند (ارائهشده توسط James C. Ahlstrom.)imputil: ماژولی که در مقایسه با ماژول موجودihooks، روشی سادهتر برای نوشتن قلابهای ایمپورت سفارشی فراهم میکند. (پیادهسازیشده توسط گرگ استاین، همراه با بحثهای فراوان در python-dev در طول مسیر.)
بهبودهای IDLE¶
IDLE محیط توسعه یکپارچه (IDE) رسمی و چندسکویی پایتون است که با استفاده از Tkinter نوشته شده است. پایتون 2.0 شامل IDLE 0.6 است که تعدادی قابلیت و بهبود جدید میافزاید. فهرستی ناقص:
بهبودها و بهینهسازیهای رابط کاربری، بهویژه در حوزهی برجستهسازی سینتکس و تورفتگی خودکار.
مرورگر کلاس اکنون اطلاعات بیشتری، مانند توابع سطح بالا در یک ماژول، نمایش میدهد.
عرض تب اکنون گزینهای است که کاربر میتواند آن را تنظیم کند. هنگام باز کردن یک پرونده پایتون موجود، IDLE بهطور خودکار قراردادهای تورفتگی را تشخیص میدهد و خود را با آنها وفق میدهد.
اکنون پشتیبانی از فراخوانی مرورگرها در پلتفرمهای گوناگون وجود دارد که برای باز کردن مستندات پایتون در مرورگر استفاده میشود.
IDLE اکنون خط فرمانی دارد که تا حدود زیادی مشابه مفسر معمولی (vanilla) پایتون است.
نکتههای فراخوانی (call tips) در بسیاری از مکانها افزوده شدند.
اکنون میتوان IDLE را بهصورت یک بسته نصب کرد.
در پنجرهی ویرایشگر، اکنون یک نوار سطر/ستون در پایین وجود دارد.
سه فرمان کلیدزنی جدید: بررسی ماژول (Alt-F5)، ایمپورت ماژول (F5) و اجرای اسکریپت (Ctrl-F5).
ماژولهای حذفشده و منسوخ¶
چند ماژول به دلیل منسوخ شدن یا وجود راههای بهتر برای انجام همان کار، حذف شدهاند. ماژول stdwin دیگر وجود ندارد؛ این ماژول برای یک مجموعه ابزار پنجرهسازی مستقل از پلتفرم بود که دیگر توسعه داده نمیشود.
تعدادی از ماژولها به زیرپوشهی lib-old منتقل شدهاند: cmp، cmpcache، dircmp، dump، find، grep، packmail، poly، util، whatsound، zmod. اگر کدی دارید که به ماژولی وابسته است که به lib-old منتقل شده، میتوانید برای بازگرداندن آنها، آن پوشه را به سادگی به sys.path اضافه کنید، اما توصیه میشود هر کدی را که از این ماژولها استفاده میکند بهروزرسانی کنید.
قدردانیها¶
نویسندگان مایلاند از افراد زیر برای ارائهی پیشنهادها دربارهی پیشنویسهای مختلف این مقاله تشکر کنند: David Bolen، Mark Hammond، Gregg Hauser، Jeremy Hylton، Fredrik Lundh، Detlef Lannert، Aahz Maruch، Skip Montanaro، Vladimir Marangozov، Tobias Polzin، Guido van Rossum، Neil Schemenauer و Russ Schmidt.