Search code examples
pythondecoratorpython-decoratorsmetaclass

Possible to call stateful function in a class in Python?


Is it possible to directly set a certain value and get it in a class by any mean(inheritance, metaclass, class decorator) in Python? class B must not be polluted by set('a') in A.

import sys


class A:
    set('a')
    get()
    # -> 'a'

    print(sys.modules[__name__])
    # => <module '__main__'>


class B:
    get()
    # -> None

Solution

  • Assuming you know what you are doing, yes, it is possible to set values with programmatic names in a class body, and retrieve then, and have these values restricted to that class body.

    All you have to do is to use thelocals() call to get the namespace dictionary, and use that dictionary to hold your values:

    class A:
        locals()["key"] = "a"
        print(locals()["key"] )
    

    This will print "a", and obviously, this value won't be part of a class B namespace.

    If you want just to store values without associating then with a name, the stackfull project provide a push and pop calls that will behave just like you proposed in your example - but if you try a pop() withour a previous push in the same scope, you will get an error due to a stack underflow:

    
    In [4]: !pip install stackfull                                                                 
    Collecting stackfull
    ...
    Successfully installed stackfull-1.0.0
    
    
    In [5]: from stackfull import push, pop                                                        
    
    In [6]: class A: 
       ...:     push("a") 
       ...:     push("b") 
       ...:     print(pop()) 
       ...:     print(pop()) 
       ...:                                                                                        
    b
    a
    In [7]: class B: 
       ...:     pop() 
       ...:   
    ...
    StackUnderflowError:
    

    (Disclaimer - I am the author of the stackfull package. I never really needed anything beyond what is already there, so it has not been updated in a long time - and with the "walrus" operator in Python 3.8, it is no longer that useful)

    Ok - so I listed this because it resembles the code in your question, but chances are you need something more mainstream, like writing your code in methods, and set instance attributes.