String manipulation using list comprehension - python

I am trying below code and expecting output as,
matching string where every even letter is uppercase, and every odd letter is lowercase, however my output is list of all uppercase characters.
def myfunc(*args):
return ''.join([args[i].upper() if i%2==0 else args[i].lower() for i in range(len(args))])
How can I get expected output ? I tried same list comprehension syntax to test and it works fine. What's wrong with this specific code ?

By writing *args in your function declaration, it means that you're iterating over a number of strings and not just one string. For example:
myfunc('hello', 'goodbye')
Your function will iterate over a hello and goodbye, with hello having an index of 0 which is even number and thus converting its characters to uppercase, whereas goodbye has an index of 1 which is odd and thus covnerting its characters to lowercase:
HELLOgoodbye
If you wish to call your function for only one string, you have to remove the * from *args or inserting the string's characters one by one:
myfunc('h','e','l','l','o')
So, the declaration and implementation of your function should look like this:
def myfunc(args):
return ''.join([args[i].upper() if i%2==0 else args[i].lower() for i in range(len(args))])
Calling myfunc('hello') will return the correct result.

The problem is, you're using var-args. That's wrapping the string passed with a list, then you're iterating over that list (which only contains one string). This means your code does work to some extent; its just alternating the case of each whole word instead of each character.
Just get rid of the var-args:
def myfunc(word):
return ''.join([word[i].upper() if i%2==0 else word[i].lower() for i in range(len(word))])
print(myfunc("hello world"))
# HeLlo WoRlD
I'll just note, there's a few ways this could have been debugged. If you had checked the contents of args, you would have seen that it only contained a single element when one argument was passed, and two when two arguments were passed. If you had passed two arguments in, you would have also noticed that it alternated the case of each word as a whole. That would have likely given you enough hints to figure it out.

The above answers are correct but they ask you to modify the current syntax. In general you should try to understand how *args works.
In python, *args in a function definition is used to receive variable number of arguments. Such cases arise when we don't know in advance how many arguments will be passed.
For example :
def myFun(*argv):
for arg in argv:
print (arg)
myFun('Hello', 'Welcome', 'to', 'GeeksforGeeks')
Now coming back to your code, you can make it run by selecting the first argument from the args list. See below :
def myfunc(*args):
return ''.join([args[0][i].upper() if i%2==0 else args[0][i].lower() for i in range(len(args[0]))])
print(myfunc("input"))
Help the community by selecting the best answer for this question.

Related

Why do some methods of built-in types operate in-place and some don't?

dog = 'penny'
print(dog.title())
dog_names = ['pete', 'luke', 'shane']
print(dog_names.remove('shane'))
Why does Python return an output of Penny for dog.title() but None for
dog_names.remove('shane')? Why can I not print the list dog_name with the method remove while I can use the method title on dog?
I understand that I get None because dog_name.remove has no return, but how does dog.title have a return?
The title() function is a pre-defined function in Python which is used to covert the first character of the string into uppercase and the remaining characters into lowercase and return a new string.
in your example if you run print(dog) you can see that penny is all lowercase, but if you run print(dog.title()) you can see that the first letter in Penny which is P is uppercase and the remaining is lowercase
In order to answer your question, first, you need to understand what's being returned.
When calling print on a function or method, it will display the returned value.
With that being said, you can check the return value of both functions from the documentation
https://docs.python.org/2/tutorial/datastructures.html#more-on-lists
list.remove(x) Remove the first item from the list whose value is x.
It is an error if there is no such item.
https://docs.python.org/3.7/library/stdtypes.html#str.title
str.title() Return a titlecased version of the string where words
start with an uppercase character and the remaining characters are
lowercase.
Notice how title() returns the titled case string, that's why it's printed.
On the other hand remove() doesn't return anything, in this case, python has a default return value of None (Source) that's why it's printed when calling remove()
A function/method in any programming language performs a specific task. A task could be performed on the inputs passed to the function. After performing the task, the function may want to give the result back to the caller of the function. It may do that by:
By modifying the parameters passed to it or By altering the object on which method was called. (For example, remove() method of list data type)
By returning the result to the caller. (title() method)
A combination of (1) and (2)
Your remove() method doesn't return anything back to the caller. Instead it just deletes an element from the list. To print the list after removing an element:
dog_names.remove('shane')
print(dog_names)

Trouble with Palindrome function in python

I'm having trouble in an online course for python, specifically a palindrome problem These are the instructions, but the function must be case-insensitive and not see spaces. I think the issue is in my return blocks or my flow. I think I need to use the lower function, but I'm honestly not sure.
def student_func(x):
for string in x:
x.lower()
y = x.replace(" ", "")
if y[::-1]==y:
return True
else:
return False
You actually have two separate problems in your code—and you're right that one of them is with lower and the other is with the return flow.
First, x.lower() doesn't modify x in-place. In fact, strings are immutable; nothing modifies them in-place. If you look up the interactive help or the online docs, it says:
Return a copy of the string with all the cased characters [4] converted to lowercase.
So, you need to do the same thing with lower that you do with replace: assign the result to a variable, and use that:
y = x.lower()
z = y.replace(" ", "")
Or you can reuse the same variable:
x = x.lower()
… or chain the two calls together:
y = x.lower().replace(" ", "")
As a side note, unless you're using Python 2, you should consider whether you want casefold instead of lower. For English it makes no difference, but for other languages it can.
Meanwhile, you're doing for string in x:, but then ignoring string.
If x is just a single word, you don't want to loop over it at all.
If x is a list of words, then the for string in x: is correct, but then you have to use string inside the loop, not x. Plus, you can't just return True or return False—that will exit the function as soon as you test the first word, meaning the rest of them never get tested. I'm not sure whether you want to return True if there are any pallidromes, or if they're all palindromes, or if you want to return a list of booleans instead of a single one, or what, but you can't just return the first one.
It would probably be a lot clearer if you used better names, like words instead of x and word instead of string.
Anyway, I can't tell you the right way to fix this since I don't know what you're trying to do, but hopefully this explains enough that you can fix it yourself.
Giving away the solution defeats the purpose of the exercise
your approach is more or less correct.
convert string to a standard case
remove whitespace
check if reverse of the string is equal to the original string
The error lies in how you are using the python API.
check what each of the functions do, and what they return.
a good idea is to run help(function) to see what the function's documentation has to say about it.
try help(x.lower) (note: not help(x.lower())) and see what the return value is.

Assigning variables confusion in Python 3

I thought I understood how assignment works, but after running these two pieces of code I realized I am pretty confused now.
This is in Python 3.3:
numbers=[1,4,3]
hello=numbers.reverse()
print(hello)
None
When I print(numbers) instead, I get [3,4,1] which is what I was expecting when printing hello.
On another example:
numbers='yeah'
hello=numbers.capitalize()
print(hello)
Yeah
How come when assigning a list to second variable, like the first example shows, I get None when printing that second variable, but when assigning a string this does not happen? I ran it in the Python visualizer, but this still does not answer my question as to how/why this is.
That's because numbers.reverse() reverses the list in place.
Your code shoud be:
numbers=[1,4,3]
numbers.reverse()
print(numbers)
or if you don't want to modify original list numbers, copy numbers to hello:
from copy import copy
numbers=[1,4,3]
hello=copy(numbers)
hello.reverse()
print(hello)
The documentation of the methods will always tell you if the method works in place (i.e. it change the object you are calling the method on to), or if it returns the result
As in document specified, list.reverse() "reverse the elements of the list in place" while str.capitalize() "return a copy of word with only its first character capitalized."
One works in-place while the other returns the result.

Python: Why Does str.split() Return a list While str.partition() Returns a tuple?

Comparing Python's str.split() with str.partition(), I see that they not only have different functions (split() tokenizes the whole string at each occurrence of the delimiter, while partition() just returns everything before and everything after the first delimiter occurrence), but that they also have different return types. That is, str.split() returns a list while str.partition() returns a tuple. This is significant since a list is mutable while a tuple is not. Is there any deliberate reason behind this choice in the API design, or is it "just the way things are." I am curious.
The key difference between those methods is that split() returns a variable number of results, and partition() returns a fixed number. Tuples are usually not used for APIs which return a variable number of items.
#yole answer summarise the reasoning why partition() returns tuple. But there is a nice way to "exploit" that fact. I found below example in "Automate the boring stuff with Python".
before, sep, after = 'Hello, world!'.partition(' ')
print(before)

Formatting the output of a key from a dictionary

I have a dictionary which store a string as the key, and an integer as the value. In my output I would like to have the key displayed as a string without parenthesis or commas. How would I do this?
for f_name,f_loc in dict_func.items():
print ('Function names:\n\n\t{0} -- {1} lines of code\n'.format(f_name, f_loc))
output:
Enter the file name: test.txt
line = 'def count_loc(infile):'
There were 19 lines of code in "test.txt"
Function names:
('count_loc(infile)',) -- 15 lines of code
Just incase it wasn't clear, I would like the last line of the output to be displayed as:
count_loc(infile) -- 15 lines of code
EDIT
name = re.search(func_pattern, line).groups()
name = str(name)
Using type() before my output, I verified it remains a string, but the output is as it was when name was a tuple
I don't have Python 3 so I can't test this, but the output of f_name makes it look like it is a tuple with one element in it. So you would change .format(f_name, f_loc) to .format(f_name[0], f_loc)
EDIT:
In response to your edit, try using .group() instead of .groups()
To elaborate on Peter's answer, It looks to me like you're assigning a one-item tuple as the key of your dictionary. If you're evaluating an expression in parentheses somewhere and using that as the key, be sure you don't have a stray comma in there.
Looking at your further edited answer, it's indeed because you're using the groups() method of your regex match. That returns a tuple of (the entire matched section + all the matched groups), and since you have no groups, you want the entire thing. group() with no parameters will give you that.
I expect you have a problem with your parsing code. The lines as written should work as expected.
Since the key is some type of tuple, you may want to join the different elements before printing. We can't really tell what the significance of the key is from the snippet shown.
So you could do something like such:
.format(", ".join(f_name), f_loc)

Categories

Resources