Inner class methods vs instance methods in python - python

I wrote a simple program that accepts input from the user and capitalizes it, obviously this can be done in different ways
class example():
def say_it(self):
result = input('what do you wanna say to the world')
return result
def get_result(self):
res = self.say_it()
return res
def capitalize(self):
res = self.get_result()
res = res.upper()
print(res)
def main():
Ex = example()
res = Ex.capitalize()
if __name__ == '__main__': main()
This program has 3 methods in the class body, then a new instance is created in the main function and only the capitalize method is called and the class does the whole magic and prints out a capitalized in put from the user making the whole main method look very clean
class example():
def say_it(self):
result = input('what do you wanna say to the world')
return result
def capitalize(self, words):
words = words.upper()
return words
def main():
Ex = example()
res = Ex.say_it()
final_result = Ex.capitalize(res)
print(final_result)
if __name__ == '__main__': main()
The second program does the same thing but it has less methods in the class body and more methods in the main method, it calls the methods in the class and works with the results returned, and then the final print statement is actually issued in the main method unlike the first program, thought it looks like the main method could get very confusing when the program expands and grows
My question is this which method will scale better in real life situations (i.e more readable, easier to debug) where they might be like 15 methods, will it be better to just call a single method that does all the magic and gets the result or call the methods one by one in the main method, i sometimes find myself writing programs the first way where i just call one method and the class handles everything else, Also is there any difference in speed between this two programs, which one will be faster?

Functions should do what they say they do. It is confusing to have a function called capitalize() that goes and calls a function to print and prompt and gather input.
A function shouldn't just call another function and not provide any value. The get_result() function doesn't serve a purpose. Calling say_it() instead produces the same result.
Your class should keep the data. That's the whole point of the object. Main can call the functions, but it shouldn't have the data. The words should have been stored in the class.
There is not perceptible performance difference between who calls the functions.

Related

python threading - multiple parameter and return

I have a method like this in Python :
def test(a,b):
return a+b, a-b
How can I run this in a background thread and wait until the function returns.
The problem is the method is pretty big and the project involves GUI, so I can't wait until it's return.
In my opinion, you should besides this thread run another thread that checks if there is result. Or Implement callback that is called at the end of the thread. However, since you have gui, which as far as I know is simply a class -> you can store result into obj/class variable and check if the result came.
I would use mutable variable, which is sometimes used. Lets create special class which will be used for storing results from thread functions.
import threading
import time
class ResultContainer:
results = [] # Mutable - anything inside this list will be accesable anywher in your program
# Lets use decorator with argument
# This way it wont break your function
def save_result(cls):
def decorator(func):
def wrapper(*args,**kwargs):
# get result from the function
func_result = func(*args,**kwargs)
# Pass the result into mutable list in our ResultContainer class
cls.results.append(func_result)
# Return result from the function
return func_result
return wrapper
return decorator
# as argument to decorator, add the class with mutable list
#save_result(ResultContainer)
def func(a,b):
time.sleep(3)
return a,b
th = threading.Thread(target=func,args=(1,2))
th.daemon = True
th.start()
while not ResultContainer.results:
time.sleep(1)
print(ResultContainer.results)
So, in this code, we have class ResultContainer with list. Whatever you put in it, you can easily access it from anywhere in the code (between threads and etc... exception is between processes due to GIL). I made decorator, so you can store result from any function without violating the function. This is just example how you can run threads and leave it to store result itself without you taking care of it. All you have to do, is to check, if the result arrived.
You can use global variables, to do the same thing. But I dont advise you to use them. They are ugly and you have to be very careful when using them.
For even more simplicity, if you dont mind violating your function, you can just, without using decorator, just push result to class with list directly in the function, like this:
def func(a,b):
time.sleep(3)
ResultContainer.results.append(tuple(a,b))
return a,b

Python class default to using one function

I'm trying to make a Python class (call it CLASS) in which there is a main function (call it FUNC) that most users will wish to use.
In this case I would like the user to be able to call the class name without the need to use brackets before the favourite function eg.:
CLASS(B, C) rather than CLASS().FUNC(B, C)
This is purely aesthetic but it means that for users who will use FUNC and not care about the other functions they could explicitly call, they don't need to write the annoying curly brackets.
Here is a simple code example of the kind of class I would create, where the main function (which I've called FUNC for continuity) utilises other functions in the class:
class Example:
def dummy_operation(self,A):
return A*2.
def FUNC(self,B,C):
A = self.dummy_operation(B)
result = A + C
return result
So here, Example takes the place of CLASS for legibility.
One way to do this looks like the use of an if '__main__' statement (see - Python main call within class).
However, as FUNC takes arguments B and C, this will return an error:
if __name__ == '__main__':
Example().target_function()
Out:
TypeError: target_function() missing 2 required positional arguments: 'B' and 'C'
Is there a way to pass Example(B,C), where in fact it is calling Example().FUNC(B,C) but one can still call Example().dummy_operation(A) if required?
Many thanks in advance!
This problem was solved by #snakecharmerb in the comments.
class Example:
def dummy_operation(self,A):
return A*2.
def __call__(self,B,C):
A = self.dummy_operation(B)
result = A + C
return result
Example = Example()
print(Example(1,1))
print(Example.dummy_operation(1))
Out:
3.0
2.0

Python - how to properly extend classes to modify the operation of base methods

I am using some open-source python code that I need to make a slight modification to. Here is the starting situation.
Starting Situation
class BaseGatherer:
def get_string(self):
#a bunch of stuff I don't need to modify
return self.my_string #set with a hard value in __init__()
class BaseDoer:
def do_it(self, some_gatherer):
#a bunch of stuff I don't need to modify
string_needed = some_gatherer.get_string()
self.do_stuff(string_needed)
Externally, this would get used as follows:
my_gatherer = BaseGatherer()
my_doer = BaseDoer()
my_doer.do_it(my_gatherer)
What I need to change
What I need to do is two things:
Have BaseGatherer::get_string() return it's my_string with an inserted modification that changes each time it gets called. For example, the first time it gets called I get my_string[0:1] + 'loc=0' + my_string[1:], the second time I get 'my_string[0:1] + 'loc=10' + my_string[1:], etc.
Modify BaseDoer::do_it() to call BaseDoer::do_stuff() in a loop (until some stopping condition), each time setting string_needed with some_gatherer.get_string() which by #1 returns a different string with each call.
with the following restriction
The base code I am using is regularly updated and I don't want to modify that code at all; I want to be able to clone the repo I get it from and only possibly have to modify my "extended" code. It's ok to assume the names of the BaseGatherer and BaseDoer classes don't change in the base code, nor do the names of the methods I care about here, though some auxiliary methods that I don't need to modify will get updated (which is key for me).
My Question
My main question is what is the best, most Pythonic, way to do this?
My Attempt
Given the restriction I mentioned, my first inclination is to write derived classes of both BaseGatherer and BaseDoer which make the changes I need by writing new versions of the get_string() and do_it() methods respectively. But, I have a feeling that I should use function decorators to do this. I've read up on them a little and I get the basic idea (they wrap a function so that you can control/modify parameters passed to or values returned from the function you are wrapping without modifying that function?; please correct me if I am missing something crucial). But, I don't know how to implement this in the derived class, neither syntactically nor logically. For example, do I have to give the function decorator that I write a #classmethod decorator? If so, why?
Here is what I did. It works but I want to learn and understand a) what is the right way to do what I want and b) how to actually do it.
class DerivedGatherer(BaseGatherer):
def __init__(self):
super(DerivedGatherer, self).__init__() #I'm in Python 2.7 :(
self.counter = 0 #new variable not in BaseGatherer
#DON'T override BaseGatherer::get_string(), just write a new function
def get_string_XL(self):
self.counter += 10
return self.my_string[0:1] + 'loc=' + str(self.counter) + self.my_string[1:]
class DerivedDoer(BaseDoer):
def do_it_XL(self, some_derived_gatherer):
while(~some_stop_condition()):
string_needed = some_derived_gatherer.get_string_XL()
self.do_stuff(string_needed)
I would then call it just as above but create derived instances and call their XL methods instead of the base class one's.
But, there are problems with this that don't satisfy my goal/requirement above: both BaseGatherer::get_string() and BaseDoer::do_it() perform a lot of other functionality which I would have to just copy into my new functions (see the comment in them). This means when the code I'm using gets updated I have to do the copying to update my derived classes. But, I am ONLY changing what you see here: inserting something into the string that changes with each call and putting a loop at the end of do_it(). This is why I have a feeling that function decorators are the way to go. That I can wrap both get_string() and do_it() so that for the former I can modify the string with each call by looking at a local counter and for the second I can just have a loop that calls the base do_it() in a loop and passes a different string each time (it's ok to call do_it() multiple times).
Any help with suggestions on the best way to do this and how would be very greatly appreciated.
Thank you!
This is most easily done with plain inheritance, no repetition of code:
class DerivedGatherer(BaseGatherer):
def __init__(self):
super(DerivedGatherer, self).__init__()
self.counter = 0
def get_string(self):
self.counter += 10
super_string = super(DerivedGatherer, self).get_string()
return super_string[0:1] + 'loc=' + str(self.counter) + super_string[1:]
class DerivedDoer(BaseDoer):
def do_it(self, some_derived_gatherer):
while(~some_stop_condition()):
super(DerivedDoer, self).do_it(some_derived_gatherer)
As Martijn has explained to you, you can easily call a method in the base class from a method in the subclass. You can do it with super to insure you get the entire class structure as he shows. For illustration, though, if you are have a simple hierarchy with only one superclass and one subclass, this is how you can do it:
>>> class Foo(object):
... def xxx(self):
... return "Foo.xxx was called"
...
>>> class Bar(Foo):
... def xxx(self):
... return "Bar.xxx was called and then %s" % Foo.xxx(self)
...
>>> Bar().xxx()
'Bar.xxx was called and then Foo.xxx was called'

Python: communication between "faraway" classes on the same call chain

I have this start.py:
# start.py
class Start:
def __init__(self):
self.mylist = []
def run(self):
# some code
Executing its run() method will at some point invoke the put_item(obj) method in moduleX.py:
# moduleX.py
def put_item(obj):
# what should I write here
run() is NOT the direct caller of put_item(obj). In fact, from run() to put_item(obj) the execution is quite complex and involves a lot of other invocations.
My problem is, when put_item(obj) is called, can I directly add the value of obj back to mylist in the class Start? For example:
s = Start()
# suppose during this execution, put_item(obj) has been
# invoked 3 times, with obj equals to 1, 2, 3 each time
s.run()
print(s.mylist) # I want it to be [1,2,3]
UPDATE:
From run() to put_item(obj) the execution involves heavy usages of 3rd-party modules and function calls that I have no control over. In other words, the execution inbetween run() to put_item(obj) is like a blackbox to me, and this execution leads to the value of obj that I'm interested in.
obj is consumed in put_item(obj) in moduleX.py, which is also a 3rd-party module. put_item(obj) originally has GUI code that displays obj in a fancy way. However, I want to modify its original behavior such that I can add obj to mylist in class Start and use mylist later in my own way.
Therefore, I cannot pass Start reference along the call chain to put_item since I don't know the call chain and I simply cannot modify it. Also, I cannot change the method signatures in moduleX.py otherwise I'll break the original API. What I can change is the content of put_item(obj) and the start.py.
Simply make put_item return the item you want to put in your instance:
def put_item():
# some code
return 42
class Start:
def __init__(self):
self.mylist = []
def run(self):
# some code
self.mylist.append(put_item())
s = Start()
s.run()
print(s.mylist)
Prints:
[42]
Yes, you can, but you will have to propagate a reference to your Start object's list down the call stack to put_item(). Your Start object can then add items to the list. It does not have to know or care that the object it is being passed is in the Start. It can just blindly add them.
For example (Ideone):
class Start:
def __init__(self):
self.mylist = []
def run(self):
foo(self.mylist)
print(self.mylist)
def foo(listRef):
bar(listRef)
def bar(listRef):
someItem = "Hello, World!"
put_item(listRef, someItem)
def put_item(listRef, obj):
listRef.append(obj)
x = Start()
x.run()
Of course, you'll get the appropriate runtime error if the thing you pass to foo turns out not to be a list.

Python 3: Calling a Function from a class, self

I am trying to learn about classes, can someone explain to me why this code is not working. I thought when calling a function from a class, "self" is automatically ommitted, but the interpreter tells me that argument "a" is missing (he thinks self = 10).
#! coding=utf-8
class test:
def __init__(self):
"do something here"
def do(self,a):
return a**2
d = test.do
print(d(10))
Instantiate the class first:
d = test().do
print(d(10)) # prints 100
test.do is an unbound method, test().do is bound. The difference is explained in this thread: Class method differences in Python: bound, unbound and static.
You have to instantiate the class first:
d = test()
then you can call a method:
print(d.do(10))
if you want to use method statically you have to declare it in python
#! coding=utf-8
class test:
def __init__(self):
"do something here"
#staticmethod
def do(a):
return a**2
d = test.do
print(d(10)) #and that's work
Since you haven't instantiated the class (a fancy term for created) you can't be assigning methods to any random variable. Like already said, you must create the object first, whilst making sure the method you call is a part of the class you called or connected to the class in some way (such as creating another class and then communicating that class with the current class). So you should first type d=test() followed by d.do().
Also, remember that in your declaration of the method you crated a parameter so what you done was wrong in itself anyway, because when you declared the do function, you should have put within the brackets the number you wanted to send to the method to calculate its square. So you type test.do(10) and then the 10 is sent by the self reference to the method to be done whatever it is you told it to do.
One more thing: although it isn't a huge deal, it helps if all of your class names begin with a capital letter, as this is usually the 'pythonic' way to do things, and it also makes your code much easier to read, because when you first called the class, somebody could easily mistaken it for an ordinary function
class test:
def __init__(self):
"do something here"
def do(self,a):
return a**2
def __call__(self,a):
return self.do(a)
a = test
test.do(a,10)
#or
a = test().do
a(10)
#or
a = test()
test.do(a,10)
#or
a = test()
print(a(10))

Categories