diff --git a/.gitignore b/.gitignore index 27f1fd8..796ac1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .ruff_cachetry init .idea/ +/venv/ +.DS_Store diff --git a/README.md b/README.md index f8e70ba..4691e76 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -Learn project with Python examples and for homework \ No newline at end of file +# Python__Pro \ No newline at end of file diff --git a/book.json b/book.json new file mode 100644 index 0000000..e8627ab --- /dev/null +++ b/book.json @@ -0,0 +1,31 @@ + + [ + { + "title": "Гамлет", + "author": "Вильям Шекспир", + "year": "1603" + }, + { + "title":"Изучаем Python", + "author":"Эрик Мэтиз", + "year": "2020" + }, + { + "title": "Ромэо и Джульетта", + "author": "Вильям Шекспир", + "year": "1597" + }, + { + "title": "Nature", + "author": "Nature publishing group", + "year": "1869", + "edition": "10" + }, + { + "title": "Medical", + "author": "World Helth Organization", + "year": "1948", + "edition": "1010" + } + ] + diff --git a/examples/__init__.py b/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/examples/constants.py b/examples/constants.py deleted file mode 100644 index 437b8eb..0000000 --- a/examples/constants.py +++ /dev/null @@ -1,5 +0,0 @@ -MOVIES = [ - 'Фільм 1: Шерлок Голмс', - 'Фільм 2: Інцепція', - 'Фільм 3: Матриця', -] diff --git a/examples/context_managers.py b/examples/context_managers.py deleted file mode 100644 index 51f39a2..0000000 --- a/examples/context_managers.py +++ /dev/null @@ -1,55 +0,0 @@ -from contextlib import contextmanager - - -@contextmanager -def file_opener(filename, mode): - file = open(filename, mode) - yield file - file.close() - - -class FileOpener: - def __init__(self, filename, mode): - self.filename = filename - self.mode = mode - self.file = None - - def __enter__(self): - self.file = open(self.filename, self.mode) - return self.file - - def __exit__(self, exc_type, exc_value, traceback): - self.file.close() - - -def call_class_context_manager(): - with FileOpener('class_cm.txt', 'w') as file: - file.write('Я був заповнений за допомогою классового контекстного менеджеру!') - - -def call_func_context_manager(): - with file_opener('func_cm.txt', 'w') as file: - file.write('Я був заповнений за допомогою функціонального контекстного менеджеру!') - - -def call_try_finally_construction(): - file = None - try: - file = open('try_finally.txt', 'w') - file.write('Я був заповнений за допомогою try/except/finally конструкцією!!') - except Exception as e: - print(f'Помилка: {e}') - finally: - if file: - file.close() - - -if __name__ == '__main__': - print('call_class_context_manager') - call_class_context_manager() - - print('call_func_context_manager') - call_func_context_manager() - - print('call_try_finally_construction') - call_try_finally_construction() diff --git a/examples/decorators.py b/examples/decorators.py deleted file mode 100644 index 69cd5b4..0000000 --- a/examples/decorators.py +++ /dev/null @@ -1,51 +0,0 @@ -import time - - -def timer(func): - def wrapper(*args, **kwargs): - start_time = time.perf_counter() - result = func(*args, **kwargs) - end_time = time.perf_counter() - elapsed_time = end_time - start_time - print(f"Функція '{func.__name__}' виконувалася {elapsed_time:.4f} секунд") - return result - return wrapper - - -@timer -def long_running_function(num): - for _ in range(num): - pass - - -def run_decorated_func_without_args(): - long_running_function(1000000) - - -def logger(func): - def wrapper(*args, **kwargs): - result = func(*args, **kwargs) - with open('log.txt', 'a') as file: - file.write( - f"Функція '{func.__name__}' була викликана з аргументами {args} і ключовими словами {kwargs}." - f" Результат: {result}\n", - ) - return result - return wrapper - - -@logger -def add(a, b): - return a + b - - -def run_decorated_func_with_args(): - add(2, 3) - - -if __name__ == '__main__': - print('run_decorated_func_without_args') - run_decorated_func_without_args() - - print('run_decorated_func_with_args()') - run_decorated_func_with_args() diff --git a/examples/func_cm.txt b/examples/func_cm.txt deleted file mode 100644 index 8c521e0..0000000 --- a/examples/func_cm.txt +++ /dev/null @@ -1 +0,0 @@ -Я був заповнений за допомогою функціонального контекстного менеджеру! \ No newline at end of file diff --git a/examples/generators.py b/examples/generators.py deleted file mode 100644 index 6ea250b..0000000 --- a/examples/generators.py +++ /dev/null @@ -1,51 +0,0 @@ -from examples.constants import MOVIES - - -def movie_generator(): - for movie in MOVIES: - yield movie - - -def via_for_loop(): - for movie in movie_generator(): - print(movie) - - -def use_generator_expression(): - movie_gen = (title for title in MOVIES) - - for movie in movie_gen: - print(movie) - - -def use_next(): - movie_gen = (title for title in MOVIES) - print(next(movie_gen)) # Виведе "Фільм: Шерлок Голмс" - - -def second_generator_usage(): - movie_gen = (title for title in MOVIES) - - # Використовуємо генератор вперше - for movie in movie_gen: - print(movie) - - print('Спроба викликати генератор вдруге:') - - # Спроба використовувати генератор вдруге - for movie in movie_gen: - print(movie) - - -if __name__ == '__main__': - print('via_for_loop') - via_for_loop() - - print('use_generator_expression') - use_generator_expression() - - print('use_next') - use_next() - - print('second_generator_usage') - second_generator_usage() diff --git a/examples/iterators.py b/examples/iterators.py deleted file mode 100644 index 2cd672f..0000000 --- a/examples/iterators.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Ітератори в Python - це об'єкти, які реалізують два методи: __iter__() та __next__(). -Ітератори дозволяють ітерувати (або проходитися) по елементам колекції (наприклад, списку або словника) послідовно. -""" -from examples.constants import MOVIES - - -class MovieCollection: - def __init__(self, movies_list: list[str] = MOVIES): - self.movies = movies_list - - def __iter__(self): - self.current_movie = 0 - return self - - def __next__(self): - if self.current_movie >= len(self.movies): - raise StopIteration - - movie = self.movies[self.current_movie] - self.current_movie += 1 - return movie - - -my_movies = MovieCollection() - - -def iter_movies_with_function(movies: MovieCollection = my_movies): - movie_iterator = iter(movies) - - print(next(movie_iterator)) # Фільм 1: Шерлок Голмс - print(next(movie_iterator)) # Фільм 2: Інцепція - print(next(movie_iterator)) # Фільм 3: Матриця - - # Цей наступний виклик спричинить StopIteration, тому що всі фільми вже були перебрані. - print(next(movie_iterator)) - - -def iter_movies_with_magic_methods(movies: MovieCollection = my_movies): - movie_iterator = movies.__iter__() - - print(movie_iterator.__next__()) # Фільм 1: Шерлок Голмс - print(movie_iterator.__next__()) # Фільм 2: Інцепція - - -def iter_via_for_loop(movies: MovieCollection): - for movie in movies: - print(movie) - - -if __name__ == '__main__': - print('iter_movies_with_function') - iter_movies_with_function() - - print('iter_movies_with_magic_methods') - iter_movies_with_magic_methods() - - print('iter_via_for_loop') - iter_via_for_loop(movies=MOVIES) diff --git a/examples/log.txt b/examples/log.txt deleted file mode 100644 index 34009a8..0000000 --- a/examples/log.txt +++ /dev/null @@ -1,8 +0,0 @@ -Функція 'add' була викликана з аргументами (2, 3) і ключовими словами {}. Результат: 5 -Функція 'add' була викликана з аргументами (2, 3) і ключовими словами {}. Результат: 5 -Функція 'add' була викликана з аргументами (4, 7) і ключовими словами {}. Результат: 11 -Функція 'add' була викликана з аргументами (4, 7) і ключовими словами {}. Результат: 11 -Функція 'add' була викликана з аргументами (0, 0) і ключовими словами {}. Результат: 0 -Функція 'add' була викликана з аргументами (0, 0) і ключовими словами {}. Результат: 0 -Функція 'add' була викликана з аргументами (0, 0) і ключовими словами {}. Результат: 0 -Функція 'add' була викликана з аргументами (0, 0) і ключовими словами {}. Результат: 0 diff --git a/examples/main.py b/examples/main.py deleted file mode 100644 index 94e3a87..0000000 --- a/examples/main.py +++ /dev/null @@ -1,16 +0,0 @@ -# This is a sample Python script. - -# Press ⌃R to execute it or replace it with your code. -# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings. - - -def print_hi(name): - # Use a breakpoint in the code line below to debug your script. - print(f'Hi, {name}') # Press ⌘F8 to toggle the breakpoint. - - -# Press the green button in the gutter to run the script. -if __name__ == '__main__': - print_hi('PyCharm') - -# See PyCharm help at https://www.jetbrains.com/help/pycharm/ diff --git a/examples/oop.py b/examples/oop.py deleted file mode 100644 index c54354f..0000000 --- a/examples/oop.py +++ /dev/null @@ -1,65 +0,0 @@ -from abc import ABC, abstractmethod - - -# Абстракція -class AbstractPiglet(ABC): - def __init__(self, name: str): - self.name = name - - @abstractmethod - def build_house(self): - raise NotImplementedError - - @property - @abstractmethod - def house_material(self): - raise NotImplementedError - - -class Piglet(AbstractPiglet): - def __init__(self, name, material: str = 'солома'): - super().__init__(name) - self.__house_material = material # Інкапсуляція - self._strategy = 'Врятуватися від вовка.' - - @property - def house_material(self): - return self.__house_material - - def print_strategy(self): - print(self._strategy) - - def build_house(self): - print(f'{self.name} побудував будинок з {self.house_material}!') - - -# Наслідування -class ImprovedPiglet(Piglet): - def __init__(self, name: str, material: str = 'цегла'): - super().__init__(name=name, material=material) - - -class Wolf: - def __init__(self, name: str = 'Вова'): - self.name = name - - def huff_and_puff(self, piglet: AbstractPiglet): - if piglet.house_material == 'солома': - print(f'Вовк {self.name} він здув будинок!') - else: - print(f'Вовк {self.name} не зміг здути будинок.') - - -if __name__ == '__main__': - first_piglet = Piglet(name='Хрю') - first_piglet.build_house() - first_piglet.print_strategy() - - second_piglet = ImprovedPiglet(name='Хря') - second_piglet.build_house() - second_piglet.print_strategy() - - big_bad_wolf = Wolf() - # Поліморфізм - big_bad_wolf.huff_and_puff(piglet=first_piglet) - big_bad_wolf.huff_and_puff(piglet=second_piglet) diff --git a/examples/pydantics.py b/examples/pydantics.py deleted file mode 100644 index 67ed19a..0000000 --- a/examples/pydantics.py +++ /dev/null @@ -1,58 +0,0 @@ -from datetime import ( - date, - datetime, -) - -from dateutil.relativedelta import relativedelta -from pydantic import ( - BaseModel, - EmailStr, - computed_field, - field_validator, -) - - -class User(BaseModel): - first_name: str - last_name: str - birth_date: date - email: EmailStr - - @computed_field - @property - def age(self) -> int: - return relativedelta(datetime.now(), self.birth_date).years - - @field_validator('email') - def validate_domain_zone(cls, value): - if '.ru' in value: - raise ValueError('We do not accept ru domains!') - - return value - - -if __name__ == '__main__': - # Створення інстансу моделі за допомогою іменованих аргументів - user1 = User( - first_name='Іван', - last_name='Петрович', - birth_date='1990-01-15', - email='ivan.petrovich@example.com', - ) - - # Створення інстансу моделі передавши словником - attrs = { - 'first_name': 'Олена', - 'last_name': 'Сергіївна', - 'birth_date': '1985-05-20', - 'email': 'olena.sergiivna@example.com', - } - - user2 = User(**attrs) - - # Вивести модель у вигляді словника і як JSON - print(user1.model_dump()) - print(user1.model_dump_json()) - - print(user2.model_dump()) - print(user2.model_dump_json()) diff --git a/examples/solid.py b/examples/solid.py deleted file mode 100644 index 6f67826..0000000 --- a/examples/solid.py +++ /dev/null @@ -1,116 +0,0 @@ -from abc import ABC, abstractmethod -from typing import List - - -# Single Responsibility Principle -class Engine: - def start(self) -> str: - return 'Двигун стартував' - - def stop(self) -> str: - return 'Двигун зупинився' - - -class Radio: - def turn_on(self) -> str: - return 'Радіо включено' - - def turn_off(self) -> str: - return 'Радіо виключено' - - -# Open/Closed Principle -class BaseSensor(ABC): - @abstractmethod - def read_data(self) -> str: - pass - - -class TemperatureSensor(BaseSensor): - def read_data(self) -> str: - return 'Дані температурного датчика' - - -# Liskov Substitution Principle -class Bird: - def move(self) -> str: - return 'Птах літає' - - -class Ostrich(Bird): - def move(self) -> str: - return 'Страус біжить' - - -# Interface Segregation Principle -class Worker(ABC): - @abstractmethod - def work(self) -> str: - pass - - -class Musician(Worker): - def work(self) -> str: - return 'Музикант грає на інструменті' - - -class Builder(Worker): - def work(self) -> str: - return 'Будівельник будує будівлю' - - -# Dependency Inversion Principle -class LightBulb(ABC): - @abstractmethod - def turn_on(self) -> str: - pass - - @abstractmethod - def turn_off(self) -> str: - pass - - -class IncandescentBulb(LightBulb): - def turn_on(self) -> str: - return 'Лампочка розжарюється' - - def turn_off(self) -> str: - return 'Лампочка гасне' - - -class Switch: - def __init__(self, bulb: LightBulb): - self.bulb = bulb - - def operate(self) -> str: - return self.bulb.turn_on() + '\n' + self.bulb.turn_off() - - -if __name__ == '__main__': - # Single Responsibility Principle - engine = Engine() - print(engine.start()) - radio = Radio() - print(radio.turn_on()) - - # Open/Closed Principle - sensors: List[BaseSensor] = [TemperatureSensor()] - for sensor in sensors: - print(sensor.read_data()) - - # Liskov Substitution Principle - bird = Bird() - print(bird.move()) - ostrich = Ostrich() - print(ostrich.move()) - - # Interface Segregation Principle - musician = Musician() - print(musician.work()) - builder = Builder() - print(builder.work()) - - # Dependency Inversion Principle - bulb = IncandescentBulb() - switch = Switch(bulb=bulb) - print(switch.operate()) diff --git a/examples/try_finally.txt b/examples/try_finally.txt deleted file mode 100644 index 458e2fe..0000000 --- a/examples/try_finally.txt +++ /dev/null @@ -1 +0,0 @@ -Я був заповнений за допомогою try/except/finally конструкцією!! \ No newline at end of file diff --git a/lesson_2.py b/lesson_2.py new file mode 100644 index 0000000..a5944ef --- /dev/null +++ b/lesson_2.py @@ -0,0 +1,136 @@ +from typing import List +from pydantic import BaseModel +import logging +import json + + +class BookModel(BaseModel): + title: str + author: str + year: int + + +class AbstractLibraryItem(BaseModel): + def item_info(self): + raise NotImplementedError + + +class Book(BookModel, AbstractLibraryItem): + def item_info(self): + return f"Книга '{self.title}' автора {self.author}, год издания {self.year}" + + +class Journal(BaseModel): + title: str + author: str + year: int + edition: int + + def item_info(self): + return f"Журнал '{self.title}' автора {self.author}, год издания {self.year}, номер издания {self.edition}" + + +class Library: + def __init__(self): + self.__books: List[AbstractLibraryItem] = [] + + def __iter__(self): + return iter(self.__books) + + def book_author(self, author: str): + return [book for book in self.__books if isinstance(book, Book) and book.author.lower() == author.lower()] + + @staticmethod + def log_add_book(func): + def wrapper(self, item: AbstractLibraryItem): + logging.info(f"Добавлено в библиотеку: {item.item_info()}") + return func(self, item) + + return wrapper + + @staticmethod + def check_book_exists(func): + def wrapper(self, title: str): + if any(isinstance(book, Book) and book.title.lower() == title.lower() for book in self.__books): + return func(self, title) + else: + logging.error(f"Книга '{title}' не найдена в библиотеке.") + + return wrapper + + @log_add_book + def add_book(self, item: AbstractLibraryItem): + self.__books.append(item) + + @check_book_exists + def remove_book(self, title: str): + self.__books = [book for book in self.__books if + not (isinstance(book, Book) and book.title.lower() == title.lower())] + + def save_books(self, filename: str = 'my_file.txt'): + unique_books = set() + unique_journals = set() + + with open(filename, 'w') as file: + for item in self.__books: + if isinstance(item, Book): + book_tuple = (item.title, item.author, item.year) + if book_tuple not in unique_books: + unique_books.add(book_tuple) + file.write(f"Книга: {item.title}, Автор: {item.author}, Год издания: {item.year}\n") + elif isinstance(item, Journal): + journal_tuple = (item.title, item.author, item.year, item.edition) + if journal_tuple not in unique_journals: + unique_journals.add(journal_tuple) + file.write( + f"Журнал: {item.title}, Автор: {item.author}, Год издания: {item.year}, Номер издания: {item.edition}\n") + + def load_books_from_file(self, filename: str = 'book.json'): + with open(filename, 'r') as file: + books_data = json.load(file) + for book_data in books_data: + if 'edition' in book_data: + journal = Journal(**book_data) + self.add_book(journal) + else: + book = Book(**book_data) + self.add_book(book) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + + my_library = Library() + + my_library.load_books_from_file() + + books_in_library = list(my_library) + if books_in_library: + print("Список книг в библиотеке:") + for item in books_in_library: + print(item.item_info()) + + author = "Вильям Шекспир" + book_author = my_library.book_author(author) + if book_author: + print(f"\nКниги автора '{author}':") + for book in book_author: + print(book.item_info()) + + title_to_remove = "Гамлет" + my_library.remove_book(title_to_remove) + books_after_removal = list(my_library) + if books_after_removal: + print("\nУдалена книга:", {title_to_remove}) + print("Список книг после удаления:") + for item in books_after_removal: + print(item.item_info()) + + my_library.load_books_from_file('book.json') + books_after_addition = list(my_library) + if books_after_addition: + print("\nСписок книг в библиотеке после добавления:") + for item in books_after_addition: + print(item.item_info()) + + my_library.save_books('my_file.txt') diff --git a/main.py b/main.py deleted file mode 100644 index 94e3a87..0000000 --- a/main.py +++ /dev/null @@ -1,16 +0,0 @@ -# This is a sample Python script. - -# Press ⌃R to execute it or replace it with your code. -# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings. - - -def print_hi(name): - # Use a breakpoint in the code line below to debug your script. - print(f'Hi, {name}') # Press ⌘F8 to toggle the breakpoint. - - -# Press the green button in the gutter to run the script. -if __name__ == '__main__': - print_hi('PyCharm') - -# See PyCharm help at https://www.jetbrains.com/help/pycharm/ diff --git a/my_file.txt b/my_file.txt new file mode 100644 index 0000000..0ad7033 --- /dev/null +++ b/my_file.txt @@ -0,0 +1,5 @@ +Книга: Изучаем Python, Автор: Эрик Мэтиз, Год издания: 2020 +Книга: Ромэо и Джульетта, Автор: Вильям Шекспир, Год издания: 1597 +Журнал: Nature, Автор: Nature publishing group, Год издания: 1869, Номер издания: 10 +Журнал: Medical, Автор: World Helth Organization, Год издания: 1948, Номер издания: 1010 +Книга: Гамлет, Автор: Вильям Шекспир, Год издания: 1603 diff --git a/poetry.lock b/poetry.lock index 7142b2a..b237b9a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -375,4 +375,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "2c7156bdfce01ec2335e79c1049d72601609909d2da6bdfed12647b7eb6332f2" +content-hash = "2c7156bdfce01ec2335e79c1049d72601609909d2da6bdfed12647b7eb6332f2" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..47bb487 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,9 @@ +blinker==1.7.0 +click==8.1.7 +Flask==3.0.2 +itsdangerous==2.1.2 +Jinja2==3.1.3 +MarkupSafe==2.1.5 +Werkzeug==3.0.1 + +pydantic~=2.6.4 \ No newline at end of file