CodeQL 文档

基类中的冲突属性

ID: py/conflicting-attributes
Kind: problem
Security severity: 
Severity: warning
Precision: high
Tags:
   - reliability
   - maintainability
   - modularity
Query suites:
   - python-security-and-quality.qls

单击查看 CodeQL 仓库中的查询

当一个类继承多个基类时,属性查找从左到右在基类中进行。这种形式的属性查找称为“方法解析顺序”,它是解决 菱形继承问题 的解决方案,其中多个基类在共享的超类中重写了一个方法。

不幸的是,这意味着如果多个基类定义了相同的属性,最左边的基类将有效地覆盖最右边的基类的属性,即使最左边的基类不是最右边的基类的子类。除非所讨论的方法是为继承而设计的,使用 super,否则这种隐式覆盖可能不是预期行为。即使它是预期行为,它也会使代码难以理解和维护。

建议

有一些方法可以用来解决这个问题

  • 在子类中覆盖属性以实现正确的行为。

  • 修改类层次结构,将等效或冗余的方法移动到一个公共超类。

  • 修改方法层次结构,将复杂的方法分解成组成部分。

  • 使用委托而不是继承。

示例

在这个例子中,类 ThreadingTCPServer 继承自 ThreadingMixInTCPServer。但是,这两个类都实现了 process_request,这意味着 ThreadingTCPServer 将从 ThreadingMixIn 继承 process_request。因此,TCPServerprocess_request 的实现将被忽略,这可能不是正确的行为。


class TCPServer(object):
    
    def process_request(self, request, client_address):
        self.do_work(request, client_address)
        self.shutdown_request(request)

    
class ThreadingMixIn:
    """Mix-in class to handle each request in a new thread."""

    def process_request(self, request, client_address):
        """Start a new thread to process the request."""
        t = threading.Thread(target = self.do_work, args = (request, client_address))
        t.daemon = self.daemon_threads
        t.start()

class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

这可以通过覆盖方法来解决,如类 ThreadingTCPServerOverriding 所示,或者通过确保两个基类提供的功能不重叠来解决,如类 ThreadingTCPServerChangedHierarchy 所示。

   
#Fixed by overriding. This does not change behavior, but makes it explicit and comprehensible.
class ThreadingTCPServerOverriding(ThreadingMixIn, TCPServer):
    
    def process_request(self, request, client_address):
        #process_request forwards to do_work, so it is OK to call ThreadingMixIn.process_request directly
        ThreadingMixIn.process_request(self, request, client_address)
        

#Fixed by separating threading functionality from request handling.
class ThreadingMixIn:
    """Mix-in class to help with threads."""

    def do_job_in_thread(self, job, args):
        """Start a new thread to do the job"""
        t = threading.Thread(target = job, args = args)
        t.start()

class ThreadingTCPServerChangedHierarchy(ThreadingMixIn, TCPServer):
    
    def process_request(self, request, client_address):
        """Start a new thread to process the request."""
        self.do_job_in_thread(self.do_work,  (request, client_address))
    

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私