当前位置:  开发笔记 > 编程语言 > 正文

Python中的抽象属性

如何解决《Python中的抽象属性》经验,为你挑选了5个好方法。

在Python中使用抽象属性实现以下Scala代码的最短/最优雅的方法是什么?

abstract class Controller {

    val path: String

}

Controller强制使用子类来定义Scala编译器的"路径".子类看起来像这样:

class MyController extends Controller {

    override val path = "/home"

}

Wtower.. 70

Python 3.3+

from abc import ABCMeta, abstractmethod


class A(metaclass=ABCMeta):
    def __init__(self):
        # ...
        pass

    @property
    @abstractmethod
    def a(self):
        pass

    @abstractmethod
    def b(self):
        pass


class B(A):
    a = 1

    def b(self):
        pass

未能声明ab在派生类B中将引发TypeError如下:

TypeError:无法B使用抽象方法实例化抽象类a

Python 2.7

有一个@abstractproperty装饰器:

from abc import ABCMeta, abstractmethod, abstractproperty


class A:
    __metaclass__ = ABCMeta

    def __init__(self):
        # ...
        pass

    @abstractproperty
    def a(self):
        pass

    @abstractmethod
    def b(self):
        pass


class B(A):
    a = 1

    def b(self):
        pass

您的python 3解决方案将`a`实现为`B`的类属性,而不是对象属性。如果改为使用类B(A):def __init __(self):self.a = 1 ...`则在实例化B时会出错:“无法使用抽象实例化抽象B类方法“ (3认同)


小智.. 62

虽然在运行时之前不会遇到异常,但Python有一个内置的异常.

class Base(object):
    @property
    def path(self):
        raise NotImplementedError


class SubClass(Base):
    path = 'blah'

具体来说,在访问attrtibute之前不会遇到异常,在这种情况下,无论如何都会遇到AttributeError. (9认同)

并不是说只有``path`直接在`SubClass`上设置才有效.给定一个实例`sc = SubClass()`,如果你试图设置`sc.path ='blah'`或者有一个方法包含类似`self.path ='blah'`的东西,而不直接定义`path`` SubClass`,你会得到一个`AttributeError:无法设置属性`. (8认同)

我认为提出一个'NotImplementedError`是更明确的,因此可能比将它留给`AttributeError`更好. (5认同)


小智.. 13

自从最初提出这个问题以来,python已经改变了抽象类的实现方式。我在python 3.6中使用abc.ABC形式主义使用了稍微不同的方法。在这里,我将常量定义为必须在每个子类中定义的属性。

from abc import ABC, abstractmethod


class Base(ABC):

    @property
    @classmethod
    @abstractmethod
    def CONSTANT(cls):
        return NotImplementedError

    def print_constant(self):
        print(type(self).CONSTANT)


class Derived(Base):
    CONSTANT = 42

这将强制派生类定义常量,否则TypeError当您尝试实例化子类时将引发异常。如果要将常量用于抽象类中实现的任何功能,则必须使用type(self).CONSTANT而不是just 访问子类常量CONSTANT,因为该值在基类中未定义。

还有其他方法可以实现此功能,但是我喜欢这种语法,因为对我来说,这似乎对读者来说是最简单和显而易见的。

先前的答案都触及了有用的观点,但是我认为被接受的答案并不能直接回答问题,因为

该问题要求在抽象类中实现,但可接受的答案并不遵循抽象形式主义。

问题要求实施是强制的。我认为在此答案中强制执行更为严格,因为如果CONSTANT未定义子类,则在实例化子类时会导致运行时错误。接受的答案允许实例化该对象,并且仅在CONSTANT访问该对象时抛出错误,从而使执行不太严格。

这不是对原始答案的错。自发布以来,对抽象类语法进行了重大更改,在这种情况下,它可以实现更整洁,更实用的实现。



1> Wtower..:

Python 3.3+

from abc import ABCMeta, abstractmethod


class A(metaclass=ABCMeta):
    def __init__(self):
        # ...
        pass

    @property
    @abstractmethod
    def a(self):
        pass

    @abstractmethod
    def b(self):
        pass


class B(A):
    a = 1

    def b(self):
        pass

未能声明ab在派生类B中将引发TypeError如下:

TypeError:无法B使用抽象方法实例化抽象类a

Python 2.7

有一个@abstractproperty装饰器:

from abc import ABCMeta, abstractmethod, abstractproperty


class A:
    __metaclass__ = ABCMeta

    def __init__(self):
        # ...
        pass

    @abstractproperty
    def a(self):
        pass

    @abstractmethod
    def b(self):
        pass


class B(A):
    a = 1

    def b(self):
        pass


您的python 3解决方案将`a`实现为`B`的类属性,而不是对象属性。如果改为使用类B(A):def __init __(self):self.a = 1 ...`则在实例化B时会出错:“无法使用抽象实例化抽象B类方法“

2> 小智..:

虽然在运行时之前不会遇到异常,但Python有一个内置的异常.

class Base(object):
    @property
    def path(self):
        raise NotImplementedError


class SubClass(Base):
    path = 'blah'


具体来说,在访问attrtibute之前不会遇到异常,在这种情况下,无论如何都会遇到AttributeError.
并不是说只有``path`直接在`SubClass`上设置才有效.给定一个实例`sc = SubClass()`,如果你试图设置`sc.path ='blah'`或者有一个方法包含类似`self.path ='blah'`的东西,而不直接定义`path`` SubClass`,你会得到一个`AttributeError:无法设置属性`.
我认为提出一个'NotImplementedError`是更明确的,因此可能比将它留给`AttributeError`更好.

3> 小智..:

自从最初提出这个问题以来,python已经改变了抽象类的实现方式。我在python 3.6中使用abc.ABC形式主义使用了稍微不同的方法。在这里,我将常量定义为必须在每个子类中定义的属性。

from abc import ABC, abstractmethod


class Base(ABC):

    @property
    @classmethod
    @abstractmethod
    def CONSTANT(cls):
        return NotImplementedError

    def print_constant(self):
        print(type(self).CONSTANT)


class Derived(Base):
    CONSTANT = 42

这将强制派生类定义常量,否则TypeError当您尝试实例化子类时将引发异常。如果要将常量用于抽象类中实现的任何功能,则必须使用type(self).CONSTANT而不是just 访问子类常量CONSTANT,因为该值在基类中未定义。

还有其他方法可以实现此功能,但是我喜欢这种语法,因为对我来说,这似乎对读者来说是最简单和显而易见的。

先前的答案都触及了有用的观点,但是我认为被接受的答案并不能直接回答问题,因为

该问题要求在抽象类中实现,但可接受的答案并不遵循抽象形式主义。

问题要求实施是强制的。我认为在此答案中强制执行更为严格,因为如果CONSTANT未定义子类,则在实例化子类时会导致运行时错误。接受的答案允许实例化该对象,并且仅在CONSTANT访问该对象时抛出错误,从而使执行不太严格。

这不是对原始答案的错。自发布以来,对抽象类语法进行了重大更改,在这种情况下,它可以实现更整洁,更实用的实现。



4> drhagen..:

In Python 3.6+, you can annotate an attribute of an abstract class (or any variable) without providing a value for that attribute.

class Controller:
    path: str

class MyController(Controller):
    path = "/home"

This makes for very clean code where it is obvious that the attribute is abstract. Code that tries to access the attribute when if has not been overwritten will raise an AttributeError.



5> phoenix..:

您可以在abc.ABC抽象基类中创建一个属性,其值NotImplemented如此,如果该属性未被覆盖然后使用,则会在运行时显示错误.

以下代码使用PEP 484类型提示来帮助PyCharm正确地静态分析path属性的类型.

import abc


class Controller(abc.ABC):
    path = NotImplemented  # type: str


class MyController(Controller):
    path = '/home'

推荐阅读
mylvfamily
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有