简体   繁体   中英

Make subclass have its own class attribute

I have an class Generic

class Generic:
    raw_data = []
    objects = dict()

and concrete classes

class A(Generic):
    raw_data = module.somethingA

class B(Generic):
    raw_data = module.somethingB

I want to populate each raw_data onto each objects dict of the class. To that, I'm running:

for object_type in (A, B):
     for data in object_type.raw_data:
         new_object = object_type(*data)
         object_type.objects[id(new_object)] = new_object

However, this does not work because objects is shared between A and B , and I wanted each subclass of Generic to have their own objects.

How do I achieve this without having to type objects = dict() on every subclass?

I'm inclined to say that this is a traditional case where a meta class is required (that adds objects to each new class); is this the case, or is there a simpler option?

Either use a metaclass or use a class decorator.

A class decorator could simply create the attribute:

def add_objects(cls):
    cls.objects = {}
    return cls

@add_objects
class A(generic):
    raw_data = module.somethingA

This doesn't really add anything however; you just replace one line ( objects = {} ) with another ( @add_objects ).

You could just add the object in your loop:

for object_type in (A, B):
     if 'objects' not in vars(object_type):
         object_type.objects = {}
     for data in object_type.raw_data:
         new_object = object_type(*data)
         object_type.objects[id(new_object)] = new_object

or copy it (reading the attribute may retrieve the parent class attribute or a direct attribute, it doesn't matter here):

for object_type in (A, B):
     object_type.objects = object_type.objects.copy()
     for data in object_type.raw_data:
         new_object = object_type(*data)
         object_type.objects[id(new_object)] = new_object

or create the dictionary from scratch:

for object_type in (A, B):
     object_type.object = {
         id(new_object): new_object
         for data in object_type.raw_data
         for new_object in (object_type(*data),)}

I don't think a metaclass is necessary here. Why not just copy the parent class objects before populating each subclass in your loop?

for object_type in (A, B):
     # copy Generic.objects onto object_type.objects here
     object_type.objects = Generic.objects.copy()
     for data in object_type.raw_data:
         new_object = object_type(*data)
         object_type.objects[id(new_object)] = new_object

Additionally you can modify to use super and/or deepcopy if you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM