دیوانه بازی با برنامه نویسی: چطور با پایتون تا صبح بیدار بمانیم؟

به نام خدا.سلام.دیشب که تا صبح خوابم نمیبرد، به سرم زد که:من که خوابم نمیبره، بزار یه برنامه کوتاه بنویسم که یه «چند جمله ای» رو براش تایپ میکنی و بعد بهش میگی این چند جمله ای رو برام با فلان عدد evaluate کن.این یعنی چه حالا؟ نگران نباش همون ساده کردن و جاگذاریه که همه بلدن. یعنی اینکه مثلاً به کامپیوتر میگی چند جمله ایِ من میشه «x^2 + 3x - 4» و بهم بگو که اگه به جای x یه عددی بزاریم، حاصلِ چند جمله ای چند میشه؟بزار بصورت کُد هم یه مثال بزنیم:Chand jomlei ro vared kon: x^2 + 3x - 4 Bejaye x che adadi bezarim? 1 Inam az javab: 0اول بهش چند جمله ای رو دادیم، بعد بهش گفتیم به جای x بزار 1 و اون هم جواب رو به ما میده.یه نکته: شاید خیلی ها بگن خب همه این کارها و خیلی کارهای دیگه رو هم با یه library یا module میشه به راحتی انجام داد دیگه. اینم حرف درستیه. ولی از اونجایی که من خوابم نمیبرد و قطعاً به چیزی برای گذراندنِ وقت محتاج بودم، تصمیم گرفتم که این کار رو بدون استفاده از هیچ library و module خاصی انجام بدم. یعنی خودم چیزی که user وارد کرده رو parse کنم و غیره. البته تنها جایی که یه ذره تنبلی کردم استفاده از ()eval و deepcopy بود که اگه میخواستم اونها رو هم خودم implement کنم احتمالاً تا هفته آینده باید نمیخوابیدم.خب من اونقدرها نمیتانم بیدار بمانم!حالا چکار کردم؟اول کُد رو ببینید، بعدش یه توضیح کوتاه میدم:from copy import deepcopy class Polynomial: def __init__(self, input_str): self._parts = input_str.split() self._terms = self._terms() self._variable = self._variable() self._degree = self._degree() def _variable(self): variable = None for i in range(len(self._terms)): for j in range(len(self._terms[i])): if self._terms[i][j] not in &quot0123456789^.&quot: variable = self._terms[i][j] break return variable def get_variable(self): return self._variable def _ops_info(self): &quot&quot&quot Operations in the polynomial and their info. Not necessary because we used the lovely 'eval' in evaluate method! But I have kept this just for fun. &quot&quot&quot ops_info = [] for i in range(len(self._parts)): if self._parts[i] in &quot+-&quot: ops_info.append({ 'op': self._parts[i], 'info': { 'index': i, 'prev_next': { 'prev': {'index': i - 1, 'term': self._parts[i - 1]}, 'next': {'index': i + 1, 'term': self._parts[i + 1]}} } }) return ops_info def _terms(self): terms = [] for i in range(len(self._parts)): if self._parts[i] not in &quot+-&quot: terms.append(self._parts[i]) # print('* _terms():', terms) # Test return terms def _degree(self): term_degrees = {} for i in range(len(self._terms)): if '^' in self._terms[i]: term_degrees[i] = { 'term': self._terms[i], 'index': i, 'degree': self._terms[i][self._terms[i].index('^') + 1:] } elif self._variable in self._terms[i]: term_degrees[i] = { 'term': self._terms[i], 'index': i, 'degree': 1 } else: term_degrees[i] = { 'term': self._terms[i], 'index': i, 'degree': 0 } degrees = [] for term_info in term_degrees.values(): degrees.append(int(term_info['degree'])) return (max(degrees)) def _prepare_terms(self): # Replace '^' with '**' and put '*' between variable and numbers. prepared = deepcopy(self._parts) for i in range(len(prepared)): if &quot^&quot in prepared[i]: for j in range(len(prepared[i])): if prepared[i][j] == '^': prepared[i] = prepared[i][:j] + '**' + prepared[i][j+1:] elif self._variable in prepared[i]: for j in range(len(prepared[i])): if prepared[i][j] == self._variable: if len(prepared[i]) > 1: prepared[i] = prepared[i][:j] + '*' + prepared[i][j:] # print('* Prepared:', prepared) # Test return prepared def evaluate(self, num): polynomial = self._prepare_terms() # Replace x's with 'num'. for i in range(len(polynomial)): if self._variable in polynomial[i]: for j in range(len(polynomial[i])): if polynomial[i][j] == self._variable: polynomial[i] = polynomial[i][:j] + ('*' if (polynomial[i][j-1] not in '*-+' and j != 0) else '') + num + polynomial[i][j+1:] # print(&quot* Polynomial with 'num':&quot, ' '.join(polynomial)) # Test return eval(' '.join(polynomial)) def __str__(self): return ( 'Motaghayer: {}\n'.format(self._variable) + 'Daraje: {}'.format(self._degree) )حالا چکار میکنه این کُد؟کل این دیوانه بازی رو به وسیله یه class انجام دادم و اسمش رو هم گذاشتم Polynomial. توی این class هم یه سری method هست که internal هست و قرار نیست call بشه از بیرون. فقط دو تا method هستن که قراره call بشن و اونم evaluate و get_variable هست که اولی قراره جوابی که میخوایم رو به ما بده و دومی هم برای تست کردن و پُز دادن به درد میخوره! (آخرِ مقاله میبینی کجا ازش استفاده شده).کُلِ class داره یه چند جمله ای رو مدل سازی میکنه.این چند جمله ایِ ما تشکیل شده از یه سری term یا جمله و یه درجه ای داره و متغیرش رو هم از همون اول تعیین میکنیم. یه instance variable دیگه هم به اسم parts_ داریم که جاهای دیگه استفاده میشه.وظیفه متُدِ variable_ اینه که متغیر رو پیدا کنه. این باعث میشه که ما بتانیم علاوه بر x از هر حرف دیگه ای به عنوان متغیر استفاده کنیم. از این متغیر توی جاهای دیگه استفاده میشه.وظیفه متُد get_variable هم که اینه که متغیر رو به ما بده، که ما مستقیماً با instance variable روبرو نشیم (به دلایل بسیار امنیتی که جان میلیون ها نفر هم بهش بستگی داره!).وظیفه متُدِ ops_info_ اینه که یه سری اطلاعات راجب operation هایی که توی چند جمله ای هست، به ما میده. البته من چون از eval استفاده کردم، دیگه نیازی به این متُد نبود. همینطور برای fun نگهش داشتم.وظیفه متُدِ terms_ اینه که جمله های اون چند حمله ای رو تعیین کنه. از این هم توی جاهای دیگه استفاده میشه.وظیفه متُدِ degree_ هم اینه که درجه چند جمله ای رو مشخص کنه. مثلاً x^2 - 3x + 3 میشه درجه ۲ و x^2 - 4x^5 + 6 میشه درجه ۵. اینم بیشتر جنبه وقت کُشی و fun داشت.وظیفه متُد prepare_terms_ هم اینه که اوضاع رو برای eval قراهم کنه. ازش توی متُد اصلیِ ما یعنی evaluate استفاده میشه.متُد evaluate هم که تنها متُدیه که قراره از بیرون call بشه و جوابی که میخوایم رو به ما میده.اون متُد __str__ هم برای اینه که وقتی user یه instance از Polynomial رو به print تحویل داد، یه جورایی یه سری اطلاعاتِ دلخواه رو به user نشان بدیم.مثال برای استفاده از این classحالا اگه بخوایم از این class استفاده کنیم، یه راه اینه که کُد زیر رو آخرِ همون کُدِ اصلی وارد کنیم:print('Samaleik.') inp = input(&quotChand jomlei ro vared kon: &quot) polynomial = Polynomial(inp) adad = input(&quotBejaye {} che adadi bezarim? &quot.format(polynomial.get_variable())) print('============================') print(polynomial) print('============================') print('Inam az javab:', polynomial.evaluate(adad))به عنوانِ ورودی، چند جمله ای رو از user میگیریم.بعد یه Polynomial میسازیم با استفاده از اون و اسمش رو هم میزاریم polynomial.بعد میپرسیم که به جای متغیر چه عددی بزاریم.و در آخر هم جواب میدیم.نتیجه کار رو هم یه بار دیگه با چند تا مثال، میبینیم:Samaleik. Chand jomlei ro vared kon: x^2 + 3x - 4 Bejaye x che adadi bezarim? 1 ============================ Motaghayer: x Daraje: 2 ============================ Inam az javab: 0Samaleik. Chand jomlei ro vared kon: s^6 - 3s^3 - 4 Bejaye s che adadi bezarim? 3 ============================ Motaghayer: s Daraje: 6 ============================ Inam az javab: 644Samaleik. Chand jomlei ro vared kon: -z^2 + 3z^4 - 2z + 1 Bejaye z che adadi bezarim? 2 ============================ Motaghayer: z Daraje: 4 ============================ Inam az javab: 41حرف آخرخدا رو شکر نوشتنِ این کُد یه ۳ ساعتی از وقت رو کُشت و من هم با موفقیت شب رو صبح کردم. دیوانه بازیِ باحالی هم بود.با توجه به میزان وقتی که داشتم تلاش کردم که درست کار کنه، ولی شما امتحانش کنید اگه باگ هم داشت، خودتان برطرف کنید. شاید تمرین خوبی هم باشه.قسمتِ باحالِ ماجرا هم اینه که این کُد بصورتِ عمدی یه سری مشکلات داره:یعنی چه؟ یعنی برای همه چند جمله ای ها کار نمیکنه. مثلاً سعی کنید بهش x + 3- بدید. یا مثلاً x^3 + 2- بهش بدید.یه تمرین برای شما اینه که جوری تغییرش بدین که برای اینها هم کار کنه. کارِ سختی نیست اصلاً، سعی کنید انجامش بدید.اینجور تمرین ها که اول باید سعی کنید کُد رو بفهمید و بعد هم تغییرش بدید و یا چیزی بهش اضافه کنید، خیلی کمک میکنه به یادگیری و مهارت پیدا کردن. یعنی درواقع برنامه نویسی یعنی همین دیگه!توی مقاله بعدی میخوام به این class یه متُد اضافه کنم که مُشتقِ اولِ چند جمله ای رو به ما بده. اولش باید ببینم کِی بی خوابی میگیرم دوباره!مخلص، یا علی.برای ارتباط با من میتانید از آدرس ایمیل odiwxe@gmail.com یا از ID تلگرام solyinho@ استفاده کنید.