简体   繁体   中英

how do you automate setting self attributes in init of python class?

I'd like to automate unpacking init variables once and for all. My thought process is to unpack all and use setattr with the name of the variable as the attribute name.

class BaseObject(object):
    def __init__(self, *args):
        for arg in args:
            setattr(self, argname, arg)

class Sub(BaseObject):
    def __init__(self, argone, argtwo, argthree, argfour):
        super(Sub, self).__init__(args*)

Then you should be able to do:

In [3]: mysubclass = Sub('hi', 'stack', 'overflow', 'peeps')

In [4]: mysubclass.argtwo
Out[4]: 'stack'

Based on the param for 'stack' having been named argtwo .

This way you'll automatically have access but you could still override like below:

class Sub(BaseObject):
    def __init__(self, argone, argtwo, argthree, argfour):
        super(Sub, self).__init__(arglist)
        clean_arg_three = process_arg_somehow(argthree)
        self.argthree   = clean_arg_three

Clearly I'm stuck on how to pass the actual name of the param (argone, argtwo, etc) as a string to setattr , and also how to properly pass the args into the super init (the args of super(Sub, self).__init__(args*) )

Thank you

Use kwargs instead of args

class BaseObject(object):
    def __init__(self, **kwargs):
        for argname, arg in kwargs.iteritems():
            setattr(self, argname, arg)

class Sub(BaseObject):
    def __init__(self, argone, argtwo, argthree, argfour):
        super(Sub, self).__init__(argone=argone, argtwo=argtwo,   argthree=argthree)

Then you can do:

s = Sub('a', 'b', 'c')
import inspect

class BaseObject(object):
    def __init__(self, args):
        del args['self']
        self.__dict__.update(args)

class Sub(BaseObject):
    def __init__(self, argone, argtwo, argthree, argfour):
        args = inspect.getargvalues(inspect.currentframe()).locals
        super(Sub, self).__init__(args)

s = Sub(1, 2, 3, 4)

BaseObject.__init__() needs to discover the names of the arguments to Sub.__init__() somehow. The explicit approach would be to pass a dictionary of arguments to BaseObject.__init__() , as Uri Shalit suggested. Alternatively, you can use the inspect module to do this magically, with no extra code in your subclass. That comes with the usual downsides of magic ("how'd that happen?").

import inspect

class BaseObject(object):
    def __init__(self):
        frame = inspect.stack()[1][0]
        args, _, _, values = inspect.getargvalues(frame)
        for key in args:
            setattr(self, key, values[key])

class Sub(BaseObject):
    def __init__(self, argone, argtwo, argthree, argfour):
        super(Sub, self).__init__()

This works fine as written, but if you don't define Sub.__init__() , this will grab the arguments from the wrong place (ie, from the function where you call Sub() to create an object). You might be able to use inspect to doublecheck that the caller is an __init__() function of a subclass of BaseObject . Or you could just move this code to a separate method, eg, set_attributes_from_my_arguments() and call that from your subclasses' __init__() methods when you want this behavior.

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