【问题标题】:Python Abstract Method Default Logic, super() methodPython 抽象方法默认逻辑,super() 方法
【发布时间】:2017-05-11 22:32:31
【问题描述】:

我来自 Java 世界,我很难理解 super() 方法,因为它与抽象方法相关。

我有一个带有抽象方法的抽象类。这个类的子类负责查询我的 MySQL 数据库并将格式化的报告返回给我。在一半的子类中,它们使用完全相同的逻辑来运行报告。在另一半,每个人都需要自己的逻辑。因此我想让run_report 成为一个抽象方法。

class Report:
    __metaclass__ = ABCMeta

    def __init__(self):
        self.user = 'root'
        self.passwd = ''
        self.host = '127.0.0.0.1'
        self.port = '80'
        self.db = 'animals'        
        self.conn = mysql.connector.connect(user=self.user, password=self.passd, db=self.db, host=self.host, port=self.port)
        self.cursor = self.conn.cursor()

    @staticmethod
    def construct_query(query, external_data):
        finalQuery = query % external_data
        return finalQuery

    @abstractmethod
    def run_report(self, query):
        self.cursor.execute(self, query)
        results = self.cursor.fetchall()
        return data

下面是一个使用抽象方法的类的实现示例:

class SheepReport(Report):

    query = "SELECT COUNT(*) FROM sheep WHERE alive = 1;"

    def run_report(query):
        super(Report, self).run_report(query)

这种语法看起来很神秘。我的代码太不完整,目前无法测试运行,我正试图将错误扼杀在萌芽状态。我是否正确理解了抽象方法?

相比之下,这里有一个覆盖 run_report 的类:

 class CowReport(Report):

    query = "SELECT height, weight FROM cows WHERE name IN (%s);"

    def run_report(self):
        finalQuery = self.construct_query(query, "'Hilda', 'Gary'");
        self.cursor.execute(self, finalQuery)
        results = self.cursor.fetchall()
        return data

我在正确的轨道上吗?我见过的所有 super() 和继承的例子都让我头疼,我想我需要有人帮我把它弄糊涂。

【问题讨论】:

    标签: python inheritance abstract-class super


    【解决方案1】:

    首先,我真诚地希望这只是为了学习目的,而不是实际的生产代码。将未经处理的用户输入传递到查询字符串中等于完整的SQL injection attack

    不碍事...

    抽象类通常用于定义接口,而不是具体功能。尽管如此,对于您正在尝试做的事情,仅将 query 定义为抽象属性的抽象类将大大简化您的代码。

    class Report:
        __metaclass__ = ABCMeta
    
        def __init__(self):
            self.user = 'root'
            self.passwd = ''
            self.host = '127.0.0.0.1'
            self.port = '80'
            self.db = 'animals'
            self.conn = mysql.connector.connect(user=self.user, password=self.passd, db=self.db, 
                                                host=self.host, port=self.port)
            self.cursor = self.conn.cursor()
    
        @abstractproperty
        def query(self):
            return NotImplemented
    
        def construct_query(self, **external_data):
            finalQuery = self.query % external_data
            return finalQuery
    
        def run_report(self, **external_data):
            self.cursor.execute(self, self.construct_query(**external_data))
            results = self.cursor.fetchall()
            return results
    

    有了上面的类,那么你只需要像下面这样的子类:

    class SheepReport(Report):
    
        @property
        def query(self):
            return "SELECT COUNT(*) FROM sheep WHERE alive = 1;"
    

    不要介意无条件的self.query % external_data。它适用于模板字符串或带有 empty 字典数据的纯字符串。

    【讨论】:

    • 你不应该混合外部数据和查询字符串。
    • 太棒了,谢谢,我去看看抽象方法和抽象属性的区别!
    • OnlyDean 我对@Blender 触及的问题进行了一些扩展。请记住,如果这是实际代码,则存在严重的安全问题。
    • @OnlyDean 你不需要抽象类/方法。只需在 normal 父/基类中定义您的方法,然后在您认为必要的任何子类中覆盖它。
    • @OnlyDean 当您想要非具体(通常没有实现)类时,这些类主要定义子类应遵循的接口/协议。例如,像 PyCharm 这样的 IDE 在子类化 ABC 类而不提供抽象方法/属性的具体实现时会显示警告。
    猜你喜欢
    • 2012-08-27
    • 1970-01-01
    • 2015-11-27
    • 2020-11-09
    • 2017-10-12
    • 2014-10-05
    • 2020-05-14
    • 1970-01-01
    • 2019-04-09
    相关资源
    最近更新 更多