Why Are These Inputs Treated Differently In Python? __init__ Variables Versus Arguments. - python

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.

Related

Python static method wrapper is unnecessary? [duplicate]

I just can't see why do we need to use #staticmethod. Let's start with an exmaple.
class test1:
def __init__(self,value):
self.value=value
#staticmethod
def static_add_one(value):
return value+1
#property
def new_val(self):
self.value=self.static_add_one(self.value)
return self.value
a=test1(3)
print(a.new_val) ## >>> 4
class test2:
def __init__(self,value):
self.value=value
def static_add_one(self,value):
return value+1
#property
def new_val(self):
self.value=self.static_add_one(self.value)
return self.value
b=test2(3)
print(b.new_val) ## >>> 4
In the example above, the method, static_add_one , in the two classes do not require the instance of the class(self) in calculation.
The method static_add_one in the class test1 is decorated by #staticmethod and work properly.
But at the same time, the method static_add_one in the class test2 which has no #staticmethod decoration also works properly by using a trick that provides a self in the argument but doesn't use it at all.
So what is the benefit of using #staticmethod? Does it improve the performance? Or is it just due to the zen of python which states that "Explicit is better than implicit"?
The reason to use staticmethod is if you have something that could be written as a standalone function (not part of any class), but you want to keep it within the class because it's somehow semantically related to the class. (For instance, it could be a function that doesn't require any information from the class, but whose behavior is specific to the class, so that subclasses might want to override it.) In many cases, it could make just as much sense to write something as a standalone function instead of a staticmethod.
Your example isn't really the same. A key difference is that, even though you don't use self, you still need an instance to call static_add_one --- you can't call it directly on the class with test2.static_add_one(1). So there is a genuine difference in behavior there. The most serious "rival" to a staticmethod isn't a regular method that ignores self, but a standalone function.
Today I suddenly find a benefit of using #staticmethod.
If you created a staticmethod within a class, you don't need to create an instance of the class before using the staticmethod.
For example,
class File1:
def __init__(self, path):
out=self.parse(path)
def parse(self, path):
..parsing works..
return x
class File2:
def __init__(self, path):
out=self.parse(path)
#staticmethod
def parse(path):
..parsing works..
return x
if __name__=='__main__':
path='abc.txt'
File1.parse(path) #TypeError: unbound method parse() ....
File2.parse(path) #Goal!!!!!!!!!!!!!!!!!!!!
Since the method parse is strongly related to the classes File1 and File2, it is more natural to put it inside the class. However, sometimes this parse method may also be used in other classes under some circumstances. If you want to do so using File1, you must create an instance of File1 before calling the method parse. While using staticmethod in the class File2, you may directly call the method by using the syntax File2.parse.
This makes your works more convenient and natural.
I will add something other answers didn't mention. It's not only a matter of modularity, of putting something next to other logically related parts. It's also that the method could be non-static at other point of the hierarchy (i.e. in a subclass or superclass) and thus participate in polymorphism (type based dispatching). So if you put that function outside the class you will be precluding subclasses from effectively overriding it. Now, say you realize you don't need self in function C.f of class C, you have three two options:
Put it outside the class. But we just decided against this.
Do nothing new: while unused, still keep the self parameter.
Declare you are not using the self parameter, while still letting other C methods to call f as self.f, which is required if you wish to keep open the possibility of further overrides of f that do depend on some instance state.
Option 2 demands less conceptual baggage (you already have to know about self and methods-as-bound-functions, because it's the more general case). But you still may prefer to be explicit about self not being using (and the interpreter could even reward you with some optimization, not having to partially apply a function to self). In that case, you pick option 3 and add #staticmethod on top of your function.
Use #staticmethod for methods that don't need to operate on a specific object, but that you still want located in the scope of the class (as opposed to module scope).
Your example in test2.static_add_one wastes its time passing an unused self parameter, but otherwise works the same as test1.static_add_one. Note that this extraneous parameter can't be optimized away.
One example I can think of is in a Django project I have, where a model class represents a database table, and an object of that class represents a record. There are some functions used by the class that are stand-alone and do not need an object to operate on, for example a function that converts a title into a "slug", which is a representation of the title that follows the character set limits imposed by URL syntax. The function that converts a title to a slug is declared as a staticmethod precisely to strongly associate it with the class that uses it.

Variable assignment in the constructor

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.

Should all member variables be initialized in __init__

Maybe this is more of a style question than a technical one but I have a class with several member variables and I want to have it work so that some of the member variables are initialized when the user first creates an instance of the class (i.e. in the __init__ function) and I want the other member variables to be defined from arguments of member functions that will be called later on. So my question is should I initialize all member variables in the __init__ function (and set the ones that will be defined later on to dummy values) or initialize some in the __init__ function and some in later functions. I realize this might be difficult to understand so here are a couple of examples.
This example has var3 set to 0 initially in the __init__ function, then set to the desired value later on in the my_funct function.
class myClass(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
self.var3=0
def my_funct(self,var3):
self.var3=var3
and in this example, var3 is not defined at all in the __init__ function
class myClass(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
def my_funct(self,var3):
self.var3=var3
I don't think either way would make a big difference (maybe a slight difference in memory usage). But I was wondering if one of these is preferred over the other for some reason.
In object-oriented programming it's up to the developer to ensure an object is always in a consistent state after instantiation and after a method finishes. Other than that you're free to develop the class as you wish (keeping in mind certain principles with subclassing / overriding and so on).
A tool such as Pylint will warn when you're setting instance variables outside __init__. It can be argued that setting all instance variables in the __init__ is cleaner but it's not a rule that must be abided by at all times.
I would actually discourage initializing variables you don't always need in __init__ to an arbitrary default value.
I do question your use of OO if this is the case, but I'm sure there is a valid and understandable case where __init__ will not do everything, and the class will want to further modify itself by adding additional attributes with other methods.
The proper way in my opinion to test if a variable was set while running a method that may want to use it would be to use hasattr. This is in the case that this is a valid way to use the method and the test just switches behavior in a sensible way.
Another way would be to try and use it and handle the exception and provide some user friendly information about what the user of your class is doing wrong. This is in the case the method needs the attribute to be set before running.
i.e. Hey man, you did initialize the class, but you need to make sure the z attribute exists by calling the z_init method before running the z_run method.
Another, arguably the more pythonic way, would be to just document how to use the method in the docstring and then let the exception fly when it is used improperly. This is good enough for the first implementation of something and you can then focus on the next task. This is in the same situation as above, the method needs the attribute to be set.
The reason I do not like the idea of initializing variables to arbitrary defaults is this can be confusing (because it is arbitrary) and is line noise.
If the value is not arbitrary and simply a default value that can be changed you should be using a default value in the __init__ method that can be overridden. It can also actually be a valid initial state, which is also not arbitrary and you should set it in the __init__ method.
So the real answer is it depends, and you should probably avoid it and question your use of OO if you are doing this either by adding attributes in other methods or initializing attributes to arbitrary values.
While Simeon Visser is saying to keep your object in a consistent state, he has no basis for what consistency is based on your abstract example. While Pylint warns on this kind of thing, warnings from lint programs are simply so a high level reviewer can be alerted of things that usually indicate code smell. I say high level reviewer because a real reviewer should be reading and understanding all of your code, and thus not really need Pylint.
An example that breaks the rule of thumb:
class Mutant(object):
"""A mutant!"""
def __init__(self):
"""A mutant is born with only 1 eye and 1 mouth"""
self.eyes = 1
self.mouth = 1
self.location = 'Montana'
def roll_to(self, location):
"""If they have limbs, running is less dangerous"""
if hasattr(self, 'limbs'):
print 'Your mutant broke its limbs off!!'
del self.limbs
self.location = location
def run_to(self, location):
"""If they don't have limbs, running is not effective"""
if not hasattr(self, 'limbs'):
print 'Your mutant tries to run but he has no limbs.'
else:
self.location = location
def grow_limbs(self, number_of_limbs):
"""Ah, evolution!"""
assert number_of_limbs > 0, 'Cannot grow 0 or less limbs...'
if hasattr(self, 'limbs'):
self.limbs += number_of_limbs
else:
self.limbs = number_of_limbs
Here is an excerpt from sololearn.com (a free site to learn python)
"Properties provide a way of customizing access to instance attributes.
They are created by putting the property decorator above a method, which means when the instance attribute with the same name as the method is accessed, the method will be called instead.
One common use of a property is to make an attribute read-only."
Example (also from sololearn.com):
class Pizza:
def __init__(self, toppings):
self.toppings = toppings
#property
def pineapple_allowed(self):
return False
pizza = Pizza(["cheese", "tomato"])
print(pizza.pineapple_allowed)
pizza.pineapple_allowed = True
Result:
>>>
False
AttributeError: can't set attribute
>>>
If var3 depends on var1 and var2 you could do
class myClass:
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
#property
def var3(self):
return(self.var1+self.var2) #var3 depends on var1 and var2
m1=myClass(1,2)
print(m1.var3) # var3 is 3
var3 can also be set to whatever you want using a setter function. Note that you can avoid setting var3 to an arbitrary value by using None.
class myClass2(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
self._var3=None # None or an initial value that makes sense
#property
def var3(self):
return(self._var3)
#var3.setter
def var3(self,value):
self._var3=value
m2=myClass(1,2)
print(m2.var3) # var3 is none
print(m2.var3(10)) # var3 is set to 10

Python 3: Giving a command to set attribute of self in __init__ with need to use "self"?

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.

Classes in python, how to set an attributes

When I write class in python, most of the time, I am eager to set variables I use, as properties of the object. Is there any rule or general guidelines about which variables should be used as class/instance attribute and which should not?
for example:
class simple(object):
def __init(self):
a=2
b=3
return a*b
class simple(object):
def __init(self):
self.a=2
self.b=3
return a*b
While I completely understand the attributes should be a property of the object. This is simple to understand when the class declaration is simple but as the program goes longer and longer and there are many places where the data exchange between various modules should be done, I get confused on where I should use a/b or self.a/self.b. Is there any guidelines for this?
Where you use self.a you are creating a property, so this can be accessed from outside the class and persists beyond that function. These should be used for storing data about the object.
Where you use a it is a local variable, and only lasts while in the scope of that function, so should be used where you are only using it within the function (as in this case).
Note that __init is misleading, as it looks like __init__ - but isn't the constructor. If you intended them to be the constructor, then it makes no sense to return a value (as the new object is what is returned).
class Person(object):
def __init__(self, name):
# Introduce all instance variables on __init__
self.name = name
self.another = None
def get_name(self):
# get_name has access to the `instance` variable 'name'
return self.name
So if you want a variable to be available on more than one method, make
it an instance variable.
Notice my comment on introducing all instance vars on __init__.
Although the example below is valid python don't do it.
class Person(object):
def __init__(self):
self.a = 0
def foo(self):
self.b = 1 # Whoa, introduced new instance variable
Instead initialize all your instance variables on __init__ and set
them to None if no other value is appropriate for them.
I try to imagine what I want the API of my class to look like prior to implementing it. I think to myself, If I didn't write this class, would I want to read the documentation about what this particular variable does? If reading that documentation would simply waste my time, then it should probably be a local variable.
Occasionally, you need to preserve some information, but you wouldn't necessarily want that to be part of the API, which is when you use the convention of appending an underscore. e.g. self._some_data_that_is_not_part_of_the_api.
The self parameter refers to the object itself. So if you need to use on of the class attributes outside of the class you would it call it as the name of class instance and the attribute name. I don't think there is any guideline on when to use self, it all depends on your need. When you are building a class you should try to think about what you will use the variables you creating for. If you know for sure that you will need that specific attribute in the program you are importing your class, then add self.

Categories