I have the following question - can I use the value of one parameter to define another parameter ? Here's an illustration of what I'm trying to do.
Suppose I have a config file that looks like this:
[MyTaskRunner]
logdir=/tmp/logs
numruns=2
and I defined MyTaskRunner like this:
class MyTaskRunner(luigi.Task):
logdir=luigi.Parameter(default=None)
rundate=luigi.Parameter(default=today)
where logdir is a parameter obtained from the config file and rundate is a parameter that was passed in at runtime.
Now, suppose I wish to define a new variable logpath_str like this
logpath_str="{}/{}".format(logdir, rundate)
Is it possible to define this as a parameter ?
Would the solution be to specify the default value as in:
logpath=luigi.Parameter(default=logpath_str)
Any suggestions welcome.
Parameter values are not resolved until the class has been initialised (during __init__) so a simple way to achieve the behaviour you're looking for is to implement __init__ yourslef and initialise logpath with a default value after calling super.
class MyTaskRunner(luigi.Task):
logdir=luigi.Parameter(default=None)
logpath=luigi.Parameter(default=None)
rundate=luigi.Parameter(default=today)
def __init__(self, *args, **kwargs):
super(MyTaskRunner, self).__init__(*args, **kwargs)
if self.logpath is None:
self.logpath = "{}/{}".format(self.logdir, self.rundate)
Another possibility would be to use the property decorator for this.
class MyTaskRunner(luigi.Task):
logdir=luigi.Parameter(default=None)
rundate=luigi.Parameter(default=today)
#property
def logpath_str():
return "{}/{}".format(self.logdir, self.rundate)
When the property is called, the object is already instantiated and the two necessary variables are initialized and hence properly callable.
Compared to overriding the constructor, you save some unnecessary lines of code. And, personally, I think the intention is more clear.
However, this only works as long as your parameter (here logpath_str) has to be read-only. As soon as the parameter has to be writable, you have to override __init__. Hence, in this case, it may be better to go with Michael C's solution.
For completeness, with a setter, the solution would look like this:
class MyTaskRunner(luigi.Task):
logdir=luigi.Parameter(default=None)
rundate=luigi.Parameter(default=today)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Set the default here
self._logpath_str = "{}/{}".format(self.logdir, self.rundate)
#property
def logpath_str():
return self._logpath_str
#logpath_str.setter
def logpath_str(value):
self._logpath_str = value
Related
I have a question to the variable assignment in the constructor: I have a constructer which takes the argument 'context'. First, I assign this variable to a class variable. Second, I create another class which also takes 'context' as an argument.
To my question: Is it better to assignment the class variable (self.context) or the argument from the constructor (context) to the new created class?
class State():
def __init__(self, context):
self.context = context
self.diconnected = Disconnected(self.context)
or
class State():
def __init__(self, context):
self.context = context
self.diconnected = Disconnected(context)
The end result is the same. Disconnected(context) is just slightly shorter and faster.
This is really not going to effect your program execution time in any significant way in Python. The only situation this could matter is when multiple threads may be using this data. I'd always use the argument just in case.
None is objectively "better"; you're passing the same object to Disconnected in any case.
Which one you write depends on which dependency you want to emphasize: that Disconnected has the same context as self (which also implies that self always has one), or that it has the context passed in as the parameter.
I have a class Document, this class is really complex to instantiate so I have a builder object to create them. Both elements are not mine, so I can't change them
Now, I want to create a subclass of Document, just to add some specific methods. In order to keep using the provided builder I tried this:
class SpecialDocument(Document):
def __new__(cls, *args):
return DocumentBuilder(*args)
def __init__(self, *args, **kwargs):
#My initialization
The problem here is that the __init__ method never executes cause the __new__ method doesn't return a SpecialDocument (It returns a Document)
In my particular case I don't need to build my SpecialDocument differently from how I build a Document. Is there a way to use the same builder? If not, how can I achieve this? I just want to inherit from Document to add particular functionalities, maybe it could be achieved with metaclasses but I never used them (Probably cause I don't fully understand it), a little insight on them would be nice if it can help solving my problem
You don't actually need a metaclass here - you just have to proper call the superclass' __new__ method. The way you are doing it, the instantiation of the superclass does not "know" it is being called from a subclass at all.
So, just write your code like this instead:
class SpecialDocument(Document):
def __new__(cls, *args):
return super().__new__(cls, *args)
def __init__(self, *args, **kwargs):
#My initialization
Now, that is the ordinary way to do it - and would work if the code in your "builder" function was correctly placed inside Docment's __new__ or __init__.
Since the code there does nt do that, and you can[ t pass your subclass as a parameter to the builder, a working solution might be to create a normal document, and swap its class after it has been built:
def special_document_init(special_document):
...
class SpecialDocument(Document):
def my_special_method(self, ...):
...
def overriden_method(self):
...
result = super().overriden_method()
...
def build_special_document(*args):
document = DocumentBuilder(*args)
document.__class__ = SpecialDocument
special_document_init(document)
return document
Suppose I have a constructor in python:
def __init__(self, bBoolFlags_a_Plenty):
self.bBoolFlags_a_Plenty = self.bBoolFlags_a_Plenty
[...] # one line for each bool flag passed in.
Is there a way to assign function arguments passed to init() to member variables/attributes of the class having the same name as the function arguments without having to hand write each one?
Of something more limited in scope, perhaps a one liner will do. Something like:
self.* = ( arg_bool1, arg_bool2, arg_bool3, arg_bool4)
Actually, I would prefer the latter, just because I don't want the 'kitchen sink' to be assigned to self.
thanks.
You can either use kwargs:
def __init__(self, **flags):
for flag, value in flags.iteritems():
setattr(self, flag, value)
Or as #bgporter correctly suggests use the __dict__ directly (assuming that you don't define the __slots__ attribute):
def __init__(self, **flags):
self.__dict__.update(flags)
Depending on what number "plenty" actually specifies, it may however be easier to keep them in a seperate dict anyway:
def __init__(self, **flags):
self.flags = flags
I'd favour the latter possibility especially if the class has other, "non-flag" attributes as well.
You could also:
def __init__(self, **kwargs):
for key in iter(kwargs):
settatr(self, key, kwargs.get(key))
I know the question header sounds weird, but since English is not my first language, I find it very hard to formalize. However, I might be able to explain it with bit more text.
The problem is, that I'm trying to create a class called "Foo" for example.
# ../myProject/Foo.py
class Foo:
'''Represents an example class for stackoverflow'''
Now all of Foo class' instances have function attribute, which simply holds a function which can be executed via the instance. Also, there's a parameters attribute, a tuple or a list, which holds parameters which should be used when the function gets called.
def __init__(self, function, parameters):
self.function = function
self.parameters = parameters
def callFunction(self):
if self.function:
self.function(*self.parameters)
This seems to be working fine, however, the problem is, that I want to give it a default value, to change an attribute of the instance. I basically wanna do the following:
def __init__(self, function=setattr, \
parameters=(self, "togglableAttribute", not self.togglableAttribute)):
And doing this will raise NameError: name 'self' is not defined. How should I implement this in order for it to work, or should I come up with a workaround?
self is the typical variable name used to describe the instance. However, default arguments are evaluated when the function is created (at class creation time). Of course self doesn't exist yet because the class doesn't even exist yet -- The class is still in the process of being built.
The typical way to do this is to check for a sentinel;
def __init__(self, function=setattr, parameters=None):
if parameters is None:
parameters = (self, "togglableAttribute", not self.togglableAttribute)
See my answer here (and the comments below it) for a discussion of various objects that you can use as your sentinel and the various pros and cons of each.
I am trying to write a base crud controller class that does the
following:
class BaseCrudController:
model = ""
field_validation = {}
template_dir = ""
#expose(self.template_dir)
def new(self, *args, **kwargs)
....
#validate(self.field_validation, error_handler=new)
#expose()
def post(self, *args, **kwargs):
...
My intent is to have my controllers extend this base class, set the
model, field_validation, and template locations, and am ready to go.
Unfortunately, decorators (to my understanding), are interpreted when
the function is defined. Hence it won't have access to instance's
value. Is there a way to pass in dynamic data or values from the sub
class?
For example:
class AddressController(BaseCrudController):
model = Address
template_dir = "addressbook.templates.addresses"
When I try to load AddressController, it says "self is not defined". I am assuming that the base class is evaluating the decorator before the sub class is initialized.
Thanks,
Steve
Perhaps using a factory to create the class would be better than subclassing:
def CrudControllerFactory(model, field_validation, template_dir):
class BaseCrudController:
#expose(template_dir)
def new(self, *args, **kwargs)
....
#validate(field_validation, error_handler=new)
#expose()
def post(self, *args, **kwargs):
....
return BaseCrudController
Unfortunately, decorators (to my
understanding), are interpreted when
the function is defined. Hence it
won't have access to instance's value.
Is there a way to pass in dynamic data
or values from the sub class?
The template needs to be called with the name of the relevant attribute; the wrapper can then get that attribute's value dynamically. For example:
import functools
def expose(attname=None):
if attname:
def makewrapper(f):
#functools.wraps(f)
def wrapper(self, *a, **k):
attvalue = getattr(self, attname, None)
...use attvalue as needed...
return wrapper
return makewrapper
else:
...same but without the getattr...
Note that the complication is only because, judging from the code snippets in your Q, you want to allow the expose decorator to be used both with and without an argument (you could move the if attname guard to live within wrapper, but then you'd uselessly repeat the check at each call -- the code within wrapper may also need to be pretty different in the two cases, I imagine -- so, shoehorning two different control flows into one wrapper may be even more complicated). BTW, this is a dubious design decision, IMHO. But, it's quite separate from your actual Q about "dynamic data".
The point is, by using the attribute name as the argument, you empower your decorator to fetch the value dynamically "just in time" when it's needed. Think of it as "an extra level of indirection", that well-known panacea for all difficulties in programming!-)