Assigning class variable dynamic value from inside

2019-08-03 19:18发布

问题:

I am trying to dynamically assign a class variable a value from inside of a class.

class Test:
  dynamic_value = get_dynamic_value()

I believe get_dynamic_value() should belong to the Test class. Is there a way to have Test contain this method?

Right now I am using and it is working

def get_dynamic_value():
  return 'my dynamic value'

class Test:
  dynamic_value = get_dynamic_value()

I would like for Test to contain this method so I have tried to make it both a @classmethod and a @staticmethod and calling it by

class Test:
  dynamic_value = Test.get_dynamic_value()

  @staticmethod
  def get_dynamic_value():
    return 'dynamic'

But when trying it using a static method I receive

AttributeError: class Test has no attribute 'get_dynamic_value'

Is there any way to do this? Or is there a better way to handle this?

回答1:

Class suites evaluate from top to bottom, and the class you are defining does not exist until after the entire suite is evaluated.

You can put the function definition inside the class body, but you've got to call it after it's been defined, not before. So, this will work:

class Test:

  def get_dynamic_value():
    return 'dynamic'

  dynamic_value = get_dynamic_value()

Marking the function as a staticmethod is not necessary; it's not used as a method at all, just a function that is called during the evaluation in the class suite. If you don't want the function to be available after the class is defined (as it isn't intended as a method), you can delete it.

class Test:

  def get_dynamic_value():
    return 'dynamic'

  dynamic_value = get_dynamic_value()
  del get_dynamic_value

If the value is really supposed to be dynamically calculated, every time you ask for it (so it is able to change from access to access), then you should use a property.

class Test:

  @property
  def dynamic_value(self):
    return 'dynamic'

This would only be evaluate when accessed on a class instance, but the property object itself would exist on the class.



回答2:

Just to add to Matt Anderson's answer - a workaround with class property:

class classproperty(property):
    def __get__(self, cls, owner):
        return classmethod(self.fget).__get__(None, owner)()

class Test:
  @classproperty
  def dynamic_value(cls):
    return 'dynamic'

And a simple test:

In [102]: Test.dynamic_value
Out[102]: 'dynamic'