Is there a way to create subclasses on the fly?

I am creating a game in which I have a somewhat complicated method for creating entities.

When the layer is loaded, the boot code reads a bunch of YAML files that contain attributes of all the different possible units. Using a YAML file, it creates a so-called EntityResource object. This EntityResource object serves as an authoritative source of information at the birth of new units. The goal is twofold:

  • Cheating Deter implementing a hash check on the output of a YAML file
  • Help in debugging, having all the information about the device, comes from one, authoritative source.

These EntityResource objects EntityResource then passed to the EntityFactory object to create units of a specific type.

My question is the following. Is there a way to dynamically create EntityResource EntityResource based on the contents of the YAML file that is being read?

In addition, I would like for each of these subclasses related to the YAML file to be assigned a singleton metaclass. Any reservations?

+4
source share
3 answers

I'm not sure if this is what you are looking for, but you can use type to dynamically subclass:

 SubClass = type('SubClass', (EntityResource,), {}) 

Change To understand how type works, you just need to translate how you would write the class and translate it into a type call. For example, if you want to write something like:

 class SubClass(EntityResource): A=1 B=2 

then it will be translated into:

  SubClass = type('SubClass', (EntityResource,), {'A': 1, 'B': 2}) 

Where:

  • The first argument is just the class name
  • The second argument is a list of parent classes
  • The third argument is that the dictionary initializes the class object. This includes not only class attributes, but also methods.
+21
source

You can subclass on the fly. This does not mean that you should. In any case, I will provide a mechanism.

The base attribute in each class indicates an inheritance chain:

 class Animal(object): pass class Dog(Animal): pass print Animal.__bases__ print Dog.__bases__ # prints: #(<type 'object'>,) #(<class '__main__.Animal'>,) 

So __bases__ is a tuple with the "basics of inheritance". You can replace this tuple (you cannot "attach to it" or "jump out of it" because it is a tuple and the tuples are immutable). For example, let's say that you have a mixin class that adds functionality to some animal subclasses, but not others:

 class Animal(object): pass class Dog(Animal): pass class Cat(Animal): pass class TalkMixin(object): def talk(self): print("I talk like a {0}".format(self.__class__.__name__)) if __name__ == "__main__": dog = Dog() cat = Cat() try: dog.talk() cat.talk() except AttributeError: print("Great - the program raised AttributeError, as expected") # now, add the MixIn to the class "Dog", but not to the class # "Cat" - do this on the fly: old_dog_bases = Dog.__bases__ Dog.__bases__ = (Animal, TalkMixin) # this should be successful! dog.talk() try: cat.talk() except AttributeError: print("As expected, cat.talk() raised AttributeError") # now do the same (add the mixin dynamically - via inheritance) to # the Cat old_cat_bases = Cat.__bases__ Cat.__bases__ = (Animal, TalkMixin) # this should be successful! cat.talk() # Now, remove the mixin (drop from the inheritance) for both cats # and dogs: Dog.__bases__ = old_dog_bases Cat.__bases__ = old_cat_bases try: dog.talk() cat.talk() except AttributeError: print("as expected, they can no longer talk") 

It produces the following output:

 Great - the program raised AttributeError, as expected I talk like a Dog As expected, cat.talk() raised AttributeError I talk like a Cat as expected, they can no longer talk 

Many people consider MixIn classes to be evil. And they may be right! You can imagine that if you mess up the base attribute, you pretty much destroyed your program. So here it is: you can dynamically change the inheritance of an object, but that doesn’t mean what you should (perhaps abstract classes or an implementation of concepts?)

+2
source

When I hear “subclassing on the fly,” I understand that “create objects that behave differently on the fly,” which is really a configuration issue.

Is there anything you need that you cannot get by simply reading some data and creating an object that decides how it will behave based on what it reads?

Here is a metaphor: I am a convenient guy, I can collect any IKEA element that you throw on me. But every time I’m not a different person, I’m just the same convenient guy who reads a different set of diagrams and looks for different screws and pieces of wood. That my reasoning for the subclass is not a natural solution here.

+1
source

Source: https://habr.com/ru/post/1396316/


All Articles