How to implement a submethod in a Python-class? - python

I appologize, if I didn't express my self clearly. What I want to do is this:
class someClass(object):
def aMethod(self, argument):
return some_data #for example a list or a more complex datastructure
def aMethod_max(self, argument):
var = self.aMethod(argument)
#do someting with var
return altered_var
or I could do:
def aMethod(self, argument):
self.someVar = some_data
return some_data #for example a list or a more complex datastructure
def aMethod_max(self, argument):
if not hasattr(self, someVar):
self.aMethod(argument)
#do someting with self.var
return altered_var
But I considered this too complicated and hoped for a more elegant solution. I hope that it's clear now, what I want to accomplish.
Therefore I phantasized about something like in the following paragraph.
class someClass(object):
someMethod(self):
#doSomething
return result
subMethod(self):
#doSomething with the result of someMethod
Foo = someClass()
Foo.someMethod.subMethod()
or if someMethod has an argument something like
Foo.someMethod(argument).subMethod()
How would I do something like this in python?
EDIT: or like this?
subMethod(self):
var = self.someMethod()
return doSomething(var)

Let's compare the existing solutions already given in your question (e.g. the ones you call "complicated" and "inelegant") with your proposed alternative.
The existing solutions mean you will be able to write:
foo.subMethod() # foo.someMethod() is called internally
but your proposed alternative means you have to write:
foo.someMethod().subMethod()
which is obviously worse.
On the other hand, if subMethod has to be able to modify the result of any method, rather than just someMethod, then the existing solutions would mean you have to write:
foo.subMethod(foo.anyMethod())
with the only disadvantage here being that you have to type foo twice, as opposed to once.
Conclusion: on the whole, the existing solutions are less complicated and inelegant than your proposed alternative - so stick with the existing solutions.

You can do method chaining when the result of someMethod is an instance of someClass.
Simple example:
>>> class someClass:
... def someMethod(self):
... return self
... def subMethod(self):
... return self.__class__
...
>>> x=someClass()
>>> x
<__main__.someClass instance at 0x2aaaaab30d40>
>>> x.someMethod().subMethod()
<class __main__.someClass at 0x2aaaaab31050>

Not sure if I'm understanding it right, but perhaps you mean this:
Foo.subMethod(Foo.someMethod())
This passes the result of someMethod() to subMethod(). You'd have to change your current definition of subMethod() to accept the result of someMethod().

You can achieve something similar using decorators:
def on_result(f):
def decorated(self,other,*args,**kwargs):
result = getattr(self,other)(*args,**kwargs)
return f(result)
return decorated
Usage:
class someClass(object):
def someMethod(self,x,y):
#doSomething
result = [1,2,3,x,y] # example
return result
#on_result
def subMethod(self):
#doSomething with the result of someMethod
print self # example
Foo = someClass()
Foo.subMethod("someMethod",4,5)
Output:
[1, 2, 3, 4, 5]
As you see, the first argument is the name of the method to be chained, and the remaining ones will be passed to it, no matter what its signature is.
EDIT: on second thought, this is rather pointless, since you could always use
Foo.submethod(Foo.someMethod(4,5))...
Maybe I didn't understand what you're trying to achieve. Does the subMethod have to be linked to a specific method only? Or maybe it's the syntatic form
a.b().c()
that's important to you? (in that case, see kojiro's answer)

From the feedback so far, I understand that subMethod will link only to someMethod, right? Maybe you can achieve this combining a decorator with a closure:
def on_result(other):
def decorator(f):
def decorated(self,*a1,**k1):
def closure(*a2,**k2):
return f(self,getattr(self,other)(*a1,**k1),*a2,**k2)
return closure
return decorated
return decorator
class someClass(object):
def someMethod(self,a,b):
return [a,2*b]
#on_result('someMethod')
def subMethod(self,result,c,d):
result.extend([3*c,4*d])
return result
Foo = someClass()
print Foo.subMethod(1,2)(3,4) # prints [1,4,9,16]
The decorator is kinda "ugly", but once written it's usage is quite elegant IMHO (plus, there are no contraints in the signature of either method).
Note: I'm using Python 2.5 and this is the only way I know of writing decorators that take arguments. There's probably a better way, but I'm too lazy to look it up right now...

Related

What is the difference between a higher-order function and a class?

I was going through the basics of functional programming, and eventually came accross the concept of higher-order functions. I saw an example in this video by Corey Schafer (starts at 11:00), which shows a Python function that can wrap messages in arbitrary HTML tags:
def html_tag(tag):
def wrap_text(msg):
print('<{0}>{1}</{0}>'.format(tag, msg))
return wrap_text
print_h1 = html_tag('h1')
print_h1('Test Headline!')
print_h1('Another Headline!')
print_p = html_tag('p')
print_p('Test Paragraph!')
Output:
<h1>Test Headline!</h1>
<h1>Another Headline!</h1>
<p>Test Paragraph!</p>
I get that it gives you the flexibility of re-using the same function for different purposes (different tags, in this example). But you could achieve the same result using Python classes, too:
class HTML_tag:
def __init__(self, tag):
self.tag = tag
def wrap_text(self, msg):
print('<{0}>{1}</{0}>'.format(self.tag, msg))
print_h1 = HTML_tag('h1')
print_h1.wrap_text('Test Headline!')
print_h1.wrap_text('Another Headline!')
print_p = HTML_tag('p')
print_p.wrap_text('Test Paragraph!')
Output:
<h1>Test Headline!</h1>
<h1>Another Headline!</h1>
<p>Test Paragraph!</p>
The higher-order function approach definitely looks cleaner, but apart from the aesthetics, are there any other reasons I might want to prefer a higher-order function over a class? E.g., regarding aspects like
Performance
Memory
...
Higher order functions take and/or return functions. Let's look at both cases.
Taking a function as a parameter
Here, a HOF is definitely the way to go. The class version amounts to a HOF with extra steps. For the class version, you need to have pre-negotiated the key the function is callable on. It's really a useless wrapper around the meat of what you're trying to accomplish.
HOF
def my_map(fn, arr):
result = []
for a in arr:
result.append(fn(a))
return result
my_map(lambda a: a + 1, [1, 2, 3]) # [2, 3, 4]
Class version
def my_map(inst, arr):
result = []
for a in arr:
result.append(inst.fn(a))
return result
class my_mapper:
def fn(self, a):
return a + 1
my_map(my_mapper(), [1, 2, 3]) # [2, 3, 4]
Returning a function
In both versions here, what we're doing is creating an encapsulation of some value a, and a function that works over it.
I think that a class is generally useful if you want more than one function to be defined over some data, when the encapsulated data can change (you're encoding a state machine), or when you expect operations to be specific to your class (ie. users of your class need to know the operations defined over the class).
I would use a function that returns a function, when what I'm doing amounts to partial application, (I have a function that takes multiple parameters, and I want to preapply some, like 'add'). I would also use functools.partial to do this.
def adder(a):
return lambda b: a + b
class adder_class:
def __init__(self, a):
self.a = a
def add(self, b):
return a + b
Ultimately, whether it's best to use a HOF or a class will become clear from context.

Return values automatically in python class

I am a new python user. Thus it might be very silly. But what is the best way to run a class automatically (which has several functions inside) and return the result for a given value. for example:
class MyClass():
def __init__(self,x):
self.x=x
def funct1(self):
return (self.x)**2
##or any other function
def funct2(self,y):
return y/100.0
##or any other function
def wrapper(self):
y=self.funct1()
z=self.funct2(y)
##or other combination of functions
return z
Right now to run this, I am using:
run=MyClass(5)
run.wrapper()
But I want to run like this:
MyClass(5)
Which will return a value and can be saved inside a variable with out needing to use the wrapper function.
You can create a functor as below:
class MyClass(object):
def __init__(self,x):
self.x=x
def funct1(self):
return (self.x)**2
##or any other function
def funct2(self,y):
return y/100.0
##or any other function
def __call__(self):
y=self.funct1()
z=self.funct2(y)
##or other combination of functions
return z
The call to this functor will be like as follow:
MyClass(5)() # Second () will call the method __call__. and first one will call constructor
Hope this will help you.
So when you write MyClass(5), you're instatiating a new instance of that class: MyClass and so the short answer is no, you do need the wrapper because when you instantiate the class it will necessarily return the object and not a certain value.
If you want to just return a value based on the input (say 5) consider using a function instead.
The function would be like:
def my_func(x):
y = x**2
z = y/100.0
return z
There a lots of reasons to use classes, see this answer https://stackoverflow.com/a/33072722/4443226 -- but if you're just concerned with the output of an operation/equation/function then I'd stick with functions.
__init__ method should return None.
documentation link
no non-None value may be returned by init()

Return from method if other method succeeds with one line

I have trouble finding a fitting title for this question, so please forgive me.
Many methods in my class look like this:
def one_of_many():
# code to determine `somethings`
for something in somethings:
if self.try_something(something):
return
# code to determine `something_else`
if self.try_something(something_else):
return
…
where self.try_something returns True or False.
Is there a way to express this with something like:
def one_of_many():
# code to determine `somethings`
for something in somethings:
self.try_something_and_return(something) # this will return from `one_of_many` on success
# code to determine `something_else`
self.try_something_and_return(something_else) # this will return from `one_of_many` on success
…
I was fiddling with decorators and context managers to make this happen with no success but I still believe that "There must be a better way!".
It looks like itertools to the rescue:
When you say method, I assume this is a method of a class so the code could look like this:
import itertools
class Thing:
def one_of_many(self):
# code to determine `somethings`
for something in itertools.chain(somethings,[something_else]):
if self.try_something(something):
return
Hopefully something_else is not too difficult to compute.
Hopefully this mcve mimics your problem:
a = [1,2,3]
b = 3
def f(thing):
print(thing)
return False
class F:
pass
self = F()
self.trysomething = f
Map the method to all the things and take action if any return True
if any(map(self.trysomething, a + [b])):
print('yeay')
else:
print('nay')
Depending on what a and b actually are you may have to play around with ways to concatenate or flatten/add or chain as #quamrana mentioned.
if self.try_something(a_thing) or self.try_something(another_thing):
return
But you'll either need to know your thing's beforehand.. or calculate them with an expression within the function call.

What does "bound method" error mean when I call a function?

I am creating a word parsing class and I keep getting a
bound method Word_Parser.sort_word_list of <__main__.Word_Parser instance at 0x1037dd3b0>
error when I run this:
class Word_Parser:
"""docstring for Word_Parser"""
def __init__(self, sentences):
self.sentences = sentences
def parser(self):
self.word_list = self.sentences.split()
def sort_word_list(self):
self.sorted_word_list = self.word_list.sort()
def num_words(self):
self.num_words = len(self.word_list)
test = Word_Parser("mary had a little lamb")
test.parser()
test.sort_word_list()
test.num_words()
print test.word_list
print test.sort_word_list
print test.num_words
There's no error here. You're printing a function, and that's what functions look like.
To actually call the function, you have to put parens after that. You're already doing that above. If you want to print the result of calling the function, just have the function return the value, and put the print there. For example:
print test.sort_word_list()
On the other hand, if you want the function to mutate the object's state, and then print the state some other way, that's fine too.
Now, your code seems to work in some places, but not others; let's look at why:
parser sets a variable called word_list, and you later print test.word_list, so that works.
sort_word_list sets a variable called sorted_word_list, and you later print test.sort_word_list—that is, the function, not the variable. So, you see the bound method. (Also, as Jon Clements points out, even if you fix this, you're going to print None, because that's what sort returns.)
num_words sets a variable called num_words, and you again print the function—but in this case, the variable has the same name as the function, meaning that you're actually replacing the function with its output, so it works. This is probably not what you want to do, however.
(There are cases where, at first glance, that seems like it might be a good idea—you only want to compute something once, and then access it over and over again without constantly recomputing that. But this isn't the way to do it. Either use a #property, or use a memoization decorator.)
This problem happens as a result of calling a method without brackets. Take a look at the example below:
class SomeClass(object):
def __init__(self):
print 'I am starting'
def some_meth(self):
print 'I am a method()'
x = SomeClass()
''' Not adding the bracket after the method call would result in method bound error '''
print x.some_meth
''' However this is how it should be called and it does solve it '''
x.some_meth()
You have an instance method called num_words, but you also have a variable called num_words. They have the same name. When you run num_words(), the function replaces itself with its own output, which probably isn't what you want to do. Consider returning your values.
To fix your problem, change def num_words to something like def get_num_words and your code should work fine. Also, change print test.sort_word_list to print test.sorted_word_list.
For this thing you can use #property as an decorator, so you could use instance methods as attributes. For example:
class Word_Parser:
def __init__(self, sentences):
self.sentences = sentences
#property
def parser(self):
self.word_list = self.sentences.split()
#property
def sort_word_list(self):
self.sorted_word_list = self.word_list.sort()
#property
def num_words(self):
self.num_words = len(self.word_list)
test = Word_Parser("mary had a little lamb")
test.parser()
test.sort_word_list()
test.num_words()
print test.word_list
print test.sort_word_list
print test.num_words
so you can use access the attributes without calling (i.e., without the ()).
I think you meant print test.sorted_word_list instead of print test.sort_word_list.
In addition list.sort() sorts a list in place and returns None, so you probably want to change sort_word_list() to do the following:
self.sorted_word_list = sorted(self.word_list)
You should also consider either renaming your num_words() function, or changing the attribute that the function assigns to, because currently you overwrite the function with an integer on the first call.
The syntax problem is shadowing method and variable names. In the current version sort_word_list() is a method, and sorted_word_list is a variable, whereas num_words is both. Also, list.sort() modifies the list and replaces it with a sorted version; the sorted(list) function actually returns a new list.
But I suspect this indicates a design problem. What's the point of calls like
test.parser()
test.sort_word_list()
test.num_words()
which don't do anything? You should probably just have the methods figure out whether the appropriate counting and/or sorting has been done, and, if appropriate, do the count or sort and otherwise just return something.
E.G.,
def sort_word_list(self):
if self.sorted_word_list is not None:
self.sorted_word_list = sorted(self.word_list)
return self.sorted_word_list
(Alternately, you could use properties.)
Your helpful comments led me to the following solution:
class Word_Parser:
"""docstring for Word_Parser"""
def __init__(self, sentences):
self.sentences = sentences
def parser(self):
self.word_list = self.sentences.split()
word_list = []
word_list = self.word_list
return word_list
def sort_word_list(self):
self.sorted_word_list = sorted(self.sentences.split())
sorted_word_list = self.sorted_word_list
return sorted_word_list
def get_num_words(self):
self.num_words = len(self.word_list)
num_words = self.num_words
return num_words
test = Word_Parser("mary had a little lamb")
test.parser()
test.sort_word_list()
test.get_num_words()
print test.word_list
print test.sorted_word_list
print test.num_words
and returns:
['mary', 'had', 'a', 'little', 'lamb']
['a', 'had', 'lamb', 'little', 'mary']
5
Thank you all.
Bound method error also occurs (in a Django app for instnce) , if you do a thing as below:
class Products(models.Model):
product_category = models.ForeignKey(ProductCategory, on_delete=models.Protect)
def product_category(self)
return self.product_category
If you name a method, same way you named a field.

How to call Python functions dynamically [duplicate]

This question already has answers here:
Calling a function of a module by using its name (a string)
(18 answers)
Closed 4 months ago.
I have this code:
fields = ['name','email']
def clean_name():
pass
def clean_email():
pass
How can I call clean_name() and clean_email() dynamically?
For example:
for field in fields:
clean_{field}()
I used the curly brackets because it's how I used to do it in PHP but obviously doesn't work.
How to do this with Python?
If don't want to use globals, vars and don't want make a separate module and/or class to encapsulate functions you want to call dynamically, you can call them as the attributes of the current module:
import sys
...
getattr(sys.modules[__name__], "clean_%s" % fieldname)()
Using global is a very, very, bad way of doing this. You should be doing it this way:
fields = {'name':clean_name,'email':clean_email}
for key in fields:
fields[key]()
Map your functions to values in a dictionary.
Also using vars()[] is wrong too.
It would be better to have a dictionary of such functions than to look in globals().
The usual approach is to write a class with such functions:
class Cleaner(object):
def clean_name(self):
pass
and then use getattr to get access to them:
cleaner = Cleaner()
for f in fields:
getattr(cleaner, 'clean_%s' % f)()
You could even move further and do something like this:
class Cleaner(object):
def __init__(self, fields):
self.fields = fields
def clean(self):
for f in self.fields:
getattr(self, 'clean_%s' % f)()
Then inherit it and declare your clean_<name> methods on an inherited class:
cleaner = Cleaner(['one', 'two'])
cleaner.clean()
Actually this can be extended even further to make it more clean. The first step probably will be adding a check with hasattr() if such method exists in your class.
I have come across this problem twice now, and finally came up with a safe and not ugly solution (in my humble opinion).
RECAP of previous answers:
globals is the hacky, fast & easy method, but you have to be super consistent with your function names, and it can break at runtime if variables get overwritten. Also it's un-pythonic, unsafe, unethical, yadda yadda...
Dictionaries (i.e. string-to-function maps) are safer and easy to use... but it annoys me to no end, that i have to spread dictionary assignments across my file, that are easy to lose track of.
Decorators made the dictionary solution come together for me. Decorators are a pretty way to attach side-effects & transformations to a function definition.
Example time
fields = ['name', 'email', 'address']
# set up our function dictionary
cleaners = {}
# this is a parametered decorator
def add_cleaner(key):
# this is the actual decorator
def _add_cleaner(func):
cleaners[key] = func
return func
return _add_cleaner
Whenever you define a cleaner function, add this to the declaration:
#add_cleaner('email')
def email_cleaner(email):
#do stuff here
return result
The functions are added to the dictionary as soon as their definition is parsed and can be called like this:
cleaned_email = cleaners['email'](some_email)
Alternative proposed by PeterSchorn:
def add_cleaner(func):
cleaners[func.__name__] = func
return func
#add_cleaner
def email():
#clean email
This uses the function name of the cleaner method as its dictionary key.
It is more concise, though I think the method names become a little awkward.
Pick your favorite.
globals() will give you a dict of the global namespace. From this you can get the function you want:
f = globals()["clean_%s" % field]
Then call it:
f()
Here's another way:
myscript.py:
def f1():
print 'f1'
def f2():
print 'f2'
def f3():
print 'f3'
test.py:
import myscript
for i in range(1, 4):
getattr(myscript, 'f%d' % i)()
I had a requirement to call different methods of a class in a method of itself on the basis of list of method names passed as input (for running periodic tasks in FastAPI). For executing methods of Python classes, I have expanded the answer provided by #khachik. Here is how you can achieve it from inside or outside of the class:
>>> class Math:
... def add(self, x, y):
... return x+y
... def test_add(self):
... print(getattr(self, "add")(2,3))
...
>>> m = Math()
>>> m.test_add()
5
>>> getattr(m, "add")(2,3)
5
Closely see how you can do it from within the class using self like this:
getattr(self, "add")(2,3)
And from outside the class using an object of the class like this:
m = Math()
getattr(m, "add")(2,3)
Here's another way: define the functions then define a dict with the names as keys:
>>> z=[clean_email, clean_name]
>>> z={"email": clean_email, "name":clean_name}
>>> z['email']()
>>> z['name']()
then you loop over the names as keys.
or how about this one? Construct a string and use 'eval':
>>> field = "email"
>>> f="clean_"+field+"()"
>>> eval(f)
then just loop and construct the strings for eval.
Note that any method that requires constructing a string for evaluation is regarded as kludgy.
for field in fields:
vars()['clean_' + field]()
In case if you have a lot of functions and a different number of parameters.
class Cleaner:
#classmethod
def clean(cls, type, *args, **kwargs):
getattr(cls, f"_clean_{type}")(*args, **kwargs)
#classmethod
def _clean_email(cls, *args, **kwargs):
print("invoked _clean_email function")
#classmethod
def _clean_name(cls, *args, **kwargs):
print("invoked _clean_name function")
for type in ["email", "name"]:
Cleaner.clean(type)
Output:
invoked _clean_email function
invoked _clean_name function
I would use a dictionary which mapped field names to cleaning functions. If some fields don't have corresponding cleaning function, the for loop handling them can be kept simple by providing some sort of default function for those cases. Here's what I mean:
fields = ['name', 'email', 'subject']
def clean_name():
pass
def clean_email():
pass
# (one-time) field to cleaning-function map construction
def get_clean_func(field):
try:
return eval('clean_'+field)
except NameError:
return lambda: None # do nothing
clean = dict((field, get_clean_func(field)) for field in fields)
# sample usage
for field in fields:
clean[field]()
The code above constructs the function dictionary dynamically by determining if a corresponding function named clean_<field> exists for each one named in the fields list. You likely would only have to execute it once since it would remain the same as long as the field list or available cleaning functions aren't changed.

Categories