python 包中的循环依赖

Circilar Dependance in python package

我的任务是制作一个名为 "project" 的 python 包。在里面,我必须创建 2 个单独的文件,这些文件具有我事先指定的特定名称。在它们中的每一个中,我都必须放入 1 class 及其参数和方法。到目前为止一切都很好。但这就是问题所在——每个 class 都引用另一个来正常工作(在任务描述中,我得到了两个 classes 的方法名称,其中一些必须引用来自另一个 class 所以我当然使用了 from project.xxxx import Xxxx).

我有 class 库和方法 -

add_user(user: User)

我有 class 用户使用方法

get_book(author: str, book_name: str, days_to_return: int, library: Library)

在这里我了解了循环依赖问题。我写了一些文章如何解决它 - 将这些东西合并到一个文件中或制作更多文件并重组代码。这是不行的 - 名为 "project" 的包只有 2 个文件提供了名称,并且每个文件中有 1 个 class 是必须的,因为我必须将一个包含该包的 zip 文件提交到在线自动化系统进行测试。

我遇到的另一件事是将导入语句放在其中一个文件的末尾。我尝试了 1 个文件和两个文件,但仍然出现 ImportError。

如有任何帮助,我们将不胜感激。

这是第一个class:

from project.user import User

class Library:
    def __init__(self):
        self.user_records = []
        self.books_available = {}
        self.rented_books = {}

    def add_user(self, user: User):
        if user.username in [u.username for u in self.user_records]:
            return f'User with id = {user.id} already registered in the library!'
        self.user_records.append(user)

    def remove_user(self, user: User):
        if user.username not in [u.username for u in self.user_records]:
            return 'We could not find such user to remove!'
        for i, o in enumerate(self.user_records):
            if o.username == user.username:
                del self.user_records[i]

    def change_username(self, user_id: int, new_username: str):
        user = [u for u in self.user_records if u.id == user_id][0]
        if not user:
            return f'There is no user with id = {user_id}!'
        if user.username == new_username:
            return f'Please check again the provided username - it should be different than the username used so far!'
        user.username = new_username
        return f'Username successfully changed to: {new_username} for userid: {user_id}'

这是第二个class:

from project.library import Library

class User:
    def __init__(self, user_id: int, username: str):
        self.books = []
        self.id = user_id
        self.username = username

    def get_book(self, author: str, book_name: str, days_to_return: int, library: Library):
        rented_books = [x for x in library.rented_books.values()]
        if rented_books:
            for x in rented_books:
                if book_name in x:
                    days = x[book_name]
                    return f'he book "{book_name}" is already rented and will be available in' \
                           f' {days} days!'
        if book_name in library.books_available[author]:
            if self.username not in library.rented_books:
                library.rented_books[self.username] = {}
            library.rented_books[self.username].update({book_name: days_to_return})
            library.books_available[author].remove(book_name)
            self.books.append(book_name)
            return f'{book_name} successfully rented for the next {days_to_return} days!'

    def return_book(self, author:str, book_name:str, library: Library):
        if book_name in self.books:
            library.books_available[author].append(book_name)
            library.rented_books[self.username].pop(book_name)
            self.books.remove(book_name)
        else:
            return f"{self.username} doesn't have this book in his/her records!"

    def info(self):
        books = sorted(self.books, key=lambda x: x)
        return ', '.join(books)

很高兴您开始编写自己的代码并将其发布。

快速回答是您不需要向库中添加类型提示 class。 而不是:

def add_user(self, user: User):

你可以这样写:

def add_user(self, user):

并删除导入语句 (from project.user import User)

只需更改它,库 class 中就没有任何内容需要知道用户 class,因此不再有循环依赖,您的代码将 运行。

例如,我检查了 运行ning 这个:

library_of_congress = Library()
tom = User(user_id=1, username="tom")
library_of_congress.add_user(tom)

注意:您还需要一些其他步骤才能使其他功能正常工作: (但这超出了您的 "circular dependency question" 的范围)

library_of_congress.books_available = { <put the book info here> }
tom.get_book( <put the correct arguments> )

等等

希望这对您的剩余作业有所帮助,祝您好运! 您可以在 python 中阅读有关类型提示的更多信息:

https://realpython.com/python-type-checking/

https://docs.python.org/3/library/typing.html