11

在 Scala 中,我可以定义一个抽象类并用一个对象来实现它:

abstrac class Base {
    def doSomething(x: Int): Int
}

object MySingletonAndLiteralObject extends Base {
    override def doSomething(x: Int) = x*x
}

我在 Python 中的具体示例:

class Book(Resource):

    path = "/book/{id}"

    def get(request):
        return aBook

继承在这里没有意义,因为没有两个类可以具有相同的path. 并且只需要一个实例,因此该类不会充当对象的蓝图。换句话说:这里不需要类ResourceBook在我的示例中),但需要一个基类来提供通用功能。

我想要:

object Book(Resource):

    path = "/book/{id}"

    def get(request):
        return aBook

Python 3 的方法是什么?

4

3 回答 3

7

在创建时使用装饰器将继承的类转换为对象

我相信这样一个对象的概念不是 Python 中典型的编码方式,但如果你必须这样class_to_object做,那么下面用于立即初始化的装饰器就可以解决问题。请注意,对象初始化的任何参数都必须通过装饰器传递:

def class_to_object(*args):
    def c2obj(cls):
        return cls(*args)
    return c2obj

使用这个装饰器,我们得到

>>> @class_to_object(42)
... class K(object):
...     def __init__(self, value):
...         self.value = value
... 
>>> K
<__main__.K object at 0x38f510>
>>> K.value
42

最终结果是你有一个K类似于你的 scala 对象的对象,并且命名空间中没有类来初始化其他对象。

注意:为了迂腐,可以检索对象 K 的类,K.__class__因此如果有人真的想要,可以初始化其他对象。如果你真的想要的话,在 Python 中几乎总有办法解决问题。

于 2010-08-19T12:37:44.047 回答
2

Use an abc (Abstract Base Class):

import abc
class Resource( metaclass=abc.ABCMeta ):
    @abc.abstractproperty
    def path( self ):
        ...
        return p

Then anything inheriting from Resource is required to implement path. Notice that path is actually implemented in the ABC; you can access this implementation with super.

于 2010-08-19T08:46:23.143 回答
1

如果您可以Resource直接实例化,您只需执行此操作并直接粘贴路径和get方法。

from types import MethodType

book = Resource()
def get(self):
    return aBook
book.get = MethodType(get, book)
book.path = path

这假设path并且get没有在__init__方法中使用,Resource并且路径没有被任何不应该引起您关注的类方法使用。

如果您主要关心的是确保没有任何东西从Book非类继承,那么您可以使用这个元类

class Terminal(type):
    classes = []
    def __new__(meta, classname, bases, classdict):
        if [cls for cls in meta.classes if cls in bases]:
            raise TypeError("Can't Touch This")
        cls = super(Terminal, meta).__new__(meta, classname, bases, classdict)
        meta.classes.append(cls)
        return cls

class Book(object):
    __metaclass__ = Terminal

class PaperBackBook(Book):
    pass

您可能想用更合适的东西替换抛出的异常。这只有在你发现自己实例化了很多一次性事件时才有意义。

如果这对你来说还不够好并且你正在使用 CPython,你总是可以尝试一些这样的骇客:

class Resource(object):
    def __init__(self, value, location=1):
        self.value = value
        self.location = location

with Object('book', Resource, 1, location=2):
    path = '/books/{id}'
    def get(self):
        aBook = 'abook' 
        return aBook

print book.path
print book.get()

我的第一个上下文管理器使这成为可能。

class Object(object):
    def __init__(self, name, cls, *args, **kwargs):
        self.cls = cls
        self.name = name
        self.args = args
        self.kwargs = kwargs

    def __enter__(self):
        self.f_locals = copy.copy(sys._getframe(1).f_locals)

    def __exit__(self, exc_type, exc_val, exc_tb):
        class cls(self.cls):
            pass
        f_locals = sys._getframe(1).f_locals
        new_items = [item for item in f_locals if item not in self.f_locals]
        for item in new_items:
            setattr(cls, item, f_locals[item])
            del f_locals[item] # Keyser Soze the new names from the enclosing namespace
        obj = cls(*self.args, **self.kwargs)
        f_locals[self.name] = obj # and insert the new object      

当然,我鼓励您使用上述两种解决方案之一或 Katrielalex 对 ABC 的建议。

于 2010-08-19T09:09:10.750 回答