ثبت نام


حتماً دیده‌اید که در بخش عضویت بسیاری از وب‌سایت‌ها برای امنیت بیشتر محدودیت‌هایی بر روی نام کاربری و گذرواژه وجود دارد.

می‌خواهیم با پایتون ۳ تابعی بنویسیم که تعدادی نام کاربری و گذرواژه دریافت کند و بر اساس قواعدی معتبر بودن آن‌ها را بررسی کند و در نهایت لیست نام‌های کاربری مجاز به عضویت را برگرداند.

جزئیات🔗

قواعد زیر را برای نام کاربری و گذرواژه در نظر گرفته‌ایم:

  • نام‌های کاربری quera و codecup را می‌خواهیم برای خودمان نگه داریم. کسی مجاز به عضویت با این نام‌های کاربری نیست.
  • نام کاربری کمتر از ۴ حرف بسیار کوتاه است و مجاز نیست.
  • همچنین برای امنیت کاربران، کاربری که رمز عبور او کمتر از ۶ حرف باشد یا فقط از اعداد تشکیل شده‌باشد نیز مجاز به عضویت نیست.

تابعی با نام check_registration_rules بنویسید که نام کاربری و گذرواژه‌ی تعدادی کاربر را مانند نمونه‌ی زیر دریافت کند و در خروجی لیستی از نام‌های کاربری مجاز به عضویت را برگرداند. ترتیب اعضای لیست خروجی اهمیت ندارد.

>>> check_registration_rules(username='password', sadegh='He3@lsa', quera='kLS45@l$')
['username', 'sadegh']

>>> check_registration_rules(saeed='1234567', ab='afj$L12')
[]
Python

نکات🔗

  • یک فایل Zip شامل یک فایل به نام ‍source.py که تابع check_registration_rules در آن قرار دارد آپلود کنید.
  • نام فایل Zip اهمیت ندارد.

دیجی کالا


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

کد پروژه را می‌توانید از این لینک دریافت کنید.

داخل پروژه ۲ فایل پایتون با نام‌های models.py و store.py است. شما باید توابع ناقص فایل store.py را تکمیل کنید.

جزئیات پروژه🔗

داخل کلاس Store چند تابع وجود دارد که نیاز به تکمیل دارند. همچنین object آن دارای کالاهای موجود و کاربران ثبت نام شده‌است. کالاها به صورت dictonary ذخیره شده‌اند که هر key آن یک کالا(Product) است و هر ‍‍value آن تعداد موجودی آن کالاست. کاربران هم به صورت list ذخیره شده‌اند.

وظیفه‌ی شما این است که توابع زیر را برای کلاس Store پیاده‌سازی کنید.

  • تابع remove_product این تابع وظیفه‌ی حذف کالا از فروشگاه را دارد.در صورت موجود نبود این تعداد کالا، استثایی با پیام ‍‍Not Enough Products پرتاب شود و هیچ کالایی از فروشگاه حذف نشود. در صورتی که موجودی یک کالا به صفر برسد باید از دیکشنری کالاها حذف شود.
  • تابع add_user این تابع یک کاربر را به کاربران اضافه می‌کند. در صورتی که نام کاربری تکراری باشد کاربری اضافه نمی‌کند و مقدار None بر می‌گرداند؛ در غیر این صورت، رشته‌ی نام کاربری آن کاربر را برمی‌گرداند.
  • تابع get_total_asset این تابع جمع کل دارایی‌های فروشگاه را برمی‌گرداند (دارایی فروشگاه برابر مجموع قیمت کالاهای موجود است.)
  • تابع get_total_profit این تابع مقدار سودی که فروشگاه کرده‌است را برمی‌گرداند. مقدار سود فروشگاه برابر جمع قیمت کالاهای فروخته‌شده است. ( تعداد هریک از کالاهای لیست bought_products در کلاس User یک است.)
  • تابع get_comments_by_user این تابع لیست متن نظراتی که یک کاربر خاص روی محصولات موجود در فروشگاه گذاشته‌است را بر می‌گرداند (ترتیب آن‌ها مهم نیست)
  • تابع get_inflation_affected_product_names این تابع لیستی از نام کالاهایی که تورم روی آن‌ها تاثیر گذاشته‌است را برمی‌گرداند. (تورم روی کالاهایی اثر گذاشته‌است که کالایی هم اسم آن‌ها ولی با قیمت کمتر داخل فروشگاه وجود داشته‌باشد). توجه کنید که اگر چند قیمت از یک کالا موجود باشد، نام آن فقط یک بار باید در لیست بیاید. ترتیب اعضای لیست اهمیتی ندارد.
  • تابع clean_old_comments این تابع ورودی یک تاریخ از نوع datetime می‌گیرد و همه‌ی نظراتی که قبل از آن تاریخ روی پست‌ها گذاشته شده‌اند را حذف می‌کند.
  • تابع get_comments_by_bought_users این تابع لیستی از متن نظراتی را بر می‌گرداند که صاحب آن، کالا را خریداری کرده‌است.

نکات🔗

  • توجه کنید که ممکن است از یک کالا چند عدد موجود باشد.
  • شما تنها مجاز به تغییر فایل store.py هستید.

آنچه باید آپلود کنید:🔗

  • یک فایل Zip شامل یک فایل به نام ‍store.py که کلاس Store در آن قرار دارد آپلود کنید.
  • نام فایل Zip اهمیت ندارد.

مدیریت فایل‌ها


می خواهیم برنامه ای بنویسیم که با کمک آن بتوانیم فایل های خود را مدیریت کنیم.

نیاز هایی که باید این فایل منیجر برطرف کند عبارتند از:🔗
  • ساخت یک پوشه جدید
  • ساخت یک فایل جدید
  • جستجو کردن بر اساس نام فایل
  • حذف فایل
  • بازیابی فایل

جزئیات🔗

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

رفتار خروجی متد
یک پوشه جدید با نام name در آدرس address می سازد. - create_dir(name, address)
یک فایل جدید با نام name در آدرس address ایجاد می کند . - create_file(name, address)
یک فایل با نام name را از آدرس address حذف می کند . - delete(name, address)
آدرس تمام فایل های با نام name را از آدرس address به بعد برمیگرداند ‌‍‍‍List find(name, address)
فایل با نام name را بازیابی می کند. - restore(name)

نکات🔗

  • در متد create_dir در صورت عدم وجود پوشه باید پوشه ای جدید ساخته شود در غیر این صورت نباید هیچ اتفاقی بیفتد!
  • در متد create_file در صورت عدم وجود فایل باید فایلی جدید ساخته شود در غیر این صورت نباید هیچ اتفاق دیگری بیفتد!
  • در متد delete در صورت عدم وجود فایل نباید هیچ اتفاقی بیفتد
  • در متد find باید یک لیست از تمام آدرس ها برگردانده شود ودر صورت عدم وجود فایلی با این نام یک لیست خالی برگردانده شود ترتیب این ادرس ها اهمیتی ندارد
  • آدرس‌های برگردانده شده از متد find باید از آدرس موجود در آرگومان‌ها به بعد باشد (آدرس شامل خود آرگومان نیز می‌باشد) .دقت شود که ممکن است فایل در سطوح پایین تر از سطح اول نیز موجود باشد.
  • متد restore
    • فایل بازیابی شده باید در آدرس قبلی خود قرار گیرد.
    • اگر چند فایل هم نام بصورت متوالی حذف شوند باید با هربار صدا زدن متد restore فایل‌ها به صورت متوالی و با عکس ترتیب حذف، بازیابی شوند.
    • باید در عمل حذف و بازیابی محتوای فایل حفظ شود.
    • در صورت عدم وجود فایلی برای بازیابی نباید هیچ اتفاقی بیفتد.
  • برای حل این سوال می توانید هر فایل و یا پوشه دیگری که خواستید بسازید.

نمونه🔗

fm = FileManager()
fm.create_dir('test', '.')
fm.create_dir('test1', 'test')
fm.create_dir('test2', 'test/test1/')

fm.create_file('test.txt', 'test')
fm.create_file('test.txt', 'test/test1')
fm.create_file('test.txt', 'test/test1/test2')
Plain text

خروجی:‌ باید پوشه ها و فایل های زیر ایجاد شوند.🔗

test
├── test1
│   ├── test2
│   │   └── test.txt
│   └── test.txt
└── test.txt
Plain text

ادامه دستورات🔗

print(fm.find('test.txt', 'test'))
Plain text

خروجی🔗

['test/test.txt', 'test/test1/test.txt', 'test/test1/test2/test.txt']
Plain text

ادامه دستورات🔗

fm.delete('test.txt', 'test')
fm.delete('test.txt', 'test/test1/')
fm.delete('test.txt', 'test/test1/test2')
fm.restore('test.txt')
fm.restore('test.txt')
Plain text

خروجی🔗

test
├── test1
   ├── test2
   │   └── test.txt
   └── test.txt
Plain text

آنچه باید آپلود کنید:🔗

یک فایل Zip شامل یک فایل به نام source.py که کلاس‌ FileManager در آن قرار دارد آپلود کنید.

پروکسی


می‌خواهیم کلاسی در زبان پایتون طراحی کنیم که عملکرد یک پروکسی را برای اشیائی که نماینده‌ٔ آنان‌ است داشته باشد. دقت کنید که این کلاس باید قادر باشد تمامی توابعی را که روی شی اصلی فراخوانی می‌شود، بدون تغییر کارکرد روی آنان اجرا کند. توجه کنید که این شئ می‌تواند از هر نوع کلاسی باشد.

فایل‌ اولیه پروژه را از اینجا دریافت کنید.

برای مثال اگر کد زیر را برای کلاس Radio داشته باشیم:

class Radio():   
    def __init__(self):        
        self._channel = None        
        self.is_on = False        
        self.volume = 0        

    @property    
    def channel(self):        
        return self._channel    

    @channel.setter    
    def channel(self, value):        
        self._channel = value        

    def power(self):        
        self.is_on = not self.is_on
Python

سپس اگر یک پروکسی از شئ از کلاس Radio بسازیم

radio = Radio()
radio_proxy = Proxy(radio)
Python

تمامی توابع بالا باید بر روی radio_proxy قابل فراخوانی باشد:

radio_proxy.channel = 95
radio_proxy.power()
Python
>>> radio.channel
>95
Plain text

اگر تابع فراخوانی‌شده، جزو توابع تعریف‌شده برای شئ هدف نباشد، باید استثنایی با پیام No Such Method پرتاب شود.

همچنین کلاس ‍‍Proxy که باید توابع آن را پیاده‌سازی کنید، باید قادر باشد اطلاعاتی را نیز ذخیره‌سازی کند. توابع و ویژگی‌هایی که این کلاس باید دارا باشد به شرح زیر است: (این فایل اولیه را می توانید از اینجا دریافت کنید.)

class Proxy:
    def __init__(self, obj):
        self._obj = obj

    def last_invoked_method(self):
        pass

    def count_of_calls(self, method_name):
        pass

    def was_called(self, method_name):
        pass
Python

که در آن تابع ‍‍last_invoked_method نام آخرین متد معتبر فراخوانی شده بر روی شئ هدف را بازمی‌گرداند و تایپ خروجی آن باید رشته باشد. در صورتی که تا لحظهٔ فراخوانی این تابع،‌ متدی روی شئ فراخوانی نشده بود، استثنایی با پیام No Method Is Invoked پرتاب می‌شود.

تابع count_of_calls می‌بایست به ازای نام متد ورودی، تعداد دفعاتی که این متد بر روی شئ فراخوانی شده را بازگرداند. اگر متد ورودی معتبر نباشد، مقدار 0 را برمی‌گرداند.

تابع was_called به ازای نام متد معتبر ورودیَ، یک Boolean را به عنوان خروجی برمی‌گرداند که اگر آن متد برروی شئ فراخوانی شده باشد مقدار True و در غیر این صورت مقدار Falseرا برمی‌گرداند. اگر متد ورودی معتبر نباشد مقدار False را برمی‌گرداند. در نهایت توجه کنید که در صورتی که ویژگی‌ها و متدهایی به شئ هدف، پس از ساختن پروکسی اضافه شوند، شئ پروکسی باید قادر به مدیریت توابع و ویژگی‌های جدید نیز باشد.

پاسخ ارسالی شما، باید یک فایل زیپ با ساختار زیر باشد:

<Your-zip-file-name.zip>
         └── Proxy.py
Plain text

سوپ زیبا


می‌خواهیم یک فایل HTML را پردازش کرده و هم‌چنین اطلاعاتی را از آن استخراج کنیم. برای این کار، باید کلاسی به نام HTMLParser طراحی کنید که ویژگی‌ها و توابع زیر را دارا باشد:

فایل اولیه پروژه را از اینجا دریافت کنید.

class HTMLParser:
    def __init__(self, html_doc):
        self.html_doc = html_doc
        pass

    def set_html_doc(self, html_doc):
        self.html_doc = html_doc

    def find_first(self, output_arg, **finding_args):
        pass

    def find_all(self, n, output_arg, **finding_args):
        pass

    def find_parent(self, output_arg, **finding_args):
        pass

    def find_grandparent(self, n, output_arg, **finding_args):
        pass

    def remove_comment(self, **finding_args):
        pass

    def remove_all_comments(self):
        pass

    def remove_tag(self, **finding_args):
        pass

if __name__ == '__main__':
    pass
Python

پیش از شرح توابع و ویژگی‌ها، مشخصه‌های جستجو finding_args و مشخصهٔ خروجی output_arg را شرح می‌دهیم:

۱- finding_args: یک دیکشنری است که می‌تواند یک یا چند کلید از میان name ، id ، string و class بپذیرد. برای مثال برای تگی مانند مثال زیر:

<p class="important" id="some-ID">you can <i>access</i> Quera <a href="http://www.quera.ir">here</a>!</p>
HTML

مشخصهٔ name برابر p، مشخصهٔ id برابر some-ID، مشخصه‌ٔ string برابر you can access Quera here! و مشخصهٔ class برابر important می‌باشد. تضمین می‌شود مشخصه‌های جستجوی ورودی تنها شامل مشخصه‌های فوق می‌باشد.

۲- output_arg: یک str است که مشخصهٔ مطلوب خروجی تابع را مشخص می‌کند و تضمین می‌شود مقادیری همانند بالا دارد. در صورتی که مقدار متناظر مشخصهٔ خروجی مقداردهی نشده بود، خروجی یک رشتهٔ خالی خواهد بود.

parser = HTMLParser("<b>some text.</b>")
>>> parser.find_first("class", name='b')
>""
>>> parser.find_first("string", name='b')
>"some text."
>>> parser.find_first("name", string="some text.")
>'b' 
Python

برای مثال فراخوانی یک تابع با مشخصه‌های فوق چنین است:

parser.find_first("string", id="link", name='a')
Python

ویژگی‌ها و توابع این کلاس به شرح زیر هستند:

‍۱- ویژگی html_doc: کل کد HTML به فرمت یک رشته str است.

۲- متد ‍‍find_first: مقدار مشخصهٔ خروجی (output_arg) اولین برچسب که با ویژگی‌های finding_args مطابقت داشته باشد را خروجی می‌دهد.

۳- متد find_all: یک لیست به طول حداکثر n از مقدار مشخصه‌های خروجی برچسب‌های مطابق با finding_args را برمی‌گرداند (‍‍‍‍‍nتای اول). اگر تعداد برچسب‌های یافته‌شده کمتر از n بود لیستی به اندازهٔ همان تعداد برمی‌گرداند.

مثال:

doc = '<b id="1">first</b> <b id="2">second</b> <b>third</b>'
parser.set_html_doc(doc)
>>> parser.find_all(4, "id", name='b')
>['1','2',""]
Python

۴- متد find_parent: مقدار مشخصهٔ خروجی اولین والد برچسب مطابق با مشخصه‌های جستجو را خروجی می‌دهد. (در صورتی که بیش از یک برچسب یافت شد، مقدار مطلوب را برای اولین برچسب یافته‌شده خروجی می‌دهد.) تضمین می‌شود برچسب‌های یافته‌شده حداقل یک والد دارند.

مثال: ‍‍‍

parser.set_html_doc("<p><b>example</b></p>")
>>>parser.find_parent("name", name='b', string='example')
>'p'
Python

۵- متد find_grandparent: مقدار مشخصهٔ خروجی nاُمین جد (اولین جد همان والد است.) اولین برچسب مطابق با مشخصه‌های جستجو را خروجی می‌دهد. در صورتی که n از تعداد جدهای برچسب یافته شده بیشتر باشد، استثنایی با پیام No Such Parent پرتاب شود. تضمین می‌شود برچسب‌های یافته‌شده حداقل یک والد دارند.

۶- متد remove_comment: اولین برچسب منطبق با مشخصهٔ ورودی را در صورتی که فقط محتوی کامنت باشد به طور کلی از html_docحذف می‌کند. کامنت‌های ‍‍HTML به صورت زیر هستند:

<!--Some Comments-->
HTML
parser.set_html_doc('<b id="comment"><!--comment--></b>')
>>> parser.remove_comment(name='b')
>>> parser.html_doc
>""
>>> parser.set_html_doc("<b>not a <!--comment--></b>")
>>> parser.remove_comment(name='b')
>>>parser.html_doc
>"<b>not a <!--comment--></b>"
Python

در صورتی که محتویات اولین برچسب یافته‌شده عاری از کامنت بود، استثایی با پیام No Comments Found پرتاب شود.

۷- متد remove_all_comments: تمامی برچسب‌های محتوی کامنت را از html_doc حذف می‌کند.

۸- متد remove_tag: اولین برچسب مطابق با مشخصات ورودی را به طور کلی از html_doc حذف می‌کند.

تذکر🔗

در تمامی متدهایی که می‌بایست برچسبی مطابق با مشخصات ورودی یافت شود، اگر برچسبی یافت نشد باید استثنایی با پیام No Such Tag پرتاب شود.

پاسخ ارسالی🔗

در پاسخ ارسالی خود می‌توانید از هر کتابخانه‌ای که لازم می‌دانید استفاده کنید. اما در فایل ارسالی خود، علاوه بر فایل HTMLParser.py که حاوی راه‌حل شما است، باید فایلی با نام python_requirements.txt نیز موجود باشد که در آن نام کتاب‌خانه‌های مورد نیاز و شمارهٔ نسخهٔ آن‌ها به فرمت زیر در آن موجود باشد:

firstlib==1.2.3
secondlib==4.5.6
...
Plain text

ساختار فایل ارسالی🔗

ساختار فایل .zip ارسالی شما باید به صورت زیر باشد:

<your_zip_file_name.zip>
         ├── HTMLParser.py
         └── python_requirements.txt
Plain text