How to continue calling __init__ funtion until certain condition meet? - python

Take the below code for an example.
import random
class test:
def __init__(self):
x = random.choice([1,2,3])
print(x)
if x == 2:
pass
What I want to do here is that when x equals 2 then run the function again and get the different value of x. Therefore whenever I call the test class it always assigns the x value other than 2.
NOTE: We must run the random.choice() in the __init__ and always get the value other than 2, it's okay to run the __init__ as many times as we want unless we get the different value.
The value of x is random.
What I have tried
class test:
def __init__(self):
x = random.choice([1,2,3])
if x != 2:
self.x = x
else:
test()

Update:
Implementing the while loop sounds a good idea.
Try this:
import random
class test:
def __init__(self):
x = random.choice([1,2,3])
loop = 0
while x == 2:
x = random.choice([1,2,3])
loop += 1
if loop >= 5:
x = False
It is impossible to return any value from the __init__() function, since the function is supposed to return None, therefore I have set the x value to False, if it is something you'd like,

You really don't want to be calling init recursively. If you're using Python 3.8+ there's a neat way to fulfil your requirement.
class test:
def __init__(self):
while (x := random.choice([1,2,3])) == 2:
pass
At some point the while loop will terminate when x is either 1 or 3

Related

How can I ensure that a function is "defined" in Python?

Trying to learn python as a java programmer. I would really appreciate some insight into why my program is telling me that my "isPrime" function isn't defined, especially with the use of 'self.'
import math
class Problem10:
def sumOfPrimesX(self, number):
sum = 0
for i in range(0, number):
if isPrime(i):
sum += i
return sum
def isPrime(self, x):
for n in range(0, math.floor(x/2)):
if x % n == 0:
return False
return True
print(sumOfPrimesX(input()))
all functions need it as their first parameter in a python program
No, only the instance methods, the methods related to a specific instance of a class. A simple function can need to parameter.
And you won't see the parameter self filled with the classic way of calling it, if you call the method on a instance it'll be filled by it
p = Problem10()
p.sumOfPrimesX(int(input("Give a value"))) # call on instance, one paramater given
# same as
Problem10.sumOfPrimesX(Problem10(), int(input("Give a value")))
# call on class itself, need to pass an instance as first to fill 'self
Also you need to wrap the input in an int, also start the loop at 2
p = Problem10()
print(p.sumOfPrimesX(int(input("Give a value"))))
class Problem10:
def isPrime(self, x):
for n in range(2, math.floor(x / 2)):
if x % n == 0:
return False
return True
The issue is both isPrime and sumofPrimesX are methods of the class Problem10.
Try the following:
import math
class Problem10:
def sumOfPrimesX(self, number):
sum = 0
for i in range(0, number):
if self.isPrime(i):
sum += i
return sum
def isPrime(self, x):
for n in range(0, math.floor(x/2)):
if x % n == 0:
return False
return True
pv = Problem10()
print(pv.sumOfPrimesX(input()))

Most pythonic way to get variable based on last element in generator?

I have the following code:
class MyClass:
def __init__(self):
self.some_variable = None
def func1(self):
i = 1
while i < 10:
yield i * i
self.some_variable = len(str((i * i)))
i += 1
def func2(self):
*_, last = my_class.func1()
print(self.some_variable)
my_class = MyClass()
my_class.func2()
As you can see, some_variable is the length of the last element in the generator. Basically, I was wondering, is this the most pythonic way of getting this variable? If not, how should this be done? I'm just wondering if this is how it should be done or if there's a better way of doing this.
Probably the simplest code is to simply use a for loop to consume the generator, doing nothing in the loop body. The loop variable will have the last value from the generator after the loop ends, which is exactly what you want.
for x in some_generator():
pass
print(x) # print the last value yielded by the generator
This may be a little more efficient than other options because it discards all the values before the last one, rather than storing them in a list or some other data structure.
I think that one pythonic way would be to yield both the element and the length:
def func1():
i = 1
while i < 10:
yield i * i, len(str((i * i)))
i += 1
def func2():
*_, (_, last_len) = func1()
print(last_len)
func2()
or even to extract the calculation of the derived value to another function and call it after consuming the generator:
def func1():
i = 1
while i < 10:
yield i * i
i += 1
def func2(i):
return len(str(i))
def func3():
*_, last = func1()
print(func2(last))
func3()
I think that you have simplified your example too much to be able to find the solution that fits your real use case the best.

Iteration for the last value of iteration in Python

How can I define a function in python in such a way that it takes the previous value of my iteration where I define the initial value.
My function is defined as following:
def Deulab(c, yh1, a, b):
Deulab = c- (EULab(c, yh1, a, b)-1)*0.3
return (Deulab,yh1, a,b)
Output is
Deulab(1.01, 1, 4, 2)
0.9964391705626454
Now I want to iterate keeping yh1, a ,b fixed and start with c0=1 and iterate recursively for c.
The most pythonic way of doing this is to define an interating generator:
def iterates(f,x):
while True:
yield x
x = f(x)
#test:
def f(x):
return 3.2*x*(1-x)
orbit = iterates(f,0.1)
for _ in range(10):
print(next(orbit))
Output:
0.1
0.2880000000000001
0.6561792000000002
0.7219457839595519
0.6423682207442558
0.7351401271107676
0.6230691859914625
0.7515327214700762
0.5975401280955426
0.7695549549155365
You can use the generator until some stop criterion is met. For example, in fixed-point iteration you might iterate until two successive iterates are within some tolerance of each other. The generator itself will go on forever, so when you use it you need to make sure that your code doesn't go into an infinite loop (e.g. don't simply assume convergence).
It sound like you are after recursion.
Here is a basic example
def f(x):
x += 1
if x < 10:
x = f(x)
return x
print (f(4))
In this example a function calls itself until a criteria is met.
CodeCupboard has supplied an example which should fit your needs.
This is a bit of a more persistent version of that, which would allow you to go back to where you were with multiple separate function calls
class classA:
#Declare initial values for class variables here
fooResult = 0 #Say, taking 0 as an initial value, not unreasonable!
def myFoo1(x):
y = 2*x + fooResult #A simple example function
classA.fooResult = y #This line is updating that class variable, so next time you come in, you'll be using it as part of calc'ing y
return y #and this will return the calculation back up to wherever you called it from
#Example call
rtn = classA.myFoo1(5)
#rtn1 will be 10, as this is the first call to the function, so the class variable had initial state of 0
#Example call2
rtn2 = classA.myFoo1(3)
#rtn2 will be 16, as the class variable had a state of 10 when you called classA.myFoo1()
So if you were working with a dataset where you didn't know what the second call would be (i.e. the 3 in call2 above was unknown), then you can revisit the function without having to worry about handling the data retention in your top level code. Useful for a niche case.
Of course, you could use it as per:
list1 = [1,2,3,4,5]
for i in list1:
rtn = classA.myFoo1(i)
Which would give you a final rtn value of 30 when you exit the for loop.

How should I pass variables between functions in this class?

What I'm trying to do:
executing the script, I will have to type in two numbers and it will compare them.
I want to be asked a total of 3 times.
The first time I will type in 10 and 5, second time 5 and 10 and the third time I will type in 10 and 10 to get all three possible answers.
My problem with the first code is: getnumbers() is being called inside of Checknumbers().
I want to create functions and a loop and strictly ONLY execute the functions inside a dedicated loop and not within another function.
I want everything clean cut and no reference of any function inside another function, I don't want to use any global variables either.
I solved this with a class but I'm not really sure if I'm butchering the language or if this is common practice. Also I have to reference the class inside the checknumbers() function.
First solution:
def getnumbers():
x = input("Enter the X number: ")
y = input("Enter the Y number: ")
return x, y
def checknumbers():
x, y=getnumbers()
if x > y:
print(f'x is larger then y: x is {x} and y is {y}')
elif y > x:
print(f"y is larger then x: x is {x} and y is {y}")
elif y == x:
print(f"x is equal to y: x is {x} and y is {y}")
else:
print("Dont know mate")
n = 0
while(n < 3):
checknumbers()
n += 1
This is the variant with the class:
class ui:
x = input("Enter the X number: ")
y = input("Enter the Y number: ")
def checknumbers():
if ui.x > ui.y:
print(f'x is larger then y: x is {ui.x} and y is {ui.y}')
elif ui.y > ui.x:
print(f"y is larger then x: x is {ui.x} and y is {ui.y}")
elif ui.y == ui.x:
print(f"x is equal to y: x is {ui.x} and y is {ui.y}")
else:
print("Dont know mate")
n = 0
while(n < 3):
checknumbers()
n += 1
Ideal solution, so both functions getnumbers() and checknumbers are clean cut independent of each other and they are being called inside the while loop, the problem is that x and y from the getnumbers() function are unknown to checknumbers.
The requirement is: I cant have any reference to any other function inside my functions, how do I pass x and y without referencing them?:
def getnumbers():
x = input("Enter the X number: ")
y = input("Enter the Y number: ")
return x, y
def checknumbers():
if x > y:
print(f'x is larger then y: x is {x} and y is {y}')
elif y > x:
print(f"y is larger then x: x is {x} and y is {y}")
elif y == x:
print(f"x is equal to y: x is {x} and y is {y}")
else:
print("Dont know mate")
n = 0
while(n < 3):
getnumbers()
checknumbers()
n += 1
You're getting confused between classes and instances, and between class attributes and instance attributes. (Read e.g. this)
The OO way to store state variables (like x,y) so you don't have to pass them around between function(/method) calls is to make them instance attributes. (Not class attributes, as you were doing. Don't worry, I did that too when I first learned Python).
So we declare a class UI; we will access its instance attributes as self.x, self.y inside its methods.
Don't try to directly do stuff on class UI. You must instantiate it first: ui = UI(). You should follow the Python convention that class names are Uppercase/CamelCase: UI, instance names are lowercase e.g. ui, ui1, ui2...
You were trying to put code directly into the class definition of UI, not define methods and put the code in that, and your UI class didn't even have an __init__()
Methods are functions inside a class, they always have a first argument self. If they didn't, the method wouldn't be able to access the rest of the class(!)
Now that we cleared that up, there are a couple of ways to decompose the methods to do what you want to do:
Have an empty __init__() (you could just make its body do pass). Have get_numbers() and check_numbers() be separate methods, which you manually call in-order. This is what I show below and is closest to what you said you want ("I want no reference to any function inside another function"), but is bad decomposition - what if the client called check_numbers() before get_numbers()? It would blow up on TypeError since __init__() initializes x,y with None.
Better would be to have __init__() call the method get_numbers() under-the-hood to guarantee the instance gets properly initialized. (We could always call get_numbers() again later if we want to input new numbers). That's easy to change, I leave that to you.
In approach 1., we had to initialize the instance members to something (otherwise trying to access them in check_numbers() will blow up). So we initialize to None, which will deliberately throw an exception if we compare. It doesn't really matter, this is just bad decomposition to not have __init__() properly initialize the instance (and call whatever methods it needs to to get that done). That's why approach 2. is better. Generally you should always have an __init__() that initializes the class into a known state, so that any other method can safely be called.
Code:
class UI:
def __init__(self, x=None, y=None):
self.x = x
self.y = y
def get_numbers(self):
self.x = input("Enter the X number: ")
self.y = input("Enter the Y number: ")
def check_numbers(self):
"""This is bad decomposition because if the client calls check_numbers() before get_numbers(), the NoneType will throw a TypeError"""
if self.x > self.y:
print(f'x is larger then y: x is {self.x} and y is {self.y}')
elif self.y > self.x:
print(f'y is larger then x: x is {self.x} and y is {self.y}')
elif self.y == self.x:
print(f'x is equal to y: x is {self.x} and y is {self.y}')
else:
print("Don't know mate")
# Declare an instance and reuse it three times
ui = UI()
for n in range(3):
ui.get_numbers()
ui.check_numbers()
Also, some minor stylistic points:
you don't need a while-loop for a simple counter: n = 0, while(n < 3) ... n += 1 . A for-loop is a one-liner: for n in range(3):
good Python style (see PEP-8) is to name the methods lower_case_with_underscores, thus get_numbers(), check_numbers()
a great top-down way to design a class is to write its method signatures first, think about what methods and attributes you'll need and how they'll work together. Example: "get_numbers() will get the user input, hence we'll need attributes self.x,y to store the numbers so check_numbers() can access them". And this way you should hit any problems with class design before you've written a wall of code.
If you don't want to call getnumbers() within checknumbers(), the only alternative that makes sense is to pass the numbers as parameters to checknumbers().
def getnumbers():
x = int(input("Enter the X number: "))
y = int(input("Enter the Y number: "))
return x,y
def checknumbers(x, y):
if x > y:
# etc.
...
for _ in range(3):
x,y = getnumbers()
checknumbers(x,y)
That at least has better separation of concerns.
I don't see anything wrong with the first solution (except for the fact that getumbers returns strings in Python 3) . Classes are not the solution for every problem
I cant have any reference of any other function inside my functions, how do I pass x and y without referencing them?
It's impossible to pass something without referencing it. Even if x and y were global variables (which is much worse than your current design) the using function would need to reference them.
I don't understand why you are under the impression that calling a function inside another function is bad or wrong design.

Python create an iterator/generator with feedback

Is it possible to create a iterator/generator which will decide on the next value based on some result on the previous iteration?
i.e.
y = None
for x in some_iterator(ll, y):
y = some_calculation_on(x)
I would like the logic of choosing the next x to depend on the calculation result allowing different logic for different results, much like in a search problem.
I also want to keep the how to choose the next x and the calculation on x as separate as possible.
Did you that you can send to a generator using generator.send? So yes, you can have a generator to change its behaviour based on feedback from the outside world. From the doc:
generator.send(value)
Resumes the execution and “sends” a value into the generator function.
The value argument becomes the result of the current yield expression.
The send() method returns the next value yielded by the generator
[...]
Example
Here is a counter that will increment only if told to do so.
def conditionalCounter(start=0):
while True:
should_increment = yield start
if should_increment:
start += 1
Usage
Since iteration with a for-loop does not allow to use generator.send, you have to use a while-loop.
import random
def some_calculation_on(value):
return random.choice([True, False])
g = conditionalCounter()
last_value = next(g)
while last_value < 5:
last_value = g.send(some_calculation_on(last_value))
print(last_value)
Output
0
0
1
2
3
3
4
4
5
Make it work in a for-loop
You can make the above work in a for-loop by crafting a YieldReceive class.
class YieldReceive:
stop_iteration = object()
def __init__(self, gen):
self.gen = gen
self.next = next(gen, self.stop_iteration)
def __iter__(self):
return self
def __next__(self):
if self.next is self.stop_iteration:
raise StopIteration
else:
return self.next
def send(self, value):
try:
self.next = self.gen.send(value)
except StopIteration:
self.next = self.stop_iteration
Usage
it = YieldReceive(...)
for x in it:
# Do stuff
it.send(some_result)
It's possible but confusing. If you want to keep the sequence of x values and the calculations on x separate, you should do this explicitly by not involving x with an iterator.
def next_value(x):
"""Custom iterator"""
# Bunch of code defining a new x
yield new_x
x = None
while True:
x = next_value(x)
x = some_calculation_on(x)
# Break when you're done
if finished and done:
break
If you want the loop to execute exactly i times, then use a for loop:
for step in range(i):
x = next_value(x)
x = some_calculation_on(x)
# No break
def conditional_iterator(y):
# stuff to create new values
yield x if (expression involving y) else another_x
for x in conditional_iterator(y):
y = some_computation(x)

Categories