Calling functions from main python - python

I have some python 3.4 code that works fine:
def run():
m = 0
while m != 1:
p = input('Please choose p: ')
p = makeInt(p)
#Some other code
print(p)
m = makeInt(input('Enter 1 if you would like to quit: '))
def makeInt(i):
try:
i = int(i)
except ValueError:
i = input('Incorrect input! Enter your answer: ')
i = makeInt(i)
return i
#Some other functions
if __name__ == '__main__':
run()
I want to put all this code in a class (Except possibly if __name__ ==...) When I put all the code including if __name__ ==... in a class like so:
class Foo(object):
def run(self):
m = 0
while m != 1:
p1 = input('Please choose p: ')
p1 = self.makeInt(p1)
#Some other code
print(p1)
m = self.makeInt(input('Enter 1 if you would like to quit: '))
def makeInt(self, i):
try:
i = int(i)
except ValueError:
i = input('Incorrect input! Enter your answer: ')
i = self.makeInt(i)
return i
#Some other functions and stuff
if __name__ == '__main__':
run()
I get the following error: TypeError: run() missing 1 required positional argument: 'self'. When I remove the self argument from run() it runs until makeInt() is called and then I get: NameError: name 'makeInt' is not defined. I get the same error if I take the if statement out of the class and call Foo.run(). I have some other code earlier in this program that works when I call functions of a class from another function in that same class. I realize I don't have to put all my code in a class, but in this case I want to. Why am I getting these errors and what can I do to put my working code in a class?

As others mentioned, by putting your functions in a class, you've made them methods, that means they need an instance of this class as first argument. So you can indeed call your run method using Foo().run() as Foo() will create an instance of Foo.
Another way (e.g. if you don't need the class for anything else than encapsulation) is to make them static, using the staticmethod decorator:
class Foo(object):
#staticmethod
def run():
...
#staticmethod
def makeInt(i):
...
if __name__ == '__main__':
Foo.run() # don't need an instance as run is static
In Python, a method can be static, i.e. no need for any special argument, a class method, i.e. first argument is the class itself, or a standard method, i.e. the first argument is an instance of the class.

Since you wrap your code within a class, your run() is a method now. You should remove your main from your class by unindenting it and initialize an instance of your class:
if __name__ == '__main__':
Foo().run()

It thinks the guard is a part of your class due to the indentation: you have your guard indented to the same level as the other class members. Unindent the
if __name__ == '__main__'
Also change it to be
if __name__ == '__main__':
main()
and then instantiate a new object of type Foo in your newly created main() function
def main():
newFoo = Foo()
newFoo.run()

Related

Method declared but not found in a class object

I just began the long and painful journey in Python Class Objects and try this:
class UgcObject:
def __init__(self, strPlateformeOld, strIdOld):
self.strPlateformeOld = strPlateformeOld
self.strIdOld = strIdOld
def GetApiUpdatedMetadata(self):
if self.strPlateforme == "youtube":
return True
def GetblnUpdatePossible(self):
return GetApiUpdatedMetadata()
if __name__ == '__main__':
ugc_test = UgcObject("youtube","id")
print(ugc_test.GetblnUpdatePossible())
I got an error message: NameError: name 'GetApiUpdatedMetadata' is not defined
I don't get why considering that I believe the GetApiUpdatedMetadata is declared and above the method that calls it.
What did I did wrong?
If you are trying to call another method in the same class it should have self. in front of it, and the variable name self.strPlateforme is wrong:
class UgcObject:
def __init__(self, strPlateformeOld, strIdOld):
self.strPlateformeOld = strPlateformeOld
self.strIdOld = strIdOld
def GetApiUpdatedMetadata(self):
if self.strPlateformeOld == "youtube":
return True
def GetblnUpdatePossible(self):
return self.GetApiUpdatedMetadata()
if __name__ == '__main__':
ugc_test = UgcObject("youtube","id")
print(ugc_test.GetblnUpdatePossible())

call class method but only generator being returned

I am trying to debug a method in a class. So in the iterative console I have imported my class using the line below.
from email_reader import MyClass
I then thought I just had to set an instance of my class like below.
ma_cls = MyClass('MyFolder')
Then I could call the function get_email like below,
ma_cls.get_email(filename, date_from, date_to)
When I run it the breakpoints never get hit and all that is returned is below.
Out[353]:
What am I doing wrong?
class MyClass:
def __init__(self,
outlook_folder: str):
self.__outlook_folder = outlook_folder
def get_email(self,
csv_filename: str,
emails_since: dt.datetime,
emails_to: dt.datetime = None,
unread_only: bool = False
):
breakpoint()
# some logic
if __name__ == "__main__":
breakpoint()
sse = MyClass("MyFolder")
for wt in sse.get_email(
'some_file_name.CSV',
emails_since=dt.datetime(2020, 2, 4),
emails_to=dt.datetime(2020, 2, 5),
unread_only=False):
pass
Code block in
if __name__ == "__main__":
is executed only when the script is run directly (when you directly execute the script that contains your MyClass). If you are importing the above file then everything that is inside the above if-statement is simply ignored.

Access "a method of a class" in "a function of another python file" by passing the class as that function's parameter

I have a class file. Let's call it "C1.py". The sample code looks like below.
class C1(object):
def __init__(self):
self.greeting = "Hello, world!"
def M1(ans):
if ans == 1 or ans == 2:
return True
else:
return False
Now, I have another python file in the same folder, which will access the class file shown above.
from trial import C1
def getAns(class1):
while True:
ans = input("Answer: ")
if class1.M1(ans):
return ans
break
sample = C1()
print sample.greeting
ans = getAns(sample)
print ans
When I run those files, sample.greeting prints fine. Everything is fine until when the execution reaches the line "ans = getAns(C1)", which gives the error "M1() takes exactly 1 argument (2 given)".
So, where in the code should I change so that I can call that method successfully?
Note here that the above code is only the abstraction of my whole program to highlight my problem. It sounds stupid with just the code above alone. So, please, please bear with that for me.
M1 is currently defined as a method of C1, as such it needs to have an additional self argument which would be the instance of the class. I.e
class C1(object):
def __init__(self):
self.greeting = "Hello, world!"
def M1(self, ans):
if ans == 1 or ans == 2:
return True
else:
return False
In other languages such as C++ or Java the presence of self (or this) is implicit, but in python it's explicit.
alternatively if you don't want or need M1 to access C1's state you could make M1 static via #staticmethod i.e.
class C1(object):
def __init__(self):
self.greeting = "Hello, world!"
#staticmethod
def M1(ans):
if ans == 1 or ans == 2:
return True
else:
return False

How to use mock to test a getter used for caching?

In the following class the property wheels has a cached value.
import time
class Car:
#property
def wheels(self):
if not hasattr(self, '_wheels'):
self._count_wheels()
return self._wheels
def _count_wheels(self):
time.sleep(10) # simulate a long calculation
self._wheels = 4
if __name__ == "__main__":
c = Car()
print(c.wheels) # calls _count_wheels() once
print(c.wheels) # no calls to _count_wheels()
I want to test that the first call to c.wheels calls once the method _count_wheels(); while the second call to c.wheels doesn't call the method _count_wheels()
I'd like to use unittest.mock
One simple solution is to mock the object yourself:
if __name__ == "__main__":
count = 0
to_mock = Car._count_wheels
def mocked(self):
global count
count +=1
if count>1:
raise ValueError("Called twice")
to_mock(self)
Car._count_wheels = mocked
c = Car()
print(c.wheels) # calls _count_wheels() once
try:
print(c.wheels) # no calls to _count_wheels()
except ValueError as e:
print e
You can try it with this modified Car class:
class Car:
#property
def wheels(self):
#if not hasattr(self, '_wheels'):
self._count_wheels()
return self._wheels
def _count_wheels(self):
#time.sleep(10) # simulate a long calculation
self._wheels = 4
And you will see it raises the exception. Since python is so dynamic this approach is always valid and sometimes is very useful, but of course you can use a third party tool as well ;)

Returning values from callback(s) in Python

I am currently looking at trying to use a callback in Python.
What I would like to do is return a value from the callback and then use this return value for conditional processing. So for example if the user enters "Y" I would like to print something to the console.
As I am new to Python the code below is as close as I can get currently but:
a) I am not sure if it is the Pythonic way of doing it
b) the correct way of doing it?
class Observable:
def subscribe(self,callback):
self.callback = callback
def fire(self):
self.callback()
class CallBackStuff:
def doCallback(self):
userInput = raw_input("Please enter Y or N?")
return userInput
if __name__ == '__main__':
s = CallBackStuff()
o = Observable()
o.subscribe(s.doCallback)
t = o.fire()
print t
The easiest way I can think of to do this in your code is to just store the input as
a variable in the CallBackStuff object. Then after you've called the call-back function, you can just access the input data from the CallBackStuff instance. Example below.
class Observable:
def subscribe(self,callback):
self.callback = callback
def fire(self):
self.callback()
class CallBackStuff:
storedInput = None # Class member to store the input
def doCallback(self):
self.storedInput = raw_input("Please enter Y or N?")
if __name__ == '__main__':
s = CallBackStuff()
o = Observable()
o.subscribe(s.doCallback)
o.fire()
print s.storedInput # Print stored input from call-back object
class Observable(object):
def __call__(self, fun):
return fun()
class Callback(object):
def docallback(self):
inp = raw_input()
return inp
if __name__ == "__main__":
print Observable()(Callback().docallback)

Categories

Resources