在Python中使用抽象属性实现以下Scala代码的最短/最优雅的方法是什么?
abstract class Controller { val path: String }
Controller
强制使用子类来定义Scala编译器的"路径".子类看起来像这样:
class MyController extends Controller { override val path = "/home" }
Wtower.. 70
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
未能声明a
或b
在派生类B
中将引发TypeError
如下:
TypeError
:无法B
使用抽象方法实例化抽象类a
有一个@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
访问该对象时抛出错误,从而使执行不太严格。
这不是对原始答案的错。自发布以来,对抽象类语法进行了重大更改,在这种情况下,它可以实现更整洁,更实用的实现。
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
未能声明a
或b
在派生类B
中将引发TypeError
如下:
TypeError
:无法B
使用抽象方法实例化抽象类a
有一个@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有一个内置的异常.
class Base(object): @property def path(self): raise NotImplementedError class SubClass(Base): path = 'blah'
自从最初提出这个问题以来,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
访问该对象时抛出错误,从而使执行不太严格。
这不是对原始答案的错。自发布以来,对抽象类语法进行了重大更改,在这种情况下,它可以实现更整洁,更实用的实现。
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
.
您可以在abc.ABC抽象基类中创建一个属性,其值NotImplemented
如此,如果该属性未被覆盖然后使用,则会在运行时显示错误.
以下代码使用PEP 484类型提示来帮助PyCharm正确地静态分析path
属性的类型.
import abc class Controller(abc.ABC): path = NotImplemented # type: str class MyController(Controller): path = '/home'