Python class default to using one function - python

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

Related

Pass closure to FunctionType in function

I have a code like this:
class A():
def __init__(self, a):
self.a = a
def outer_method(self):
def inner_method():
return self.a +1
return inner_method()
I want to write a test for inner_method. For that, I am using a code like this:
def find_nested_func(parent, child_name):
"""
Return the function named <child_name> that is defined inside
a <parent> function
Returns None if nonexistent
"""
consts = parent.__code__.co_consts
item = list(filter(lambda x:isinstance(x, CodeType) and x.co_name==child_name, consts ))[0]
return FunctionType(item, globals())
Calling it with find_nested_func(A().outer_method, 'inner_method') but it fails when calling to 'FunctionType' because the function cannot be created since 'self.a' stops existing in the moment the function stops being an inner function. I know the construction FunctionType can recive as an argument a closure that could fix this problem , but I don't know how to use it. How can I pass it?
The error it gives is the next one:
return FunctionType(item, globals())
TypeError: arg 5 (closure) must be tuple
Why are you trying to test inner_method? In most cases, you should only test parts of your public API. outer_method is part of A's public API, so test just that. inner_method is an implementation detail that can change: what if you decide to rename it? what if you refactor it slightly without modifying the externally visible behavior of outer_method? Users of the class A have no (easy) way of calling inner_method. Unit tests are usually only meant to test things that users of your class can call (I'm assuming these are for unit tests, because integration tests this granular would be strange--and the same principle would still mostly hold).
Practically, you'll have a problem extracting functions defined within another function's scope, for several reasons include variable capture. You have no way of knowing if inner_method only captures self or if outer_method performs some logic and computes some variables that inner_method uses. For example:
class A:
def outer_method():
b = 1
def inner_method():
return self.a + b
return inner_method()
Additionally, you could have control statements around the function definition, so there is no way to decide which definition is used without running outer_method. For example:
import random
class A:
def outer_method():
if random.random() < 0.5:
def inner_method():
return self.a + 1
else:
def inner_method():
return self.a + 2
return inner_method()
You can't extract inner_method here because there are two of them and you don't know which is actually used until you run outer_method.
So, just don't test inner_method.
If inner_method is truly complex enough that you want to test it in isolation (and if you do so, principled testing says you should mock out its uses, eg. its use in outer_method), then just make it a "private-ish" method on A:
class A:
def _inner_method(self):
return self.a + 1
def outer_method(self):
return self._inner_method()
Principled testing says you really shouldn't be testing underscore methods, but sometimes necessity requires it. Doing this things way allows you test _inner_method just as you would any other method. Then, when testing outer_method, you could mock it out by doing a._inner_method = Mock() (where a is the A object under test).
Also, use class A. The parens are unnecessary unless you have parent classes.

Python - Is it possible to define an instance method inside another instance method?

Is it possible to do something like this? (This syntax doesn't actually work)
class TestClass(object):
def method(self):
print 'one'
def dynamically_defined_method(self):
print 'two'
c = TestClass()
c.method()
c.dynamically_defined_method() #this doesn't work
If it's possible, is it terrible programming practice? What I'm really trying to do is to have one of two variations of the same method be called (both with identical names and signatures), depending on the state of the instance.
Defining the function in the method doesn't automatically make it visible to the instance--it's just a function that is scoped to live within the method.
To expose it, you'd be tempted to do:
self.dynamically_defined_method = dynamically_defined_method
Only that doesn't work:
TypeError: dynamically_defined_method() takes exactly 1 argument (0 given)
You have to mark the function as being a method (which we do by using MethodType). So the full code to make that happen looks like this:
from types import MethodType
class TestClass(object):
def method(self):
def dynamically_defined_method(self):
print "two"
self.dynamically_defined_method = MethodType(dynamically_defined_method, self)
c = TestClass()
c.method()
c.dynamically_defined_method()

TypeError for a function with a string parameter

I am trying to create a simple function that allows me to return a string reversed. However, when I call the function, the error
TypeError: reverseString() takes 1 positional argument but 2 were given
comes up. I'm more familiar with Java, and was wondering what the problem is and if passing a string parameter is the same in Python.
Class myString()
def reverseString(string):
return string[:,:,-1]
p = myString()
p.reversedString('Eric')
Python requires a special first parameter for methods to which it passes the instance that the method is being called on. You can use pretty much any valid variable name, but it's a Python convention to use self and it will make your code easier for other people to read.
class myString:
def reverseString(self, string):
return string[::-1]
p = myString()
print(p.reverseString('Eric'))
To access instance variables, you would use self.var - you can't just do var like in Java.
Also, as #jonrshape pointed out in the comments, you don't need to wrap functions in a class:
def reverseString(string):
return string[::-1]
print(reverseString('Eric'))

Python OOP init

class Sequence:
TranscriptionTable = {
"A":"U",
"T":"A",
"C":"G",
"G":"C"
}
def __init__(self, seqstring):
self.seqstring = seqstring.upper()
def transcription(self):
tt = ""
for x in self.seqstring:
if x in 'ATGC':
tt += self.TranscriptionTable[x]
return tt
DangerousVirus = Sequence('atggagagccttgttcttggtgtcaa')
print(DangerousVirus.transcription())
Hi,
I just want some clarification as to how data flows through a class. For instance, is the data in () in DangerousVirus = Sequence('atggagagccttgttcttggtgtcaa') self or seqstring?
I'm confused as to how init can have 2 variables when theres only 1 in the (). Wouldnt that mean that only self contains the sequence and seqstring is empty?
Thanks for the help! (:
self is a reference to a Sequence which is being initialized. The data string is passed as seqstring. You can see this by adding a line to print it:
print(seqstring)
The __init__ method does indeed take two arguments, but once an instance is created the self argument is "bound" to the instance (__init__ becomes a so called bound method of the instance), so you don't have to specify the instance itself anymore. If you call the unbound __init__ function from the class like this
Sequence.__init__(instance, seqstring)
you indeed have to specify the instance explicitly. The name self is just a convention, it could be anything in the definition. Take a look at the tutorial section on instance methods where this is explained.
As the other answers have said, the self arg gets passed automatically to method calls. So you must include it as the first arg in the method definition, but you must not include it in the method call.
However, there's no need to define a class for this, a simple function is sufficient. And you can use the built-in str.translate method to perform the transcription very efficiently. For large sequences, this is much faster than doing it with a Python loop as in your transcription method, since most of the work is done by compiled code, so it runs as fast as if it were written in C, not Python.
trans_table = str.maketrans('ATCG', 'UAGC')
def transcribe(seq):
seq = seq.upper()
return seq.translate(trans_table)
seq = 'atggagagccttgttcttggtgtcaa'
print(transcribe(seq))
output
UACCUCUCGGAACAAGAACCACAGUU
As mentioned in the docs, any chars that aren't in the translation table will remain unchanged in the output string. Eg,
print('abcdABCD'.translate(trans_table))
output
abcdUBGD

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