0

I want set a pattern observer on my class property

I try to use @classmethod but it doesn't have setter property.

class dataframe():
    df = None
    @classmethod
    @property
    def weather(cls):
        return cls.df
    @classmethod
    @weather.setter
    def weather(cls,value):
        cls.df= value
        print("the weath was change {}".format(cls.df))
<ipython-input-119-7e26ac08cb26> in dataframe()
      6         return cls.df
      7     @classmethod
----> 8     @weather.setter
      9     def weather(cls,value):
     10         cls.df= value

AttributeError: 'classmethod' object has no attribute 'setter'

Then I tried to adapt the solution I found there to my problem Using property() on classmethods

class dataframe_meta(type):
    def __init__(cls, *args, **kwargs):
        cls.df = None

    @property
    def change(cls):
        return cls.df

    @change.setter
    def change(cls, value):
        cls.df = value
        print("the weath was change {}".format(cls.df))

class dataframe(metaclass=dataframe_meta):
    pass

dataframe.df = 5 It doesn't return any error but the print from the function setter was not displayed.

How make it work properly?

martineau
  • 119,623
  • 25
  • 170
  • 301
Chrys Bltr
  • 68
  • 3
  • 13
  • This answer in the question you linked might be more helpful to you https://stackoverflow.com/a/39542816/548562 – Iain Shelvington Oct 07 '19 at 00:44
  • 1
    You won't see the print statement because you're not calling the setter, you're modifying the member directly. `dataframe.change = 5` would display the print statement you're looking for. That being said, I'm not sure the general approach is the best but it's hard to say without knowing more. – jedwards Oct 07 '19 at 00:44

2 Answers2

1

If you'd like to watch changes made to the df property, you should name the method df, and name the attribute that stores the actual value of df something else, such as _df:

class dataframe_meta(type):    
    def __init__(cls, *args, **kwargs):
        cls._df = None

    @property
    def df(cls):
        return cls._df

    @df.setter
    def df(cls,value):
        cls._df= value
        print("the weath was change {}".format(cls._df))
blhsing
  • 91,368
  • 6
  • 71
  • 106
0

The code you posted,


class dataframe_meta(type):
    def __init__(cls, *args, **kwargs):
        cls.df = None

    @property
    def change(cls):
        return cls.df

    @change.setter
    def change(cls, value):
        cls.df = value
        print("the weath was change {}".format(cls.df))

class dataframe(metaclass=dataframe_meta):
    pass

will work as is - however, you named the property change not df - if you do dataframe.change = 5 you will see the print.

The access to dataframe.df itself is unguarded, however.

If you want dataframe.df itself to trigger the getter/setter methods, you have to name the property itself df, and store the result in an attribute with another name. And yes, metaclasses are a straightforward way for "property" to work on class attributes.

jsbueno
  • 99,910
  • 10
  • 151
  • 209