Python method positional args troubleshooting - python

So I am trying to make a script that will traverse a string and replace certain characters. The idea is fairly simple and sudo code looks a little like this.
Input1 = ''
Input2 = ''
Input3 = ''
rawPw = Input1 + Input2 + Input 3
Remove spaces if any exist
Creates a new empty str called finalPw
Scan the rawPw string one character at a time. Each character goes to a Random bool and if True it goes to get converted. If false it appends finalPw
In it goes to conversion it checks against a list of specified characters and if it matches it goes to a specific converter method. Otherwise it will just swap upper/lower case and append finalPw
The specific converter method will use a predefined list of characters that it can be replaced by, and will use random.choice() to pick from that list to replace the character and append finalPw.
This is the code I have so far, note the upper/lower case swapping is not part of it yet, I am building and testing the code piecemeal because my last prototype was 350 lines long and a complete failure. So going from scratch here.
import random
print("Enter 3 words or series of numbers or both, each entry must be at least 5 characters in length")
def main():
input1 = 'Jim'
input2 = 'Samantha'
input3 = 'Ethan'
rawPw = (input1 + input2 + input3)
refinedPw = rawPw.replace(' ', '')
print(refinedPw)
finalPw = ''
convertTrain(refinedPw)
def switch():
switchVal = random.choice(True, False)
return switchVal
def convertTrain():
temp = main.refinedPw
onOff = False
for i in temp:
switch(i)
if i == True:
if i == 'i':
the_iExc(i)
else:
main.finalPw.append(i)
def the_iExc():
rep_iExc = ['i', '!']
repVal = random.choice(rep_iExc)
for i in len(main.refinedwPw):
slice(i)
if i == 'i':
i.replace(repVal)
return i
main()
The error I am receiving is :
line 15, in main
convertTrain(refinedPw)
TypeError: convertTrain() takes 0 positional arguments but 1 was given
I have tried changing things around a bit to see if I can't fix the positional argument, so much so that I have stripped it of all classes and am just going classless until I get it to work. For the life of me I can't seem to get it to use the appropriate number of args.

This line defines convertTrain as a function that takes no arguments:
def convertTrain():
But then inside main() you call it with an argument:
convertTrain(refinedPw)
Either change the function definition to accept an argument, or change the call to not pass an argument.

You're trying to invoke function with arguments here:
convertTrain(refinedPw)
...but there are no arguments in the function's definition
def convertTrain()
To fix this, add a new argument for the convertTrain function, like this:
def convertTrain(train) # Name of argument can be changed if needed
Read more about function declaration here: click this

Related

How to test a Function that takes no parameters

I am new here and new to programming (I have only been programming for 2 weeks). Does anyone have any suggestions on how to test a function that takes no parameters. I have tested functions that takes parameters but not one that takes no parameters.
On the test function I try passing an arguments expected as the letter 'a' in the valid_letter() function. But it gives the error that 'a' is not defined.
def valid_letter():
'''Function valid_letter
Parameters None
continuously asks for a valid letter
if invalid data is provided
'''
while True:
column = input("What column do you wish to select from a to g? ")
if column != "a" and column != "b" and\
column != "c" and column != "d" and\
column != "e" and column != "f" and\
column != "g" and column != "h":
print("Your input is invalid")
continue
else:
return column
break
def check_valid_column(expect):
answer = valid_letter()
print("Input: {}".format(answer))
print("Expected: {}, Actual {}".format(expect, answer))
def main():
check_valid_column(a)
main()
(Note: the original function was broken due to indentation so while I was fixing it I took the liberty of rewriting it to be simpler. It should still behave exactly the same as your intended original implementation and the testing strategy, which is the real focus of the question, is exactly the same regardless of implementation details.)
One way to do this is with patch:
def valid_letter() -> str:
'''
Prompts the user for a column between 'a' and 'g'.
Continuously asks for a valid letter if invalid data is provided.
'''
while True:
column = input("What column do you wish to select from a to g? ")
if ord(column) in range(ord('a'), ord('g') + 1):
return column
print("Your input is invalid")
from unittest.mock import Mock, patch
def test_valid_letter() -> None:
with patch('builtins.input', new=Mock(return_value='a')):
assert valid_letter() == 'a'
with patch('builtins.input', new=Mock(side_effect=['z', 'q', 'g', 'c'])):
assert valid_letter() == 'g'
test_valid_letter()
The patch statements in the test replace the builtin input function with a Mock object that returns a particular argument. In the first test it simply returns 'a', and so we assert that valid_letter() will return that same value. In the second test it returns successive values from the list each time it's called; we assert that valid_letter() will continue calling it in a loop until it reaches 'g'.
Another method would be via dependency injection:
from typing import Callable
from unittest.mock import Mock
def valid_letter(input_func: Callable[[str], str]) -> str:
'''
Prompts the user for a column between 'a' and 'g', using input_func.
Continuously asks for a valid letter if invalid data is provided.
'''
while True:
column = input_func("What column do you wish to select from a to g? ")
if ord(column) in range(ord('a'), ord('g') + 1):
return column
print("Your input is invalid")
def test_valid_letter() -> None:
assert valid_letter(Mock(return_value='a')) == 'a'
assert valid_letter(Mock(side_effect=['z', 'q', 'g', 'c'])) == 'g'
test_valid_letter()
In this example, rather than having valid_letter call the builtin input function, it accepts an arbitrary input function that the caller supplies. If you call it like:
valid_letter(input)
then it behaves exactly like the original, but the caller can also pass in arbitrary replacements without having to use patch. That makes testing a bit easier, and it also allows for the possibility of a caller wrapping or replacing input to allow for a different UI style -- for example, if this function were being used in a GUI app the caller could pass in an input_func that prompts the user via a dialog box instead of the terminal.
The same testing/injection logic applies to the print function -- you might find it useful to have your test validate that print is called each time an invalid value is entered, and another caller might find it useful to use an alternative output function.
The function will work with no parameters, and will still as for user input since you have input() in your called function.
The way you call valid_letter() is fine. That is not the issue. But you intended to verify that the input was "a" (which apparently represents the correct answer).
So then you should not do check_valid_column(a) as a is not a defined variable, but check_valid_column("a"), so with the character "a".

Passing an optional function (and optional parameters) to another function in Python?

I'm new to learning Python and have enough under my belt to start attempting a beginner's Tic-Tac-Toe program.
My issue is thus: I want to have a generic input function called getInput() which will get input from the user, strip trailing white space from that input, and THEN, if a function was passed to it via the optional parameter "specialTest", getInput() will run the input through this provided function and return the output which the specialTest function spat out.
Sometimes this specialTest function will need additional arguments besides the user input. Assume for my purposes that the user input will always be the first argument and is required, and that any additional args will come afterwards.
I tried to implement this situation via *args, and I got it working if the specialTest function had no additional arguments. But the first time I try to feed it additional arguments, it fails.
So for example, getInput("Age?", specialTest=int) works. It prompts for user input and feeds it through the int() function, finally returning the output as an integer. But when I try to pass getInput() a function which has an additional argument - an ordered dictionary which contains strings as keys and dictionaries as values - the program fails with TypeTypeError: getInput() got multiple values for argument 'specialTest'. What needs to be adjusted to get this working as intended?
Code:
import collections
def getInput(msg, specialTest=None, *TestArgs):
"""Get user input and export to the desired format."""
while True:
string = input(msg + ' ').strip()
# If the user passed a function to the SpecialTest parameter,
# pass the user input through that function and return its value.
# If the SpecialTest function returns False or we hit an error,
# that means the input was invalid and we need to keep looping
# until we get valid input.
if specialTest:
try:
string = specialTest(string, *TestArgs)
if string is False: continue
except:
continue
return string
def nametoMove(name, board):
"""Convert player's move to an equivalent board location."""
location = {name: theBoard.get(name)}
# return false if the location name isn't present on the board
if location[name] is None:
return False
return location
# ---Tic-Tac-Toe routine---
# fill the board
row_name = ('top', 'mid', 'lower')
col_name = ('left', 'center', 'right')
theBoard = collections.OrderedDict()
size = 3 # 3x3 board
for x in range(size):
for y in range(size):
key = row_name[x] + ' ' + col_name[y]
value = {'row': x, 'col': y}
theBoard.update({key: value})
# get player's desired board symbol
playerSymbol = getInput("X's or O's?")
# get player's age
playerAge = getInput("Age?", specialTest=int)
# get player's move and convert to same format as theBoard object
# e.g., "top left" --> {'top left': {'row': 0, 'col': 0}}
playerMove = getInput("Move?", specialTest=nametoMove, *theBoard)
In order to support supplying the same parameter via a positional or keyword argument, Python converts any keyword arguments that can be into positional arguments. That creates the conflict in your example. Syntactically, what you want can be achieved by simply omitting the argument:
playerMove = getInput("Move?", nametoMove, *theBoard)
Or you can resolve the ambiguity with a “keyword-only” argument:
def getInput(msg, *TestArgs , specialTest=None):
Then the keyword argument cannot be converted, so there is no collision. (This can be emulated in Python 2 by using **kw to accept arbitrary keyword arguments and then checking that only the expected one is actually provided.)
But the question you should be asking is “How can I preset some arguments to a function used as a callback?”, to which the answer is either a lambda:
playerMove = getInput("Move?", specialTest=lambda s: nametoMove(s, *theBoard))
or functools.partial:
playerMove = getInput("Move?", specialTest=functools.partial(nametoMove, board=theBoard))
With either of these, you don’t need TestArgs at all. The partial approach doesn’t support supplying trailing positional arguments (like varargs), but your nametoMove doesn’t actually want those anyway (as established in the comments). So in all the approaches above you omit the *.

How to complete this function then print it out, using Python?

I'm having a hard time to understand how to work with functions - I can make then but after that I don't know how to use them. My question is how can I print this code with a function?
string = "Hello"
reverse = string[::-1]
print(reverse)
I tried putting it in a function but I cannot make it print Hello.
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
also tried this
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
Nothing seems to work. I'm having same problem with this as well.
total = 0
def length(words):
for i in words:
total += 1
return total
Functions without a return value
Functions that just take action or do something without returning a value (for example, print).
Functions that don't return a value can be defined like that:
def sayHello():
print "Hello!"
And can be used (called) like that:
sayHello()
And the output will be:
Hello!
Function parameters
A function can also receive parameters (type of variables) from the caller. It's better to demonstrate it with an example.
A function that receives a name and greets this name:
def sayHelloTo(name):
print "Hello", name
It can be called like that:
sayHelloTo("Yotam")
And the output will be:
Hello Yotam
The parameters are the function's input.
Functions with a return value
Other functions, unlike sayHello() or sayHelloTo(name) (that just do something) can return a value. For example, let's make a function that rolls a dice (returns a random number between 1 and 6).
from random import randint
def rollDice():
result = randint(1, 6)
return result
The return keyword just sets the output value of the function and exits the function. An example use of the rollDice function will be:
dice = rollDice()
print "The dice says", dice
When the function hits a return keyword, it finishes and the return value (in our case, the variable result) will be placed instead of the function call. Let's assume randint(1, 6) has produced the number 3.
Result becomes 3.
Result is returned.
Now, instead of the line:
dice = rollDice()
We can treat the line as:
dice = 3
(rollDice() was replaced with 3)
Functions with parameters and a return value
Some functions (for example, math functions) can take inputs AND produce outputs. For example, let's make a function that receives 2 numbers and outputs the greater one.
def max(a,b):
if a > b:
return a
else:
return b
What it does is pretty clear, isn't it? If a is greater, it returns the value of it. Otherwise, returns the value of b.
It can be used like that:
print max(4, 6)
And the output will be:
6
Now, your case
What you want to do is a function that reverses a string. It should take 1 parameter (input) - the string you want to reverse, and output 1 value - the reversed string. This can be accomplished like that:
def reverse_a_string(my_text):
return my_text[::-1]
now you can do something like that:
s = raw_input("Please enter a string to be reversed\n") #input in Python3
r = reverse_a_string(s)
print r
r will contain the reversed value of s, and will be printed.
About your second function - well, I assume that based on this answer you can make it yourself, but comment me if you need assistance with the second one.
Local variables
About your 3rd example:
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
This is something that is really worth delaying and understanding.
the variable reverse is first used inside the function. This makes it a local variable.
This means that the variable is stored in the memory when the function is called, and when it finishes, it is removed. You can say it's lifetime is from when the function is called to when the function is done.
This means that even if you called reverse_a_string(string), you wouln't be able to use the reverse variable outside of the function, because it would be local.
If you do want to pass a value like that, you have to "declare" your variable outside of the function and to use the global keyword, like that:
reverse = "" #This makes reverse a global variable
def reverse_a_string(string):
global reverse #Stating that we are going to use the global variable reverse
reverse = string[::-1]
# Then you can call it like that:
reverse_a_string("Hello")
print reverse
The output will be
olleH
Although it's strongly not recommended to do it in Python, or in any other language.
Once you create a function you must call it. You have created the function reverse_a_string but then you never actually call it. Think about a function as a button that does something everytime it is pushed (or in our case called). If you never push the button then although it has the potential to do something, it never will. In order for the set of instructions to happen we need to push the button (or in our case call the function). So in order for your code to work you first need to define the function then actually call it:
def reverse_a_string():
string="Hello"
reverse = string[::-1]
print reverse
reverse_a_string()
Result: 'olleH'
If you want to pass your own string in to the function so it doesn't just return 'olleH' all the time your code needs to look like such:
def reverse_a_string(stringThatWillBeReversed):
reverse = stringThatWillBeReversed[::-1]
print reverse
reverse_a_string('whateverStringYouWant')
Result: The reverse of the string you entered.
Hope that helps!
I don't know whether you are asking how to define functions in python or something else
If you want to learn python functions, go to http://www.tutorialspoint.com/python/python_functions.htm or just write python tutorial in google, you will get billions of good sites
def reverse_a_string(string):
#function definition
reverse = string[::-1]
print(reverse)
#function call
reverse_a_string("your string")
But you to define function for this, you could simply do
print( string[::-1] )
# defines the 'Reverse a String' function and its arguments
def reverse_a_string():
print(string)
reverse = string[::-1]
print(reverse)
print("Type a string") # asks the user for a string input
string = input() # assigns whatever the user input to the string variable
reverse_a_string() # simply calls the function
for functions, you have to define the function, then simply call it with the function name i.e. funtion()
In my example, I ask for a string, assign that to the variable, and use it within the function. If you just want to print hello (I'm a little unclear from your question) then simply including the print("hello") or w/ variable print(string) will work inside the function as well.

Understanding a Python function

I need some help understanding a function that i want to use but I'm not entirely sure what some parts of it do. I understand that the function is creating dictionaries from reads out of a Fasta-file. From what I understand this is supposed to generate pre- and suffix dictionaries for ultimately extending contigs (overlapping dna-sequences).
The code:
def makeSuffixDict(reads, lenSuffix = 20, verbose = True):
lenKeys = len(reads[0]) - lenSuffix
dict = {}
multipleKeys = []
i = 1
for read in reads:
if read[0:lenKeys] in dict:
multipleKeys.append(read[0:lenKeys])
else:
dict[read[0:lenKeys]] = read[lenKeys:]
if verbose:
print("\rChecking suffix", i, "of", len(reads), end = "", flush = True)
i += 1
for key in set(multipleKeys):
del(dict[key])
if verbose:
print("\nCreated", len(dict), "suffixes with length", lenSuffix, \
"from", len(reads), "Reads. (", len(reads) - len(dict), \
"unambigous)")
return(dict)
Additional Information: reads = readFasta("smallReads.fna", verbose = True)
This is how the function is called:
if __name__ == "__main__":
reads = readFasta("smallReads.fna", verbose = True)
suffixDicts = makeSuffixDicts(reads, 10)
The smallReads.fna file contains strings of bases (Dna):
"> read 1
TTATGAATATTACGCAATGGACGTCCAAGGTACAGCGTATTTGTACGCTA
"> read 2
AACTGCTATCTTTCTTGTCCACTCGAAAATCCATAACGTAGCCCATAACG
"> read 3
TCAGTTATCCTATATACTGGATCCCGACTTTAATCGGCGTCGGAATTACT
Here are the parts I don't understand:
lenKeys = len(reads[0]) - lenSuffix
What does the value [0] mean? From what I understand "len" returns the number of elements in a list.
Why is "reads" automatically a list? edit: It seems a Fasta-file can be declared as a List. Can anybody confirm that?
if read[0:lenKeys] in dict:
Does this mean "from 0 to 'lenKeys'"? Still confused about the value.
In another function there is a similar line: if read[-lenKeys:] in dict:
What does the "-" do?
def makeSuffixDict(reads, lenSuffix = 20, verbose = True):
Here I don't understand the parameters: How can reads be a parameter? What is lenSuffix = 20 in the context of this function other than a value subtracted from len(reads[0])?
What is verbose? I have read about a "verbose-mode" ignoring whitespaces but i have never seen it used as a parameter and later as a variable.
The tone of your question makes me feel like you're confusing things like program features (len, functions, etc) with things that were defined by the original programmer (the type of reads, verbose, etc).
def some_function(these, are, arbitrary, parameters):
pass
This function defines a bunch of parameters. They don't mean anything at all, other than the value I give to them implicitly. For example if I do:
def reverse_string(s):
pass
s is probably a string, right? In your example we have:
def makeSuffixDict(reads, lenSuffix = 20, verbose = True):
lenKeys = len(reads[0]) - lenSuffix
...
From these two lines we can infer a few things:
the function will probably return a dictionary (from its name)
lenSuffix is an int, and verbose is a bool (from their default parameters)
reads can be indexed (string? list? tuple?)
the items inside reads have length (string? list? tuple?)
Since Python is dynamically typed, this is ALL WE CAN KNOW about the function so far. The rest would be explained by its documentation or the way it's called.
That said: let me cover all your questions in order:
What does the value [0] mean?
some_object[0] is grabbing the first item in a container. [1,2,3][0] == 1, "Hello, World!"[0] == "H". This is called indexing, and is governed by the __getitem__ magic method
From what I understand "len" returns the number of elements in a list.
len is a built-in function that returns the length of an object. It is governed by the __len__ magic method. len('abc') == 3, also len([1, 2, 3]) == 3. Note that len(['abc']) == 1, since it is measuring the length of the list, not the string inside it.
Why is "reads" automatically a list?
reads is a parameter. It is whatever the calling scope passes to it. It does appear that it expects a list, but that's not a hard and fast rule!
(various questions about slicing)
Slicing is doing some_container[start_idx : end_idx [ : step_size]]. It does pretty much what you'd expect: "0123456"[0:3] == "012". Slice indexes are considered to be zero-indexed and lay between the elements, so [0:1] is identical to [0], except that slices return lists, not individual objects (so 'abc'[0] == 'a' but 'abc'[0:1] == ['a']). If you omit either start or end index, it is treated as the beginning or end of the string respectively. I won't go into step size here.
Negative indexes count from the back, so '0123456'[-3:] == '456'. Note that [-0]is not the last value,[-1]is. This is contrasted with[0]` being the first value.
How can reads be a parameter?
Because the function is defined as makeSuffixDict(reads, ...). That's what a parameter is.
What is lenSuffix = 20 in the context of this function
Looks like it's the length of the expected suffix!
What is verbose?
verbose has no meaning on its own. It's just another parameter. Looks like the author included the verbose flag so you could get output while the function ran. Notice all the if verbose blocks seem to do nothing, just provide feedback to the user.

"Function object is unsubscriptable" in basic integer to string mapping function

I'm trying to write a function to return the word string of any number less than 1000.
Everytime I run my code at the interactive prompt it appears to work without issue but when I try to import wordify and run it with a test number higher than 20 it fails as "TypeError: 'function' object is unsubscriptable".
Based on the error message, it seems the issue is when it tries to index numString (for example trying to extract the number 4 out of the test case of n = 24) and the compiler thinks numString is a function instead of a string. since the first line of the function is me defining numString as a string of the variable n, I'm not really sure why that is.
Any help in getting around this error, or even just help in explaining why I'm seeing it, would be awesome.
def wordify(n):
# Convert n to a string to parse out ones, tens and hundreds later.
numString = str(n)
# N less than 20 is hard-coded.
if n < 21:
return numToWordMap(n)
# N between 21 and 99 parses ones and tens then concatenates.
elif n < 100:
onesNum = numString[-1]
ones = numToWordMap(int(onesNum))
tensNum = numString[-2]
tens = numToWordMap(int(tensNum)*10)
return tens+ones
else:
# TODO
pass
def numToWordMap(num):
mapping = {
0:"",
1:"one",
2:"two",
3:"three",
4:"four",
5:"five",
6:"six",
7:"seven",
8:"eight",
9:"nine",
10:"ten",
11:"eleven",
12:"twelve",
13:"thirteen",
14:"fourteen",
15:"fifteen",
16:"sixteen",
17:"seventeen",
18:"eighteen",
19:"nineteen",
20:"twenty",
30:"thirty",
40:"fourty",
50:"fifty",
60:"sixty",
70:"seventy",
80:"eighty",
90:"ninety",
100:"onehundred",
200:"twohundred",
300:"threehundred",
400:"fourhundred",
500:"fivehundred",
600:"sixhundred",
700:"sevenhundred",
800:"eighthundred",
900:"ninehundred",
}
return mapping[num]
if __name__ == '__main__':
pass
The error means that a function was used where there should have been a list, like this:
def foo(): pass
foo[3]
You must have changed some code.
By the way, wordify(40) returned "fourty". I spell it "forty"
And you have no entry for zero
In case someone looks here and has the same problem I had, you can also get a pointer to a function object if the wrong variable name is returned. For example, if you have function like this:
def foo():
my_return_val = 0
return return_val
my_val = foo()
then my_val will be a pointer to a function object which is another cause to "TypeError: 'function' object is unsubscriptable" if my_val is treated like a list or array when it really is a function object.
The solution? Simple! Fix the variable name in foo that is returned to my_return_val.

Categories