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 any way to simplify this process? Whenever I add a new member to class Foo, I'm forced to modify the constructor.
For Python 3.7+ you can use a Data Class, which is a very pythonic and maintainable way to do what you want. It allows you to define fields for your class, which are your automatically initialized instance variables.
Use dot notation or setattr() function to set the value of class attribute. Python is a dynamic language. Therefore, you can assign a class variable to a class at runtime. Python stores class variables in the __dict__ attribute.
The variables that are defined inside the methods can be accessed within that method only by simply using the variable name. Example – var_name. If you want to use that variable outside the method or class, you have to declared that variable as a global. def access_method( self ):
Create Instance Variables Instance variables are declared inside a method using the self keyword. We use a constructor to define and initialize the instance variables. Let's see the example to declare an instance variable in Python.
Please note that
class Foo(object): a = None
sets a key-value pair in Foo
's dict:
Foo.__dict__['a']=None
while
def __init__(self, a = None, b = None, c = None): self.a = a
sets a key-value pair in the Foo instance object's dict:
foo=Foo() foo.__dict__['a']=a
So setting the class members at the top of your definition is not directly related to the setting of the instance attributes in the lower half of your definition (inside the __init__
.
Also, it is good to be aware that __init__
is Python's initializer. __new__
is the class constructor.
If you are looking for a way to automatically add some instance attributes based on __init__
's arguments, you could 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 don't recommend using autoargs
for serious work. Being explicit is simple, clear and infallible. I can't say the same for autoargs
.
PPS. Is it just me, or are a lot of buttons broken on Stackoverflow? The editor window has lost all its icons... :( Clearing the browser cache fixed the problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With