我应该使用元类、类装饰器还是重写 __new__ 方法?

发布于 2024-08-26 10:37:16 字数 433 浏览 1 评论 0原文

这是我的问题。我希望下面的类有一堆属性。我可以像 foobar 一样把它们全部写出来,或者根据我见过的其他一些例子,看起来我可以使用类装饰器、元类,或者重写 __new__ 方法来自动设置属性。我只是不确定“正确”的做法是什么。

class Test(object):
    def calculate_attr(self, attr):
        # do calculaty stuff
        return attr

    @property
    def foo(self):
        return self.calculate_attr('foo')

    @property
    def bar(self):
        return self.calculate_attr('bar')

Here is my problem. I want the following class to have a bunch of property attributes. I could either write them all out like foo and bar, or based on some other examples I've seen, it looks like I could use a class decorator, a metaclass, or override the __new__ method to set the properties automagically. I'm just not sure what the "right" way to do it would be.

class Test(object):
    def calculate_attr(self, attr):
        # do calculaty stuff
        return attr

    @property
    def foo(self):
        return self.calculate_attr('foo')

    @property
    def bar(self):
        return self.calculate_attr('bar')

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

暮光沉寂 2024-09-02 10:37:16

魔法很糟糕。它使您的代码更难理解和维护。您几乎永远不需要元类或 __new__ 。

看起来您的用例可以使用非常简单的代码来实现(只有一点点魔法):

class Test(object):
    def calculate_attr(self, attr):
        return something

    def __getattr__(self, name):
        return self.calculate_attr(name)

Magic is bad. It makes your code harder to understand and maintain. You virtually never need metaclasses or __new__.

It looks like your use case could be implemented with pretty straightforward code (with only a small hint of magic):

class Test(object):
    def calculate_attr(self, attr):
        return something

    def __getattr__(self, name):
        return self.calculate_attr(name)
苏佲洛 2024-09-02 10:37:16

元类的 __new__ 不会成为您创建的类的 __new__ — 它用于创建类本身。 实际的类对象由元类返回。类的新实例由 __new__ 返回。

考虑以下(疯狂的)代码:(

def MyMetaClass(name, bases, dict):
    print "name", name
    print "bases", bases
    print "dict", dict
    return 7

class C('hello', 'world'):
    __metaclass__ = MyMetaClass

    foo = "bar"

    def baz(self, qux):
        pass

print "C", C

我使用函数而不是类作为元类。任何可调用的都可以用作元类,但许多人选择将其正确为从 type 继承的类与 new 覆盖的函数之间的差异是微妙的。)

它的输出

name C
bases ('hello', 'world')
dict {'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>}
C 7

是否可以帮助您更好地理解元类是什么

很少需要定义自己的元类。

A metaclass's __new__ does not become the __new__ for the class you make—it's used to make the class itself. The actual class object is returned by the metaclass. A new instance of a class is returned by __new__.

Consider the following (insane) code:

def MyMetaClass(name, bases, dict):
    print "name", name
    print "bases", bases
    print "dict", dict
    return 7

class C('hello', 'world'):
    __metaclass__ = MyMetaClass

    foo = "bar"

    def baz(self, qux):
        pass

print "C", C

(I used a function instead of a class as the metaclass. Any callable can be used as a metaclass, but many people choose to right theirs as classes that inherit from type with new overrided. The differences between that an a function are subtle.)

It outputs

name C
bases ('hello', 'world')
dict {'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>}
C 7

Does that help you better make sense of what metaclasses are?

You will very seldom need to define a metaclass of your own.

恬淡成诗 2024-09-02 10:37:16

当创建新类(而不是实例)时,将使用元类。通过这种方式,您可以注册类(django 会执行此操作并使用它在数据库中创建表)。由于 class 是一条指令,您可以将其视为类的装饰器。

Metaclass is used when new class - not instance - is created. This way you can for example register classes (django does it and uses it for example to create tables in the database). Since class is an instruction you can think about as a decorator for a class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文