我知道类是元类的实例,并且 __new__
在 __init__
之前运行,因为,您必须在初始化它之前创建一个实例。
现在想象一下:
import time
class ConfigurationsMeta(type):
def __new__(cls, name, bases, attr):
# Potentially a long task here (eg: Getting value from a web service)
time.sleep(2)
# Which class inherit from me (debug)
print(f'Class {name}')
config = super().__new__(cls, name, bases, attr)
#Set a variable to be propagated (Variable coming from web service)
setattr(config, "URL", "https://stackoverflow.com/")
return config
class Foo(metaclass=ConfigurationsMeta):
def __init__(self):
print(f'{__class__.__name__} : {self.URL}')
class Bar(Foo):
def __init__(self):
print(f'{__class__.__name__} : {self.URL}')
class Baz(Bar):
def __init__(self):
print(f'{__class__.__name__} : {self.URL}')
e = Foo()
s = Bar()
c = Baz()
很好,因为 URL 传播得很好,就像我所做的那样
Foo : https://stackoverflow.com/ Bar : https://stackoverflow.com/ Baz : https://stackoverflow.com/
我现在确实有一些不太明白的事情:
Class Foo
在 2 秒后写入Class Bar
在另外 2 秒后写入Baz类
又过了2秒终于写入了
所以元类被执行了三次。
这必须说明,由于 __new__
负责创建类,所以每次都必须运行它,所以运行三次。
我说得对吗?
如何避免它并使其仅运行一次?
最佳答案
这里实际上并不需要元类。假设您希望 URL
成为 class 属性,而不是实例属性,则只需使用合适的 __init_subclass__
定义来定义基类。应首先检索 URL 并将其作为参数传递给 __init_subclass__
(通过 class
语句中的关键字参数)。
class Base:
def __init_subclass__(cls, /, url=None):
super().__init_subclass__(cls)
if url is not None:
cls.URL = url
some_url = call_to_webservice()
class Foo(Base, url=some_url):
pass
class Bar(Foo):
pass
class Baz(Bar):
pass
如果 URL
应该是实例属性,则将 __init_subclass__
替换为 __init__
:
some_url = call_to_webservice()
class Base:
def __init__(self, /, url):
self.url = url
class Foo(Base):
pass
f = Foo(some_url)
关于python - 避免每次都调用 __new__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59881445/