Home > database >  Can I implement a class method dynamically in Python?
Can I implement a class method dynamically in Python?

Time:08-28

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.

CodePudding user response:

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.

  • Related