Automatically setting class class variables in Python

Let's say I have the following class in Python

class Foo(object): a = None b = None c = None def __init__(self, a = None, b = None, c = None): self.a = a self.b = b self.c = c 

Is there a way to simplify this process? Whenever I add a new member to the Foo class, I am forced to change the constructor.

+29
python constructor
Oct 07 '10 at 18:18
source share
4 answers

note that

 class Foo(object): a = None 

sets a key-value pair in a Foo dict:

 Foo.__dict__['a']=None 

but

 def __init__(self, a = None, b = None, c = None): self.a = a 

sets the key-value pair in the Foo dict instance object:

 foo=Foo() foo.__dict__['a']=a 

Therefore, setting class members at the top of your definition is not directly related to setting instance attributes in the bottom half of your definition (inside __init__ .

Also, it's good to know that __init__ is a Python initializer. __new__ is a class constructor.




If you are looking for a way to automatically add instance attributes based on __init__ arguments, you can use this:

 import inspect import functools def autoargs(*include,**kwargs): def _autoargs(func): attrs,varargs,varkw,defaults=inspect.getargspec(func) def sieve(attr): if kwargs and attr in kwargs['exclude']: return False if not include or attr in include: return True else: return False @functools.wraps(func) def wrapper(self,*args,**kwargs): # handle default values for attr,val in zip(reversed(attrs),reversed(defaults)): if sieve(attr): setattr(self, attr, val) # handle positional arguments positional_attrs=attrs[1:] for attr,val in zip(positional_attrs,args): if sieve(attr): setattr(self, attr, val) # handle varargs if varargs: remaining_args=args[len(positional_attrs):] if sieve(varargs): setattr(self, varargs, remaining_args) # handle varkw if kwargs: for attr,val in kwargs.iteritems(): if sieve(attr): setattr(self,attr,val) return func(self,*args,**kwargs) return wrapper return _autoargs 

So when you say

 class Foo(object): @autoargs() def __init__(self,x,path,debug=False,*args,**kw): pass foo=Foo('bar','/tmp',True, 100, 101,verbose=True) 

you automatically get these instance attributes:

 print(foo.x) # bar print(foo.path) # /tmp print(foo.debug) # True print(foo.args) # (100, 101) print(foo.verbose) # True 

PS. Although I wrote this (for fun), I do not recommend using autoargs for serious work. Being explicit is simple, clear, and infallible. I can not say the same for autoargs .

PPS Is it just me, or are there many buttons crashed on stackoverflow? The editor window has lost all its icons ...: ( Fixed a bug with clearing the browser cache.

+30
Oct 07 '10 at 18:20
source share

There is an elegant way to do this.

Is there a way to simplify this process? Whenever I add a new member to the Foo class, I am forced to change the constructor.

There is also a rough path. It will work, but is NOT recommended. See and decide.

 >>> class Foo(object): def __init__(self, **attrs): self.__dict__.update(**attrs) def __getattr__(self, attr): return self.__dict__.get(attr, None) >>> f = Foo(a = 1, b = 2, c = 3) >>> fa, fb (1, 2) >>> f = Foo(bar = 'baz') >>> f.bar 'baz' >>> fa >>> 

The keyword argument constructor allows you to do without explicitly defining any arguments. Warning : this contradicts the principle of "explicit is better than implicit."

You need to override __getattr__ ONLY if you want to return the default value for an attribute that is missing instead of receiving an AttributeError .

+12
Oct 07 2018-10-10
source share

Python 3.7 provides dataclasses that are useful in situations like this:

 from dataclasses import dataclass @dataclass class Foo: a: str = None b: str = None c: str = None 

This eliminates the need to write the __init__ method when you just want to keep multiple attributes.

Gives you a nice __repr__ method:

 >>> a = Foo() >>> a Foo(a=None, b=None, c=None) 
+1
Aug 16 '19 at 15:58
source share

http://code.activestate.com/recipes/286185-automatically-initializing-instance-variables-from/

This recipe and its comments provide some methods.

Python: automatically initialize instance variables?

This is the previous question.

-one
Oct 07 '10 at 18:21
source share



All Articles