Reputation: 9272
I want to have some instances of a class, MyClass
, which share some constant properties read from file, but also have properties with values unique to the instance. However, I want to read file only once for all instances.
Something like
config.json
{
"a": 1,
"b": 2,
}
Then classes definition:
class MyBaseClass:
def __new__(cls):
with open('config.json', 'r') as f:
for key, value in json.load(f).items():
setattr(cls, key, value)
class MyClass(MyBaseClass):
def __init__(self, param):
self.c = param
And when I initialize instances of MyClass
, I want
inst1 = MyClass("One")
inst2 = MyClass("Two")
to have inst1.c
is One
and inst2.c
is Two
. But I want to achieve that in a way so that MyBaseClass reads data from config.json
only once. Like in a singleton. How can I do it?
Upvotes: 3
Views: 52
Reputation: 114230
You have most of the framework already there. There are a number of pieces of code that run when a class is first created. The simplest one to use is the class body itself. You could use it to create a class variable containing the attributes you wanted with a snippet like the one you show here:
class MyBaseClass:
with open('config.json', 'r') as f:
attributes = json.load(f)
def __new__(cls):
self = super().__new__(cls)
self.__dict__.update(cls.attributes)
Any name in the class namespace that remains after the class is run becomes a class variable, not just methods. Updating a dictionary will only work if you have a regular class that doesn't use slots or have conflicting properties. In those cases, use your setattr
loop in __new__
.
Upvotes: 1
Reputation: 402263
You can define MyBaseClass
to be a metaclass, so this is done just once.
>>> class MyBaseClass(type):
... def __new__(cls, name, bases, dct):
... x = super().__new__(cls, name, bases, dct)
... print('In metaclass')
... with open('config.json', 'r') as f:
... for key, value in json.load(f).items():
... setattr(x, key, value)
... return x
...
>>>
And now, specify MyBaseClass
as a metaclass of MyClass
.
>>> class MyClass(metaclass=MyBaseClass):
... def __init__(self, param):
... self.c = param
...
In metaclass
>>>
When MyClass
is defined, that invokes MyBaseClass.__new__
method just once. Now,
>>> inst1 = MyClass("One")
>>> inst2 = MyClass("Two")
Will result in the two instances being created without any further reads for config.json
.
Upvotes: 1