Can I implement a class method dynamically in Python?
Question:
In Python, it’s no secret that you can implement attributes of an instance of a class dynamically. Here’s what that looks like:
class MyClass(object):
def __getattribute__(self, name):
if name == 'dynamic_attribute':
return "dynamic attribute value"
return super().__getattribute__(name)
# Create an instance of my class
obj = MyClass()
# I've implemented the 'dynamic_attribute' attribute dynamically, so I can
# reference it without ever having assigned it a value
print(obj.dynamic_attribute)
# As I've only implemented that one attribute dynamically, other attributes
# behave in the standard way
try:
print(obj.regular_attribute)
except AttributeError as ex:
print(f"EXPECTED ERROR: {ex}")
obj.regular_attribute = "regular attribute value"
print(obj.regular_attribute)
Result:
dynamic attribute value
EXPECTED ERROR: 'MyClass' object has no attribute 'regular_attribute'
regular attribute value
Is there any way to do this same thing with a class attribute rather than a class instance attribute? Here’s an example:
print(MyClass.dynamic_class_attribute)
I want this line of code to return a value that is computed somewhere in my code without me having to have defined a ‘dynamic_class_attribute’ attribute explicitly on the MyClass class. Can this be done? TIA.
PS: I’ve never done anything with metaclasses, but I know of their existence. I read up a little on them hoping for an obvious answer to this question. I didn’t find one.
UPDATE:
Someone asked why I wanted this. Maybe others would find my use case interesting. I was basically just being a bit anal about simplifying an API I’m creating. It isn’t quite as simple as this, but it’s basically a singleton thing, and all I’m really doing is trying to replace this:
SomeSingletonClass.get().some_method()
with this:
SomeSingletonClass.some_method()
At any moment, there’s exactly one SomeSingletonClass instance, and I reference that instance a lot, so I wanted to simplify the global reference to it as much as possible. With Raymond H’s answer, I did it. It works great.
Answers:
Is there any way to do this same thing with a class attribute rather than a class instance attribute?
Yes, just move the logic into a metaclass:
class MyMetaClass(type):
def __getattribute__(self, name):
if name == 'dynamic_attribute':
return "dynamic attribute value"
return super().__getattribute__(name)
class C(metaclass=MyMetaClass):
pass
print(C.dynamic_attribute)
The basic idea is that regular classes control the behavior of instances and metaclasses control the behavior of classes.
In Python, it’s no secret that you can implement attributes of an instance of a class dynamically. Here’s what that looks like:
class MyClass(object):
def __getattribute__(self, name):
if name == 'dynamic_attribute':
return "dynamic attribute value"
return super().__getattribute__(name)
# Create an instance of my class
obj = MyClass()
# I've implemented the 'dynamic_attribute' attribute dynamically, so I can
# reference it without ever having assigned it a value
print(obj.dynamic_attribute)
# As I've only implemented that one attribute dynamically, other attributes
# behave in the standard way
try:
print(obj.regular_attribute)
except AttributeError as ex:
print(f"EXPECTED ERROR: {ex}")
obj.regular_attribute = "regular attribute value"
print(obj.regular_attribute)
Result:
dynamic attribute value
EXPECTED ERROR: 'MyClass' object has no attribute 'regular_attribute'
regular attribute value
Is there any way to do this same thing with a class attribute rather than a class instance attribute? Here’s an example:
print(MyClass.dynamic_class_attribute)
I want this line of code to return a value that is computed somewhere in my code without me having to have defined a ‘dynamic_class_attribute’ attribute explicitly on the MyClass class. Can this be done? TIA.
PS: I’ve never done anything with metaclasses, but I know of their existence. I read up a little on them hoping for an obvious answer to this question. I didn’t find one.
UPDATE:
Someone asked why I wanted this. Maybe others would find my use case interesting. I was basically just being a bit anal about simplifying an API I’m creating. It isn’t quite as simple as this, but it’s basically a singleton thing, and all I’m really doing is trying to replace this:
SomeSingletonClass.get().some_method()
with this:
SomeSingletonClass.some_method()
At any moment, there’s exactly one SomeSingletonClass instance, and I reference that instance a lot, so I wanted to simplify the global reference to it as much as possible. With Raymond H’s answer, I did it. It works great.
Is there any way to do this same thing with a class attribute rather than a class instance attribute?
Yes, just move the logic into a metaclass:
class MyMetaClass(type):
def __getattribute__(self, name):
if name == 'dynamic_attribute':
return "dynamic attribute value"
return super().__getattribute__(name)
class C(metaclass=MyMetaClass):
pass
print(C.dynamic_attribute)
The basic idea is that regular classes control the behavior of instances and metaclasses control the behavior of classes.