Reputation: 11639
I have a class like this:
class Metrics:
meters = {}
for subscription in SUBSCRIPTION_TYPES:
meters[subscription] = metrics.new_meter(subscription)
@staticmethod
def get_meter_data(field, key):
return Metrics.meters[field].get()[key]
@staticmethod
def track(subscription, value):
Metrics.meters[subscription].notify(value)
gauge_for_passport.set_function(lambda: Metrics.meters[subscription].get()["count"])
basically, I only want the meters dictionary to be initialized once since it's going to be keeping track of certain events in my app so I have the for
loop right in the class body. Is this the right way to do this?
should I also use a classmethod
so I can use cls
and pass the class itself to the method instead of calling Metrics
directly?
Upvotes: 2
Views: 56
Reputation: 45241
Classes are "initialized" at the point in time the module is run. So when you write this:
# my_module.py
class Metrics:
meters = {}
for subscription in SUBSCRIPTION_TYPES:
meters[subscription] = metrics.new_meter(subscription)
...the for loop executes when my_module is imported.
It sounds to me like what you really want is a module, not a class. There is only one instance of any given module.
# metrics.py module
meters = {}
for subscription in SUBSCRIPTION_TYPES:
meters[subscription] = new_meter(subscription)
def get_meter_data(field, key):
return meters[field].get()[key]
def track(subscription, value):
meters[subscription].notify(value)
gauge_for_passport.set_function(lambda: meters[subscription].get()["count"])
When you want it "instantiated", you just import it:
# other_module.py
import metrics
If you really don't want this module in a separate file, there are ways of dynamically creating a module inside of another module. But honestly, it probably isn't worth the trouble, and I'm not even sure how you would write the module but also delay its execution.
One other option to delay class creation might be to write a class factory, which is a pythonic approach and might make sense depending on your use case:
def get_metrics():
class Metrics:
meters = {}
for subscription in SUBSCRIPTION_TYPES:
meters[subscription] = metrics.new_meter(subscription)
@staticmethod
def get_meter_data(field, key):
return Metrics.meters[field].get()[key]
@staticmethod
def track(subscription, value):
Metrics.meters[subscription].notify(value)
gauge_for_passport.set_function(lambda: Metrics.meters[subscription].get()["count"])
return Metrics
In this way, you can control when the class is run. But your example code really doesn't look like much of a class to me; it looks like a bunch of tools that belong in a namespace together.
Back to the idea of dynamic module creation: you could pair these two ideas together and do something like this:
from types import ModuleType
def init_metrics_module():
"""This is a function to delay creation of the module below."""
meters = {}
for subscription in SUBSCRIPTION_TYPES:
meters[subscription] = new_meter(subscription)
def get_meter_data(field, key):
return meters[field].get()[key]
def track(subscription, value):
meters[subscription].notify(value)
gauge_for_passport.set_function(lambda: meters[subscription].get()["count"])
# create module
module_dict = locals().copy()
metrics = ModuleType("metrics")
metrics.__dict__.update(module_dict)
return metrics
Then when you want it:
metrics = init_metrics_module()
type(metrics) # <class 'module'>
Upvotes: 3