به نام خدا.

سلام.
دیشب که تا صبح خوابم نمیبرد، به سرم زد که:
من که خوابم نمیبره، بزار یه برنامه کوتاه بنویسم که یه «چند جمله ای» رو براش تایپ میکنی و بعد بهش میگی این چند جمله ای رو برام با فلان عدد 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 "0123456789^.": variable = self._terms[i][j] break return variable def get_variable(self): return self._variable def _ops_info(self): """ 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. """ ops_info = [] for i in range(len(self._parts)): if self._parts[i] in "+-": 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 "+-": 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 "^" 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("* Polynomial with 'num':", ' '.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 استفاده کنیم، یه راه اینه که کُد زیر رو آخرِ همون کُدِ اصلی وارد کنیم:
print('Samaleik.') inp = input("Chand jomlei ro vared kon: ") polynomial = Polynomial(inp) adad = input("Bejaye {} che adadi bezarim? ".format(polynomial.get_variable())) print('============================') print(polynomial) print('============================') print('Inam az javab:', polynomial.evaluate(adad))
نتیجه کار رو هم یه بار دیگه با چند تا مثال، میبینیم:
Samaleik. Chand jomlei ro vared kon: x^2 + 3x - 4 Bejaye x che adadi bezarim? 1 ============================ Motaghayer: x Daraje: 2 ============================ Inam az javab: 0
Samaleik. Chand jomlei ro vared kon: s^6 - 3s^3 - 4 Bejaye s che adadi bezarim? 3 ============================ Motaghayer: s Daraje: 6 ============================ Inam az javab: 644
Samaleik. 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@ استفاده کنید.