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.
Related
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
I saw some blogs online where they put self parameters on their celery functions, why is mine causing an error like:
TypeError: xml_gr() takes exactly 1 argument (0 given)
Here is my code:
#periodic_task(run_every=timedelta(seconds=5))
def xml_gr(self):
ftp = FTP('xxxxx')
ftp.login(user='xxxxx', passwd='xxxxx')
x = xml_operation('AGIN', GR_GLOBAL_CURRENT_DATE, ftp, "GR")
ftp.close()
In addition to the accepted answer, self is used in celery to bind tasks.
Bound tasks are needed for retries. for accessing information about
the current task request, and for any additional functionality
you add to custom task base classes.
So, if you specify #task(bind=True) then you need add self as the first argument. Otherwise, not needed.
Source
"self" is used within class member functions. When you call a member function in an instance of the class, the language automatically passes in the class instance as "self". "self" lets you access the members of the class.
class Thing:
var1 = None
def set_member(self, value):
self.var1 = value
def show_member(self, value):
return self.var1
Then usage would be
a = Thing()
a.set_member(23)
a.show_member()
And you'd see the response 23. You don't have to pass in the "self" variable explicitly.
When you declare functions outside of a class, there is no reason to use "self".
My question pertains to the NotTrigger class in the code below. The evaluate method takes both trigger and story as inputs and both are objects that are defined earlier. Why would the evaluate method treat them differently, i.e. why is the 'trigger' variable initialized in NotTrigger's init method whereas the 'story' variable is taken as an argument to the evaluate method? Why can't both the 'trigger' and 'story' inputs be taken as arguments to the evaluate method? fyi, this is a question from MIT's online python course and when i try to treat them the same, i receive an error.
class Story(object):
def __init__(self, subject):
self.subject = subject
def getSubject(self):
return self.subject
class Trigger(object):
def evaluate(self, text):
return self.isWordIn(text.getSubject())
class NotTrigger(object):
def __init__(self, other):
self.trigger = trigger
def evaluate(self, story):
return not self.other.evaluate(story)
I think your question is: why is the constructor - __init__ being used here to set up state when we could just pass all arguments to the method we are going to use?
In object-oriented programming, you setup the state that a class will hold on to and use throughout it's lifetime when it is created. To intercede on that you can implement setters, but the idea is to encapsulate your state within the instance of an object, and call methods that can access that state with arguments from the outside world.
So in this case, self.trigger is set when the object is initialized because that object is something that NotTrigger depends on, for whatever reason. This is known as dependency injection - the notion that you should always try to be explicit about what a classes dependencies are when it is initialized because this is easier to understand and reason about than when they are injected at any time through arbitrary method calls.
So if I understand your question: why are we setting state in the class rather than just passing in what we need when we make a call? Because otherwise we would have no need of a class construct, and the state it holds on to.
I've got a button class that you can instantiate like so:
engine.createElement((0, 0), Button(code=print, args=("Stuff!",)))
And when it is clicked it will print "Stuff!". However, I need the button to destroy itself whenever it is clicked. Something like this:
engine.createElement((0, 0), Button(code=engine.killElement, args=(self,)))
However, that would just kill the caller, because self refers to the caller at that moment. What I need to do is give the class its own 'self' in advance...
I thought of just making the string 'self' refer to the self variable upon click, but what if I wanted to use the string 'self' in the arguments?
What is the way to do this? Is my architecture all wrong or something?
Unfortunately this is impossible — the arguments to the button's constructor are evaluated before the constructor is evaluated. You'd need to assign the button to a variable, then set the callback afterwards:
b = Button(code=engine.killElement)
b.args = (b, )
Or something similar.
You've essentially set it up so that you need a reference to an object in order to create that object, which is of course impossible. You could do something like this (a list is as good as a tuple for argument unpacking):
arglist = []
button = Button(code=engine.killElement, args=arglist)
arglist.append(button)
engine.createElement((0, 0), button)
This is inelegant, unclear, and verbose, but it'll get the reference to the instance into the instance.
You could use a sentinel value as another poster suggested. Perhaps a better suggestion would be to simply use a convention (like Python itself) that self is always passed as the first argument to the specified function and doesn't need to be specified explicitly. Then your callbacks are written to always take self, even if they don't do anything with it.
But generally you would not specify an object's behavior by passing it to that object's constructor, but through inheritance. In other words you'd subclass Button, override its onClick method or whatever, and instantiate the subclass. Having onClick know what instance it's attached to is a non-issue. So I come down on the side of yes, your architecture is a wee bit all wrong.
This is impossible in general.
However, if you're creating the Button class, you can pass a special sentinel value that means "yourself". For example:
class Button(object):
yourself = 'yourself'
def __init__(self, code, args):
self.code = code
self.args = [self if arg is yourself else arg for arg in args]
Then:
engine.createElement((0, 0), Button(code=engine.killElement, args=(Button.yourself,)))
Picking an appropriate sentinel can be tricky—obvious choices like None, 0, or '' may be legitimate values, and even tricky things you come up with may turn out to be useful arguments during debugging. Making yourself a class variable, or a global within the module, means that if you ever do need to redefine the sentinel, you only need to change it in one place, instead of everywhere you use it.
See http://bytes.com/topic/python/answers/555169-sentinel-values-special-cases for a brief discussion on picking an appropriate sentinel value. There's another blog out there with more information, but I haven't found it in a quick search… Anyway, here are some quick ideas:
None is always the best answer if it works.
Define an empty class to be the sentinel. Either the class object, or any instance of the class object, can be used.
Create a global instance of the object class (object()).
Define an empty function and use it (or its func_code or whatever).
Ellipsis (or type(Ellipsis), which is a type named ellipsis, but that name isn't accessible) is almost always safe, because it's only used in __getitem__ and friends (and possibly in defining slice objects to pass to them).
If there's a type that could not possibly be a valid value, and you've already got instances around, use one of those—e.g., the func_code member of the __init__ function.
Maybe something like this would help:
class Button(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
kwargs['args'].append(obj)
return obj
def __init__(self, code, args):
self.code = code
self.args = args
def click(self):
return self.code, self.args
b = Button(code="engine.killElement", args=[])
print b.click()
Output:
('engine.killElement', [<__main__.Button object at 0x00B59AF0>])
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.