Python decorator for random generator? - random

I am doing some coding homework and need to use a class with two functions first function to generate a random number and second function to set the value. I understand that the result should be such that getter output is equal to setter output, but they are not the same as I think setter activates getter the second time before printing result. I think I need to use decorators to solve this problem so that is how I approached it.
class RandNum(object):
random.seed(0)
def __init__(self):
self.num = self.getNum
#property
def getNum(self):
return random.randint(0,20)
#getNum.setter
def setNum(self,num):
self.num = num
After printing
randnum = RandNum()
for i in range(3):
print("getter: ", randnum.getNum)
print("setter: ", randnum.setNum)
I get
getter: 13
setter: 1
getter: 8
setter: 16
getter: 15
setter: 12
So my getter and setter are always different. How can I make them the same? Been working on it for a few days and to no avail yet, so would really appreciate the help.

Ok, answered it.
It turns out I just needed to generate random number once and I was generating it multiple times through getter function. So the correct code is .
class RandNum(object):
random.seed(0)
def __init__(self):
self.num = random.randint(0,20)
#property
def getNum(self):
return self.num
#getNum.setter
def setNum(self,num):
self.num = num

Related

How to return a final result from object designed to chain methods

I am doing this exercise:
To do this exercise, you will probably have to use return self. If the method returns itself (an instance of itself), we can chain methods.
Develop a ruby class called MathDojo that has the following functions: add, subtract. Have these 2 functions take at least 1 parameter. MathDojo.new.add(2).add(2, 5).subtract(3, 2) should perform 0+2+(2+5)-(3+2) and return 4.
I have this code:
class MathDojo
def initialize
#sum = 0
end
def add(*numbers)
numbers.inject(#sum) { |sum, number| sum + number }
self
end
def subtract(*numbers)
numbers.inject(#sum) { |sum, number| sum - number }
self
end
end
Right now, my code returns:
MathDojo.new.add(2).add(2, 5).subtract(3, 2)
# => #<MathDojo:0x0000000160b0c0>
How do I return the instance variable of an object instead of the object itself? When I remove the return to self, the methods no longer chain, although I am able to make a single method call:
MathDojo.new.subtract(2,3)
# => -5
How do I modify my code so the chaining works as expected?
Self-solved, had to edit, because the downvotes on my question put me under the reputation needed to answer my own question. My apologies.
I needed to flatten the array before injecting numbers into the array. Then added attr_accessor to collect the sum for use outside the class. I also changed the implied return of self to read:
return self
I modified the code by entering the following, as shown by jbh's answer:
attr_accessor :sum
before my initialize method
Then I modified the add and subtract methods to include calling flatten:
#sum = numbers.flatten.inject(#sum) { |sum, number| sum + number }
#sum = numbers.flatten.inject(#sum) { |sum, number| sum - number }
then as jbh also showed I added .sum to my chained methods:
puts math1 = MathDojo.new.add(2).add(2, 5).subtract(3, 2).sum
One more thing, people talk about how curmudgeony the problem solver-people on stackoverflow can be and today I experienced that. I clearly mentioned I was new to Ruby (I should have stated it's only my 2nd day) and I had to have my reputation voted down 2 points because they didn't like the format of my question, all that needed to be done was the edit.
You cannot know when a method is called if there will be a chain call after it. So you cannot choose if you should return self or the sum value.
Simple answer for that, create a sum method that should be called at the end of your chain call
class MathDojo
attr_reader :sum
end
puts MathDojo.new.add(2).add(2, 5).subtract(3, 2).sum

Ruby - modifying classes

I wrote simple method which checks if a number is Armstrong number.
But now I want to modify default Number class putting method.
So, I have code:
def is_an(number)
(number.to_s.split(//).map(&:to_i).inject{|x,y|x+y**(number.size-1)}) == number ? true : false
end
p is_an(153)
I want to use it as method: 153.is_a?
So, how I do this?
class Number
def is_an
??? How to use object data over here? ???
end
end
Thx a lot for reading.
Incorporating #mikej's answer, plus replacing number with self:
class Fixnum
def is_an
digits = self.to_s.split(//).map(&:to_i)
digits.inject(0) { |x,y| x+y**digits.size } == self
end
end
But I would suggest a name change, to make it more Ruby like. Instead of #is_an, which isn't very descriptive, how about #armstrong? then you can call:
153.armstrong?
Not an answer to your original question, but there are a couple of small bugs in your code. You need to pass 0 to the inject to use as an initial value. Otherwise, inject takes the first value from the list as the initial value. Your current code seems to work for 153 because 1^3 == 1 but it would return false for 370, for example, when it should return true.
Also, the size method on Fixnums doesn't return the number of digits in a number.
Finally, a minor point: the ? true : false isn't needed because the value of the ... == number expression is already the required boolean value. So a possible updated method would be:
def is_an(number)
digits = number.to_s.split(//).map(&:to_i)
digits.inject(0) { |x,y| x+y**digits.size } == number
end

Using Strings as Variable/Object Names in Ruby

I am dealing with fractals. You start with a rectangle, and that shape is decreased by a given decay rate. I have it set up to do the first 10 iterations of the given scenario, and each scenario looks like this:
y_1 = dec_y(y_1)
y_2 = dec_y(y_2)
a_y = [y_1, y_2]
rect_1 = TkcRectangle.new(canvas, [0,0], a_y)
where dec_y is defined as the following:
def dec_y(y)
to_ret = y / $rate
return to_ret
end
I want to turn the first snippet into a function/method (not exactly sure what the Ruby term is...), so that each iteration will just be a single line referencing a method, which makes the problem more extensible. But, I need each TkcRectangle to have a different name. The way I want to set it up, each TkcRectangle will have the same name. But, if I can set the name of the object to a string passed as an argument, then I should not have a problem.
How do I define the name of an object with a given string?
Edit : Code has not been tested, but will give you the idea.
Instead of naming each element, you can use an array and use the index instead
rectangles_array = Array.new
for each loop
rectangles_array << create_rectangle_object(y_1, y_2, canvas)
end for each loop
def dec_y(y)
to_ret = y / $rate
return to_ret
end
def create_rectangle_object(y_1, y_2, canvas)
return TkcRectangle.new(canvas, [0,0], [dec_y(y_1), dec_y(y_2)])
end
If you really want to name it read about structs.. Something like
MyRectangleStruct = Struct.new(:obj_name, :x1, :y1, :x2, :y2)
puts MyRectangleStruct.new(:obj_name => 'First_rec', .....)
define_method(method_name, &block)
with method_name being any string and &block being a block of ruby code; usually it looks something like this:
define_method(method_name) do
your code goes here
end

How to call a method in Ruby?

Hey I have a problem with my method that calculates the covariance of two arrays.
There is always the error:
undefined method 'kovarianz' for main:Object
Here is my Code:
rohstoff1 = "Eisen"
rohstoff2 = "Neodym"
daten_rohstoff1 = [1,2,3,4,5,6]
daten_rohstoff2 = [10,11,15,16,17,18]
module Enumerable
def mean
m = self.reduce(:+) / self.length.to_f
return m
end
def covariance (dat1,dat2)
kovar = dat1.inject(0) { |sum, x| sum + (x-dat1.mean) } *
dat2.inject(0) { |sum, x, i| sum + (x-dat2.mean) } / dat1.length.to_f
return kovar
end
end
puts "Kovarianz von #{rohstoff1} und #{rohstoff2} = " +
covariance(daten_rohstoff1,daten_rohstoff2)
There are two things wrong with what you're doing. First, you've defined an Enumerable instance method, not a class method. You won't pass in the array you are operating on but, rather, you will call covariance directly on the array:
daten_rohstoff1.covariance daten_rohstoff2
You should therefore define the method to take only one argument, namely the second array.
Second, and as mentioned before, you've defined a method covariance but are trying to call kovarianz. This, obviously, will not work.
The method name is called covariance but you call kovarianz in the last line. Change one or the other and you should be golden.
Well, the primary issue here being that you called kovarianz, as opposed to covariance, but the fact that the code is also embedded in a module means you have to call it like so:
Enumerable::covariance(daten_rohstoff1,daten_rohstoff2)
Hope this helped.

Creating objects from YAML, already initialized constant

Two problems, that probably are related:
I'm retreiving a number of 'persons' from a YAML-file to an array, and now i'm trying to create classes from that array.
These objects are then to placed in a new array.
It actually works out fine, if you dont consider the fact that the object added last replaces all the previously added.
In my case i get five identical copies of object #5, where i rather like to see five different ones.
My guess is that the error results somewhere in my iterator to get all the 'persons' from the YAML.
I'm getting a cuople of warnings, regarding the 're-use' of constants:
NEWSTR and NEWAL.
getPost = 0
loopa = 0
while loopa < personsInYAML
NEWSTR = TEST.fetch(getPost)
NEWAL = NEWSTR.split(' ')
getPost+=1
puts "*****************************************"
nyloop = loopa+1
puts "PERSON: " + nyloop.to_s + " name: " + NEWAL.fetch(1)
nameToArray = Person.new
outputArray.insert(loopa, nameToArray)
loopa+=1
end
Persons-class
class Person
def initialize
#name
#age
#length
#weight
#misc
end
def name
name = NEWAL.fetch(1)
return name
end
if NEWAL.include?("age:")
def age
x = NEWAL.index("age:")+1
age = NEWAL.fetch(x)
return age
end
end
if NEWAL.include?("length:")
def length
x = NEWAL.index("length:")+1
length = NEWAL.fetch(x)
return length
end
end
if NEWAL.include?("weight:")
def weight
x = NEWAL.index("weight:")+1
weight = NEWAL.fetch(x)
return weight
end
end
if NEWAL.include?("misc:")
def misc
x = NEWAL.index("misc:")+1
misc = NEWAL.fetch(x)
return misc
end
end
end
You're taking the wrong approach to populating your Person class. The only thing your loop is doing is to create brand new Person classes and stick them in an array. It isn't actually initializing the person class at all.
It looks like what you are trying to do is to use a constant (which you don't hold constant) to pass information to the Person class. However, the code that you have in your Person class that is outside of the methods is only going to be run once - when the class loads for the first time, NOT at the time that you make a new Person.
You'd be better off changing your initialize method to take some arguments, and to create the class with appropriate arguments within the loop.
def initialize(name, age = nil, length = nil, weight = nil, misc = nil)
# assign instance variables here
#name = name
...
end
You appear to be trying to create dynamic accessors to the instance variables. This doesn't make a whole lot of sense. Just define accessors on all of them, and handle the case where the instance variables are nil in whatever code is calling the Person class.

Resources