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

2 answers

  • answered 2020-05-29 18:26 Sam

    These two independent classes don't reference each other, so as long as you don't pass the same object to both, then neither will 'pollute' the other. To set a value and get a value on an object, you could use something like this:

    class A:
        def __init__(self):
            self.letter = None
        def set_value(self, letter):
            self.letter = letter
        def get_value(self):
            return self.letter if self.letter else '(none set)'
    
    class B:
        def __init__(self):
            self.letter = None
        def set_value(self, letter):
            self.letter = letter
        def get_value(self):
            return self.letter if self.letter else '(none set)'
    
    >>> a = A()
    >>> aa = A()
    >>> b = B()
    >>> a.set_value('z')
    >>> print(f'values in a, aa, and b are: {a.get_value()}, {aa.get_value()}, {b.get_value()}')
    values in a, aa, and b are: z, (none set), (none set)
    

    So as you can see, setting the a object's letter doesn't set it in b (a different class), or in aa, which is a different instance of the same A class. Hope that helps!

    Happy Coding!

  • answered 2020-05-30 02:26 jsbueno

    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.