Python: How to easily copy function parameters to object fields?

Many times I have member functions that copy parameters to the fields of objects. For instance:

class NouveauRiches(object): def __init__(self, car, mansion, jet, bling): self.car = car self.mansion = mansion self.jet = jet self.bling = bling 

Is there a python language construct that would make this code less tedious? You can use * args:

 def __init__(self, *args): self.car, self.mansion, self.jet, self.bling = args 

+: less tiring

-: function signature, not indicative enough. you need to plunge into the functional code to know how to use the function

-: does not raise TypeError when called with the wrong # parameters (but raises a ValueError )

Any other ideas? (Regardless of your suggestion, make sure the code that calls the function remains simple)

+4
source share
7 answers

You can do this with a helper method, something like this:

 import inspect def setargs(func): f = inspect.currentframe(1) argspec = inspect.getargspec(func) for arg in argspec.args: setattr(f.f_locals["self"], arg, f.f_locals[arg]) 

Using:

 class Foo(object): def __init__(self, bar, baz=4711): setargs(self.__init__) print self.bar # Now defined print self.baz # Now defined 

This is not very good, and it should probably be used only when prototyping. Please use an explicit assignment if you plan on others reading it.

It might be better not to use the function as an argument, but that would require even more ugly hacks and cheating :)

+2
source

I would go for it, also you could redefine already defined properties.

 class D: def __init__(self, **kwargs): self.__dict__.update(kwargs) 

But I personally would have come a long way. Think about it:

 - Explicit is better than implicit. - Flat is better than nested. (The Zen of Python) 
+2
source

Try something like

 d = dict(locals()) del d['self'] self.__dict__.update(d) 

Of course, it returns all local variables, not just function arguments.

+1
source

I'm not sure this is such a good idea, but it can be done:

 import inspect class NouveauRiches(object): def __init__(self, car, mansion, jet, bling): arguments = inspect.getargvalues(frame)[0] values = inspect.getargvalues(frame)[3]; for name in arguments: self.__dict__[name] = values[name] 

It doesn't read very well either, although I suppose you could put this in a useful method that is reused.

+1
source

You can try something like this:

 class C(object): def __init__(self, **kwargs): for k in kwargs: d = {k: kwargs[k]} self.__dict__.update(d) 

Or using setattr, you can do:

 class D(object): def __init__(self, **kwargs): for k in kwargs: setattr(self, k, kwargs[k]) 

Both can be called as:

 myclass = C(test=1, test2=2) 

So you should use ** kwargs, not * args.

0
source

I sometimes do this for classes that act "grouped", i.e. they have a bunch of custom attributes:

 class SuperClass(object): def __init__(self, **kw): for name, value in kw.iteritems(): if not hasattr(self, name): raise TypeError('Unexpected argument: %s' % name) setattr(self, name, value) class SubClass(SuperClass): instance_var = None # default value class SubClass2(SubClass): other_instance_var = True @property def something_dynamic(self): return self._internal_var @something_dynamic.setter # new Python 2.6 feature of properties def something_dynamic(self, value): assert value is None or isinstance(value, str) self._internal_var = value 

Then you can call SubClass2(instance_var=[], other_instance_var=False) , and it will work without defining __init__ in any of them. You can also use any property. Although this allows you to rewrite methods that you probably did not intend to (since they will return True for hasattr() as an instance variable).

If you add any property or other descriptor, it will work fine. You can use this for type checking; unlike type checking in __init__ , it will be applied at any time when this value is updated. Note that you cannot use any positional arguments for them unless you override __init__ , so sometimes what would be a natural positional argument will not work. formencode.declarative covers this and other problems, perhaps with care I would not suggest you try (in retrospect, I don't think it's worth it).

Please note that any recipe that uses self.__dict__ will not respect properties and descriptors, and if you use them together, you will get simply strange and unexpected results. I recommend using setattr() to set attributes, never self.__dict__ .

Also, this recipe does not provide a very useful signature, while some of those that perform personnel and functional introspection do. With some work, you can dynamically generate __doc__ , which clarifies the arguments ... but again I'm not sure if the gain is to add more moving parts.

0
source

I am a fan of the following

 import inspect def args_to_attrs(otherself): frame = inspect.currentframe(1) argvalues = inspect.getargvalues(frame) for arg in argvalues.args: if arg == 'self': continue value = argvalues.locals[arg] setattr(otherself, arg, value) class MyClass: def __init__(self, arga="baf", argb="lek", argc=None): args_to_attrs(self) 

The __init__ arguments are explicitly specified, so it’s clear which attributes are set. In addition, it is slightly optimized in accordance with the currently accepted answer.

0
source

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


All Articles