Finding static class attributes in Python

This is an unusual question, but I would like to dynamically generate a __slots__class attribute based on any attributes that I managed to add to the class.

For example, if I have a class:

class A(object):
    one = 1
    two = 2

    __slots__ = ['one', 'two']

I would like to do this dynamically, rather than specifying the arguments manually, how would I do this?

+3
source share
2 answers

While you are trying to define slots , the class has not yet been created, so you cannot define it dynamically from class A.

To obtain the desired behavior, use the metaclass to introspect the definition of A and add the slot attribute.

class MakeSlots(type):

    def __new__(cls, name, bases, attrs):
        attrs['__slots__'] = attrs.keys()

        return super(MakeSlots, cls).__new__(cls, name, bases, attrs)

class A(object):
    one = 1
    two = 2

    __metaclass__ = MakeSlots
+3
source

, - , __slots__ ... , , - ; , , .

- : ", , ". ! :

class B(object):
    three = None
    four = None

    temp = vars()                    # get the local namespace as a dict()
    __slots__ = temp.keys()          # put their names into __slots__
    __slots__.remove('temp')         # remove non-__slots__ names
    __slots__.remove('__module__')   # now remove the names from the local
    for name in __slots__:           # namespace so we don't get read-only
        del temp[name]               # class attributes
    del temp                         # and get rid of temp

, ... :

class B(object):
    three = 3
    four = 4

    def __init__(self):
        for key, value in self.__init__.defaults.items():
            setattr(self, key, value)

    temp = vars()
    __slots__ = temp.keys()
    __slots__.remove('temp')
    __slots__.remove('__module__')
    __slots__.remove('__init__')
    __init__.defaults = dict()
    for name in __slots__:
        __init__.defaults[name] = temp[name]
        del temp[name]
    del temp

, , ? :

class MakeSlots(type):
    def __new__(cls, name, bases, attrs):
        new_attrs = {}
        new_attrs['__slots__'] = slots = attrs.keys()
        slots.remove('__module__')
        slots.remove('__metaclass__')
        new_attrs['__weakref__'] = None
        new_attrs['__init__'] = init = new_init
        init.defaults = dict()
        for name in slots:
            init.defaults[name] = attrs[name]
        return super(MakeSlots, cls).__new__(cls, name, bases, new_attrs)

def new_init(self):
    for key, value in self.__init__.defaults.items():
        setattr(self, key, value)

class A(object):
    __metaclass__ = MakeSlots

    one = 1
    two = 2


class B(object):
    __metaclass__ = MakeSlots

    three = 3
    four = 4

, (,!) .

- , , mixin, - .

+1

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


All Articles