【问题标题】:"Unresolved attribute reference" in PyCharmPyCharm 中的“未解析的属性引用”
【发布时间】:2018-11-04 06:59:03
【问题描述】:

我在 PyCharm 中收到 unresolved attribute reference 'get_opposite_node' for class 'list' 警告,即使代码运行良好。

这是代码的相关部分:

    def bfs(self, start, end):
        visited = {start}  # visited set contains int indices
        start_node = self.Node(start)
        q = deque()
        q.append(start_node)  # deque contains Node objects
        while q:
            cur_node = q.popleft()  # Node object
            if cur_node.idx == end:
                return cur_node 

            for edge in self.get_out_edges(cur_node):
                # HERE IS WHERE I GET THE WARNING:
                child = self.Node(edge.get_opposite_node(i))
                child_idx = child.idx
                if child_idx not in visited:
                    visited.add(child_idx)
                    q.append(child)
                    child.parent = cur_node
        return None

    def get_out_edges(self, node):
        return self.adj[node.idx]

    def add_edge(self, line):
        # line is just a string from the input file 
        (v, u, w) = [int(x) for x in line.split()]
        e = Edge(v,u,w)
        self.adj[v].append(e)
        self.adj[u].append(e)
        self.edges.append(e)

self.adj是列表的列表:self.adj = [[] for _ in range(N)],后来被Edge类的边缘填充:

class Edge:
    def __init__(self, v, u, w):
        self.v = v
        self.u = u
        self.w = w

    def get_node(self):
        return self.v

    def get_opposite_node(self, k=None):
        return self.u if k == self.v or k is None else self.v

所以,基本上,虽然self.adj[i] 包含Edges,但 PyCharm 认为它包含列表(?)。有没有办法“说服”PyCharm 它不是这样的?

【问题讨论】:

    标签: python pycharm


    【解决方案1】:

    PyCharm 很困惑,因为您已将 adj 明确声明为(空)lists 的 list。它不能说您随后用理解get_opposite_node() 的对象覆盖了adj 的每个元素。但它确实知道您不能在 list 上使用 get_opposite_node()

    您可以通过将adj 声明为包含Nonelist 而不是空的lists 的list 来解决此问题。下面可能会澄清一点:

    class RealEdge:
        def get_something(self):
            return "something"
    
    
    class SomeEdgyThing:
        def __init__(self, size):
            self.adj = [[] for _ in range(size)]
    
    
    class SomeOtherEdgyThing:
        def __init__(self, size):
            self.adj = [None for _ in range(size)]
    
    
    class ReallyEdgyThing:
        def __init__(self, size):
            self.adj = [RealEdge() for _ in range(size)]
    
    
    my_complicated_thing = SomeEdgyThing(7)
    for i in range(len(my_complicated_thing.adj)):
        my_complicated_thing.adj[i] = RealEdge()
    # PyCharm warning:
    #     Unresolved attribute reference 'get_something' for class 'list'
    # Runs fine, because we overwrote all the values in adj
    # with RealEdges instead of lists.
    print(my_complicated_thing.adj[1].get_something())
    
    my_thing = SomeEdgyThing(7)
    try:
        # PyCharm warning:
        #     Unresolved attribute reference 'get_something' for class 'list'
        # Also a runtime error:
        #     AttributeError: 'list' object has no attribute 'get_something'
        print(my_thing.adj[1].get_something())
    except AttributeError as e:
        print(e)
    
    my_other_thing = SomeOtherEdgyThing(7)
    try:
        # PyCharm doesn't complain.
        # Does it assume NoneType is part of a union type...?
        # Runtime error:
        #     AttributeError: 'NoneType' object has no attribute 'get_something'
        print(my_other_thing.adj[1].get_something())
    except AttributeError as e:
        print(e)
    
    real_thing = ReallyEdgyThing(7)
    # No error
    print(real_thing.adj[1].get_something())
    

    输出:

    something
    'list' object has no attribute 'get_something'
    'NoneType' object has no attribute 'get_something'
    something
    

    我怀疑你真的不需要写 self.adj = [[] for _ in range(N)] 并且 self.adj = [None for _ in range(N)] 也可以使用,并且会导致警告消失。

    现在,您仍然会遇到这样的情况:您的代码以某种方式以错误的顺序运行,并且您尝试在 adj 的成员上调用 get_opposite_node(),而您尚未更新为包含真正的 Edge。你只是不再被警告了。出于这个原因,我建议将这些调用包装在 try: ... except AttributeError: 块中。

    【讨论】:

    • 我觉得有误会。 self.adj 不是Edges 的列表,而是Edges 的列表。 self.adj 基本上是一个列表,其中每个索引对应于图中节点的索引。 self.adj 中的每个列表都包含一个从这个节点出来的边缘列表。因此,对于给定的节点,函数 get_out_edges 返回一个边列表(然后我会遍历它:for edge in self.get_out_edges(cur_node))。我已经用另一个函数更新了原始问题,这可能会提供有关该问题的更多信息。
    • 好吧,这有点不同。在这里,PyCharm 很困惑,因为它不知道node.idx 不是slice()(这意味着get_out_edges 将返回一个列表列表)。如果您使用的是最新版本的python 3,则可以通过类型注释解决此问题,方法是将get_out_edges 的方法签名更改为def get_out_edges(self, node) -> list:,或在Node.idx 中添加注释,只要声明明确声明它是@ 987654354@。拥有完整的代码会有所帮助。
    猜你喜欢
    • 2017-10-07
    • 2015-02-03
    • 2019-08-08
    • 2019-01-10
    • 2015-06-12
    • 2019-08-19
    • 1970-01-01
    • 2020-03-05
    • 2018-06-08
    相关资源
    最近更新 更多