Reputation: 17900
I have an API class (it will be extended and used by other classes):
class A(object):
def __init__(self, **kwargs):
self.kwargs = kwargs
@classmethod
def create(cls, **kwargs):
return cls(**kwargs)
It is extended by:
class B(A):
pass
Now, this is what I want: if I instantiate class B like B(arg1=1, arg2=2)
I would like to do some additional operations when initializing it, like validate the kwargs
arguments (and this code should reside in class A, not in B). Then, if I do B.create(arg1=1, arg2=2)
, that validation should not occur.
In short, I would like to do extra operations when initializing an object only from the outside of the class it was defined; initalizing an object from a classmethod inside its class should not trigger any extra operation.
Upvotes: 1
Views: 55
Reputation: 1541
If your "extra operations" are in the constructor then I'm afraid they'll always get run, regardless of whether you instantiate directly or through a factory. You could consider only allowing object creation through a set of factory methods (some with validation and some without).
class A(object):
def __init__(self, **kwargs):
self.kwargs = kwargs
#no extra stuff
@classmethod
def create_with_extra_stuff(cls, **kwargs):
c = cls(**kwargs)
c.extra_stuff()
return c
@classmethod
def create_withuot_extra_stuff(cls, **kwargs):
return cls(**kwargs)
@classmethod
def create(cls, with_extra_stuff = False, **kwargs):
if with_extra_stuff:
return cls.create_with_extra_stuff(**kwargs)
else:
return cls.create_without_extra_stuff(**kwargs)
Of course, I don't know your full use case but factory patterns are pretty much designed for this sort of thing.
This section was added after the comments were made:
class A(object):
def __init__(self, do_extra_stuff = True, **kwargs):
if do_extra_stuff:
self.do_extra_stuff(**kwargs)
self.kwargs = kwargs
@classmethod
def create(cls, **kwargs):
return cls(do_extra_stuff = False, **kwargs)
Further edit showing alternative:
class A(object):
def __init__(self, **kwargs):
#lightweight constructor
self.kwargs = kwargs
def validate(self):
#Does not alter class variables. That would be bad in this case
#Do stuff with self.kwargs
@classmethod
def create(cls, **kwargs):
return cls(**kwargs)
main():
a = A({...})
a.validate()
b = A.create({...})
#b.validate() not called
The point is that the constructor will be called on construction. The trick then is to decide what additional stuff needs to be selective called.
Upvotes: 1
Reputation: 22561
You can use additional argument to distinguish method of class initialisation:
class A(object):
def __init__(self, __a_validate=True, **kwargs):
self.kwargs = kwargs
if __a_validate:
print 'do validation'
@classmethod
def create(cls, **kwargs):
return cls(__a_validate=False, **kwargs)
Demo:
>>> B.create(arg1=1, arg2=2)
<__main__.B object at 0x9b82f4c>
>>> B(arg1=1, arg2=2)
do validation
<__main__.B object at 0x9b7bbcc>
update for comments:
This is another solution. You can modify class attribute in create
method, for example set validate
function to None
, call constructor and then set validate
back to original state:
class A(object):
def __init__(self, **kwargs):
self.kwargs = kwargs
if self.validate:
self.validate(kwargs)
def validate(self, kwargs):
print 'do validation'
@classmethod
def create(cls, **kwargs):
tmp = cls.validate
cls.validate = None
instance = cls(**kwargs)
cls.validate = tmp
return instance
Upvotes: 1