I am learning python with an online course and have been doing fine, I have stumbled across and issue. Normally when having an issue i just google to find the answer or look up guides but the problem here is I'm not even sure what I'm looking for!
I currently have the below code. I have a task to make each workout intensity have a specific value, such as Low = 3, Medium = 6 and High = 12. Then I can find the calories burned via duration * the values dependant on the intensity and duration passed into the class.
What I don't know is how do I assign a value to a class method? I tried lists and Dictionarys and both are throwing errors. I tried writing and If statement to try if self.intensity(getattr) = "Low": Then x = 3, etc.
I really am not sure where to even start to find an answer hence asking you guys and girls.
The code currently is (I am aware pieces are missing also I'm currently only focusing on assigning values to the Intensity
class ExerciseSession:
def __init__(self, exercise, intensity, duration):
self.exercise = exercise
self.intensity = intensity
self.duration = duration
def get_exercise(self):
return self.exercise
def get_intensity(self):
return self.intensity
def get_duration(self):
return self.duration + " minutes"
def set_exercise(self, excersice):
self.set_exercise = exercise
def set_intensity(self, intensity):
self.set_intensity = intensity
def set_duration(self, duration):
self.set_duration = duration
new_exercise = ExerciseSession("Running", "Low", 60)
print(new_exercise.get_exercise())
print(new_exercise.get_exercise())
print(new_exercise.get_intensity())
print(new_exercise.get_duration())
new_exercise.set_exercise("Swimming")
new_exercise.set_intensity("High")
new_exercise.set_duration(30)
print(new_exercise.get_exercise())
print(new_exercise.get_intensity())
print(new_exercise.get_duration())
print(new_exercise.get_intensity())
print(new_exercise.get_duration())
new_exercise.set_exercise("Swimming")
new_exercise.set_intensity("High")
new_exercise.set_duration(30)
print(new_exercise.get_exercise())
print(new_exercise.get_intensity())
print(new_exercise.get_duration())
Am i just doing lists/dictionaries wrong within a class or am I missing something incredibly easy here. I understand classes and methods but it seems some things work slightly different when inside a class etc.
Firstly - are your setters implemented as they are in your question? If so, you appear to be trying to override your methods with a value. There is also a small typo in set_exercise(). Compare the below with your question:
def set_exercise(self, exercise):
self.exercise = exercise
def set_intensity(self, intensity):
self.intensity = intensity
def set_duration(self, duration):
self.duration = duration
You can then write your test statements outside of the class to figure out what value to use when calculating the number of calories consumed based on the intensity.
Alternatively, Python provides a neat way of encapsulating data without resorting to getter/setter methods through the #property decorator. The property can then be set and retrieved in a simple fashion. This is particularly useful in more complex situations where an attribute is derived from other attributes, meaning you will always access the most up-to-date attributes. This is covered in more detail here: "public" or "private" attribute in Python ? What is the best way?
class ExerciseSession:
def __init___(self, exercise, intensity, duration):
self._exercise = exercise
self._intensity = intensity
self._duration = duration
#property
def exercise(self):
return self._exercise
#property
def intensity(self):
if self._intensity == "Low":
out = 3
elif self._intensity == "Medium":
out = 6
elif self._intensity == "High":
out = 12
else:
out = None
return out
#property
def duration(self):
return self._duration
Note: the "_" before each instance attribute is used to indicate the internal attribute is conventionally private.
These properties can then be accessed as follows (note we do not have to call any methods, e.g. new_exercise.exercise()):
new_exercise = ExerciseSession("Running", "Low", 60)
print(new_exercise.exercise)
print(new_exercise.intensity)
print("{} minutes.".format(new_exercise.duration))
If you need to be able to update the type of exercise/duration/intensity on the object, rather than just creating a new one, you can add setter methods using the #.setter decorator, e.g.:
#exercise.setter
def exercise(self, value):
self._exercise = value
and these properties can be updated as:
new_exercise.exercise = "Swimming"
doing the same :-)
def calories_burned(self):
if self.intensity == "Low":
return 4 * self.duration
elif self.intensity == "Medium":
return 8 * self.duration
else:
return 12 * self.duration
Related
I defined the following Enum in Python:
class Unit(Enum):
GRAM = ("g")
KILOGRAM = ("kg", GRAM, 1000.0)
def __init__(self, symbol, base_unit = None, multiplier = 1.0):
self.symbol = symbol
self.multiplier = multiplier
self.base_unit = self if base_unit is None else base_unit
I would expect that
print(Unit.GRAM.base_unit)
print(Unit.KILOGRAM.base_unit)
will return
Unit.GRAM
Unit.GRAM
However, what I get is quite confusing
Unit.GRAM
g
Why is it so?
The way Python defines a class involves creating a new scope, processing a bunch of statements (variable assignments, function definitions, etc.), and then actually creating a class object based on the local variables which exist after all those statements have run. Nothing gets converted into Enum instances until that last step.
You could understand it somewhat like this:
def make_class_Unit():
GRAM = ("g")
KILOGRAM = ("kg", GRAM, 1000.0)
def __init__(self, symbol, base_unit = None, multiplier = 1.0):
self.symbol = symbol
self.multiplier = multiplier
self.base_unit = self if base_unit is None else base_unit
return make_class(name='Unit', base=Enum, contents=locals())
Unit = make_class_Unit()
Looking at it this way, hopefully you can tell that at the time when KILOGRAM is defined, GRAM is really just a string. It doesn't become a Unit instance until the last stage, where I call the (imaginary) make_class() function.1
1Even though the make_class function I used above doesn't actually exist under that name, it's not too different from what Python really does, which is calling the constructor of type or a metaclass (which in this case is the metaclass for Enums).
DavidZ explained the problem well.
The last bit that you need to solve this problem is this: when the __init__ of each member is being run, the Enum has been created -- so you can call it:
self.base_unit = self if base_unit is None else self.__class__(base_unit)
Say I have a class (Rectangle) which implements a method (describe) as follows:
class Rectangle(object):
def __init__(self, height, width):
self.height = height
self.width = width
def describe(self):
return 'Rectangle with height {:0.2f} and width {:0.2f}'.format(float(self.height),
float(self.width))
This works as expected:
r = Rectangle(5, 3)
r.describe()
>>> 'Rectangle with height 5.00 and width 3.00'
I would like to be able to specify, at instantiation, an alternative function which would take the place of describe. I believe the below works:
import functools as ft
class RectangleEnhanced(object):
def __init__(self, height, width, description_function=None):
self.height = height
self.width = width
if description_function is None:
self.describe = self.default_describe
else:
self.describe = ft.partial(description_function, self)
def default_describe(self):
return 'Rectangle with height {:0.2f} and width {:0.2f}'.format(float(self.height),
float(self.width))
So that:
s = RectangleEnhanced(5, 3)
s.describe()
>>> 'Rectangle with height 5.00 and width 3.00'
continues to work as before, but, in addition:
def area_description(enh_rect):
return 'Rectangle with area {:0.2f}'.format(float(enh_rect.height * enh_rect.width))
t = RectangleEnhanced(5, 3, area_description)
t.describe()
>>> 'Rectangle with area 15.00'
Is this a reasonable approach to this problem? I can't imagine that I'm the first person to want to do this, and so I'm nervous that the approach below is suboptimal/unpythonic/bad/etc. Is there a "right" way to handle this?
Edit
Here's an example closer to my use case:
class FilterableCollection(object):
def __init__(self, items, owner, purpose, filterfunc=None):
self.items = set(items)
self.owner = owner
self.purpose = purpose
if filterfunc is None:
self.filterfunc = lambda x: True
else:
self.filterfunc = ft.partial(filterfunc, self)
def filtered(self):
return filter(self.filterfunc, self.items)
items = ['fun_ball', 'boring_ball', 'fun_bear', 'boring_bear']
owner = 'Bill'
purpose = 'fun'
f = FilterableCollection(items, owner, purpose)
print f.filtered()
def is_applicable(self, item):
return self.purpose in item
g = FilterableCollection(items, owner, purpose, is_applicable)
print g.filtered()
which returns:
['fun_bear', 'fun_ball', 'boring_ball', 'boring_bear']
['fun_bear', 'fun_ball']
as expected. So the idea is that when you create a specific instance of a FilterableCollection you can create a custom filter (which may depend on other attributes of that particular FitlerableCollection) which is then available to be called whenever. So there might be 10 FilterableCollections floating around, and they can each be filtered with their respective filters by calling the .filtered method.
I'm very open to the idea of doing this with inheritance or any other technique. But how would that apply in this case?
The essence is that for each instance of the class, I want to be able
to perform a certain kind of filtering on some data attached to the
instance. Depending on the context, the kind of filtering required
could vary widely.
What you describe here is known as the strategy pattern, and your example implementation is almost as pythonic as possible - Python functions being objects, quite a few design patterns requiring a full blown "functor" class in most mainstream languages are implemented with a plain function in Python.
The only "improvement" I can see would be to get rid of the partial - Python functions do know how to become instance methods:
if description_function is None:
self.describe = self.default_describe
else:
self.describe = description_function.__get__(self)
You can read this for more about this behaviour : https://wiki.python.org/moin/FromFunctionToMethod
Not that this would change anything from a purely functional (no pun intended) but it will certainly make you look as a PythonGuru(tm)
Your implementation makes sense. It is common for a class to take an optional param in its __init__ and to use a senisble default value if it isn't being passed. In your case that parameter is a function.
So this is a good implementation given you really really want to do that.
However, like many other commentator point out, this doesn't sound like a very good idea. The difference between taking a simple value and taking a function to override a method like this, is that the function param affects the behavior of the instance. Instances of the same type shouldn't really have different behavior.
Therefor using different types (e.g. using inheritance), is the most straightforward approach.
Since you asked, here is how you can use inheritance here:
class FilterableCollection(object):
def __init__(self, items, owner, purpose):
self.items = set(items)
self.owner = owner
self.purpose = purpose
def filtered(self):
return self.items
class ApplicabilityFilterableCollection(FilterableCollection):
def filtered(self):
return [ item for item in self.items if self.purpose in item ]
f = FilterableCollection(items, owner, purpose)
print f.filtered()
g = ApplicabilityFilterableCollection(items, owner, purpose)
print g.filtered()
I want to create a function within a class that can access two different members with the same function. For example in the code below, I want both of the lines below to use the 'apply' function on different variables in the class
print(state.apply(rate))
print(state.apply(wage))
I had thought if I put in a dummy variable in the function definition (called exposure), it would replace it with the variables passed to the function (rate and wage in the example below). What is the correct way of doing this in python 3?
class State():
def __init__(self):
self.rate = 0
self.wage = 0
def apply(self, exposure):
self.exposure = self.exposure - 1
return self.exposure
state = State()
rate = State.rate
wage = State.wage
print(state.apply(rate))
print(state.apply(wage))
EDIT: I had made a typo where I had State instead of state in each print statement. I have now corrected this
This would be the only way:
class State:
def __init__ (self):
self.rate = 0
self.wage = 0
def apply (self, exposure):
setattr(self, exposure, getattr(self, exposure) - 1)
return getattr(self, exposure)
>>> state = State()
>>> print(state.apply('rate'))
-1
>>> print(state.apply('wage'))
-1
>>> print(state.apply('wage'))
-2
Note that those are instance variables, so you cannot access them using the type, State, but only using the object, state.
However, I would say, that whatever you are trying, you’re doing it wrong. If you describe your actual problem, we may be able to suggest a way better solution for it instead.
I'm still new to python and this is probably going be one of those (stupid) boring questions. However, any help will be much appreciated. I'm programing something that involves many variables and I've decided to use a class to encapsulate all variables (hopefully making it easier to "read" for me as time passes), but it's not working as I thought it will. So, without further ado here is a part of the class that captures the gist.
import numpy as np
class variable:
def __init__(self, length):
self.length = length # time length`
def state_dynamic(self):
length = self.length
return np.zeros((2, np.size(length)))
def state_static(self):
length = self.length
return np.zeros((2, np.size(length)))
def control_dynamic(self):
length = self.length
return np.zeros((2, np.size(length)))
def control_static(self):
length = self.length
return np.zeros((2, np.size(length)))
def scheduling(self):
length = self.length
return np.zeros(np.size(length))
def disturbance(self):
length = self.length
dummy = np.random.normal(0., 0.1, np.size(length))
for i in range(20):
dummy[i+40] = np.random.normal(0., 0.01) + 1.
dummy[80:100] = 0.
return dummy
I've also tried this one:
import numpy as np
class variable:
def __init__(self, type_1, type_2, length):
self.type_1 = type_1 # belongs to set {state, control, scheduling, disturbance}
self.type_2 = type_2 # belongs to set {static, dynamic, none}
self.length = length # time length
def type_v(self):
type_1 = self.type_1
type_2 = self.type_2
length = self.length
if type_1 == 'state' and type_2 == 'dynamic':
return np.zeros((2, np.size(length)))
elif type_1 == 'state' and type_2 == 'static':
return np.zeros((2, np.size(length)))
elif type_1 == 'control' and type_2 == 'dynamic':
return np.zeros((2, np.size(length)))
elif type_1 == 'control' and type_2 == 'static':
return np.zeros((2, np.size(length)))
elif type_1 == 'scheduling' and type_2 == 'none':
return np.zeros(np.size(length))
elif type_1 == 'disturbance' and type_2 == 'none':
dummy = np.random.normal(0., 0.1, np.size(length))
for i in range(20):
dummy[i+40] = np.random.normal(0., 0.01) + 1.
dummy[80:100] = 0.
return dummy
Now, using the first one (the outcome is the same for the second class as well), when I write the following, say:
In [2]: time = np.linspace(0,10,100)
In [5]: v = variable(time)
In [6]: v1 = v.state_dynamic
In [7]: v1.size
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/home/<ipython-input-7-e6a5d17aeb75> in <module>()
----> 1 v1.size
AttributeError: 'function' object has no attribute 'size'
In [8]: v2 = variable(np.size(time)).state_dynamic
In [9]: v2
Out[9]: <bound method variable.state_dynamic of <__main__.variable instance at 0x3ad0a28>>
In [10]: v1[0,0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/<ipython-input-10-092bc2b9f982> in <module>()
----> 1 v1[0,0]
TypeError: 'instancemethod' object has no attribute '__getitem__'
I was hoping that by writing
variable(length).state_dynamic
I'll access
np.zeros((2, np.size(length)))
Anyway, if I made something utterly stupid please let me know :) and feel free to give any kind of advice. Thank you in advance for your time and kind attention. Best regards.
EDIT #1:
#wheaties:
Thank you for a quick reply and help :)
What I'm currently trying to do is the following. I have to plot several "variables", e.g., state, control, dropouts, scheduling and disturbances. All the variables depend on three parameters, namely, dynamic, static and horizon. Further, state and control are np.zeros((2, np.size(length))), dropouts and scheduling are np.zeros(np.size(length)) and disturbance has specific form (see above). Initially, I declared them in the script and the list is very long and looks ugly. I use these variables to store responses of dynamical systems considered and to plot them. I don't know if this is a good way of doing this and if you have any suggestion please share.
Thanks again for your help.
Do you mean you want named access to a bunch of state information? The ordinary python idiom for class variables would look like this:
class Variable(object):
def __init__ (self, state_dynamic, state_static, control_static, control_dynamic, scheduling):
self.state_dynamic = state_dynamic
self.state_static = state_static
self.control_static = control_static
self.control_dynamic = control_dynamic
self.scheduling = control_dynamic
Which essentially creates a bucket with named fields that hold values you put in via the constructor. You can also create lightweight data classes using the namedtuple factory class, which avoids some of the boilerplate.
The other python idiom that might apply is to use the #property decorator as in #wheaties answer. This basically disguises a function call to make it look like a field. If what you're doing can be reduced to a functional basis this would make sense. This is an example of the idea (not based on your problem set, since I'm not sure I grok what you're doing in detail with all those identical variables) -- in this case I'm making a convenience wrapper for pulling individual flags out that are stored in a python number but really make a bit field:
class Bits(object):
def __init__(self, integer):
self.Integer = integer # pretend this is an integer between 0 and 8 representing 4 flags
#property
def locked(self):
# low bit = locked
return self.Integer & 1 == 1
#property
def available(self):
return self.Integer & 2 == 2
#property
def running_out_of_made_up_names(self):
return self.Integer & 4 == 4
#property
def really_desperate_now(self):
return self.Integer & 8 == 8
example = Bits(7)
print example.locked
# True
print example.really_desperate_now
# False
A method in Python is a function. If you want to get a value from a member function you have to end it with (). That said, some refactoring may help eliminate boilerplate and reduce the problem set size in your head. I'd suggest using a #property for some of these things, combined with a slight refactor
class variable:
def __init__(self, length):
self.length = length # time length`
#property
def state_dynamic(self):
return self.np_length
#property
def state_static(self):
return self.np_length
#property
def control_dynamic(self):
return self.np_length
#property
def control_static(self):
return self.np_length
#property
def scheduling(self):
return self.np_length
#property
def np_length(self):
return np.zeros(2, np.size(self.length))
That way you can use those functions as you would a member variable like you tried before:
var = variable(length).state_dynamic
What I can't tell from all this is what the difference is between all these variables? I don't see a single one. Are you assuming that you have to access them in order? If so, that's bad design and a problem. Never make that assumption.
As an example, just a couple of dummy objects that will be used together. FWIW this is using Python 2.7.2.
class Student(object):
def __init__(self, tool):
self.tool = tool
def draw(self):
if self.tool.broken != True:
print "I used my tool. Sweet."
else:
print "My tool is broken. Wah."
class Tool(object):
def __init__(self, name):
self.name = name
self.broken = False
def break(self):
print "The %s busted." % self.name
self.broken = True
Hammer = Tool(hammer)
Billy = Student(Hammer)
Tommy = Student(Hammer)
That's probably enough code, you see where I'm going with this. If I call Hammer.break(), I'm calling it on the same instance of the object; if Billy's hammer is broken, so is Tommy's (it's really the same Hammer after all).
Now obviously if the program were limited to just Billy and Tommy as instances of Students, the fix would be obvious - instantiate more Hammers. But clearly I'm asking because it isn't that simple, heh. I would like to know if it's possible to create objects which show up as unique instances of themselves for every time they're called into being.
EDIT: The kind of answers I'm getting lead me to believe that I have a gaping hole in my understanding of instantiation. If I have something like this:
class Foo(object):
pass
class Moo(Foo):
pass
class Guy(object):
def __init__(self, thing):
self.thing = thing
Bill = Guy(Moo())
Steve = Guy(Moo())
Each time I use Moo(), is that a separate instance, or do they both reference the same object? If they're separate, then my whole question can be withdrawn, because it'll ahve to make way for my mind getting blown.
You have to create new instances of the Tool for each Student.
class Student(object):
def __init__(self, tool):
self.tool = tool
def draw(self):
if self.tool.broken != True:
print "I used my tool. Sweet."
else:
print "My tool is broken. Wah."
class Tool(object):
def __init__(self, name):
self.name = name
self.broken = False
def break(self):
print "The %s busted." % self.name
self.broken = True
# Instead of instance, make it a callable that returns a new one
def Hammer():
return Tool('hammer')
# Pass a new object, instead of the type
Billy = Student(Hammer())
Tommy = Student(Hammer())
I'll try to be brief. Well.. I always try to be brief, but my level of success is pretty much random.randint(0, never). So yeah.
Lol. You even failed to be brief about announcing that you will try to be brief.
First, we need to be clear about what "called into being" means. Presumably you want a new hammer every time self.tool = object happens. You don't want a new instance every time, for example, you access the tool attribute, or you'd always a get a new, presumably unbroken, hammer every time you check self.tool.broken.
A couple approaches.
One, give Tool a copy method that produces a new object that should equal the original object, but be a different instance. For example:
class Tool:
def __init__(self, kind):
self.kind = kind
self.broken = False
def copy(self):
result = Tool(self.kind)
result.broken = self.broken
return result
Then in Student's init you say
self.tool = tool.copy()
Option two, use a factory function.
def makehammer():
return Tool(hammer)
class Student:
def __init__(self, factory):
self.tool = factory()
Billy = Student(makehammer)
I can't think any way in Python that you can write the line self.tool = object and have object automagically make a copy, and I don't think you want to. One thing I like about Python is WYSIWYG. If you want magic use C++. I think it makes code hard to understand when you not only can't tell what a line of code is doing, you can't even tell it's doing anything special.
Note you can get even fancier with a factory object. For example:
class RealisticFactory:
def __init__(self, kind, failurerate):
self.kind = kind
self.failurerate = failurerate
def make(self):
result = Tool(self.kind)
if random.random() < self.failurerate:
result.broken = True
if (self.failurerate < 0.01):
self.failurerate += 0.0001
return result
factory = RealisticFactory(hammer, 0.0007)
Billy = Student(factory.make)
Tommy = Student(factory.make) # Tommy's tool is slightly more likely to be broken
You could change your lines like this:
Billy = Student(Tool('hammer'))
Tommy = Student(Tool('hammer'))
That'll produce a distinct instance of your Tool class for each instance of the Student class. the trouble with your posted example code is that you haven't "called the Tool into being" (to use your words) more than once.
Just call Tool('hammer') every time you want to create a new tool.
h1 = Tool('hammer')
h2 = Tool('hammer')
Billy = Student(h1)
Tommy = Student(h2)
Oh wait, I forgot, Python does have magic.
class Student:
def __setattr__(self, attr, value):
if attr == 'tool':
self.__dict__[attr] = value.copy()
else:
self.__dict__[attr] = value
But I still say you should use magic sparingly.
After seeing the tenor of the answers here and remembering the Zen of Python, I'm going to answer my own dang question by saying, "I probably should have just thought harder about it."
I will restate my own question as the answer. Suppose I have this tiny program:
class Item(object):
def __init__(self):
self.broken = False
def smash(self):
print "This object broke."
self.broken = True
class Person(object):
def __init__(self, holding):
self.holding = holding
def using(self):
if self.holding.broken != True:
print "Pass."
else:
print "Fail."
Foo = Person(Item())
Bar = Person(Item())
Foo.holding.smash()
Foo.using()
Bar.using()
The program will return "Fail" for Foo.using() and "Pass" for Bar.using(). Upon actually thinking about what I'm doing, "Foo.holding = Item()" and "Bar.holding = Item()" are clearly different instances. I even ran this dumpy program to prove it worked as I surmised it did, and no surprises to you pros, it does. So I withdraw my question on the basis that I wasn't actually using my brain when I asked it. The funny thing is, with the program I've been working on, I was already doing it this way but assuming it was the wrong way to do it. So thanks for humoring me.