String operations not working on python strings - python

I am using xlrd to read xls cell into a string, after which none of the string functions work on that string.
attribute_name = str(worksheet.cell_value(row,col))
attribute_name.strip()
attribute_name.lower()
print len(attribute_name)
if(len(attribute_name) > 8):
print 'value' + str(ord(attribute_name[8]))
print 'attributename:'+attribute_name+':'
prints :
9
value32
attributename:TSA01_HE :
9
value32
attributename:TSA02_HE :
I am mainly interested in getting rid of the whitespace at the end of the attribute name. Am I missing anything obvious ? I have tried replace etc but as you can see, even .lower() doesnt work.
$ python --version
Python 2.7.5

strip and lower do not work in place; they return the changed value. So you should assign their result to the old variable.
attribute_name = attribute_name.strip().lower()

Methods like str.XXX always return new strings instead of edit the original string. This is because strings are immutables in python. Likewise, operators on string like += rebinds the variable to a new string as well:
In [755]: s='a'
In [756]: id(s)
Out[756]: 30887376
In [757]: s+='bc' #same as s=s+'bc'
In [758]: id(s) #identity of the variable has been changed
Out[758]: 301145192
So if you wish your operation on a string to take effect, always remember to assign the result back with =.
Other immutables like ints, floats, tuples, frozensets works the same as strs. E.g., you won't expect i=3; i.__add__(10) makes i==13.

Take care that both strip() and lower() do not modify the string you apply them on; you should therefore do attribute_name = attribute_name.strip().lower().
Example:
>>> a = ' A '
>>> a.strip().lower()
'a'
>>> a
' A '

Related

iterate through a tuple to form a string

I am trying to create a function named make_string, that uses * correctly with a parameter: strings
The function should return a string of all the values supplied joined, and separated by a space.
Outside the make_string function, I declare a variable named my_string, and assign the value returned from the make_string function.
Then I call the make_string function with the following values: "Alderaan", "Coruscant", "Dagobah", "Endor", "Hoth". Finally I print the value of my_string to the terminal...and it returns None, when it should return Alderaan Coruscant Dagobah Endor Hoth
Can anybody tell me where I am going wrong please?
def make_string(*strings):
my_string = ""
for x in strings:
my_string = x.join(strings)
return my_string
my_string = make_string()
make_string("Alderaan", "Coruscant", "Dagobah", "Endor", "Hoth")
print(my_string)
There are a few things going on in your code that are a little wonky.
You're constantly re-assigning the value of my_string every time you loop through for x in strings
There's no reason to start with a blank string here since you're already using join
Your function call isn't setting to my_string -- it isn't set to anything. What you want is like my_string = make_string("Bob", "Mary") etc.
This should do the trick:
def make_string(*strings):
return " ".join(strings)
my_string = make_string("Alderaan", "Coruscant", "Dagobah", "Endor", "Hoth")
print(my_string)
Personally, I would say you don't even need a function here, especially if you can easily set what you're using for *strings to a variable. For example:
planets = ["Alderaan", "Coruscant", "Dagobah", "Endor", "Hoth"]
print(" ".join(planets))

How to remove double quotes from list of strings?

VERSION = ["'pilot-2'", "'pilot-1'"]
VERSIONS_F = []
for item in VERSION:
temp = item.replace('"','')
VERSIONS_F.append(temp)
print (VERSIONS_F)
In the above block of code VERSIONS_F is also printing the same ["'pilot-2'", "'pilot-1'"], but I would need something like ['pilot-2', 'pilot-1']. I even tried strip('"') and am not seeing what I want.
You can do this in a couple of lines:
VERSION = ["'pilot-2'", "'pilot-1'"]
VERSIONS_F = [item [1:-1] for item in VERSION]
print(VERSIONS_F)
OUTPUT:
['pilot-2', 'pilot-1']
This way simply slices the first and last character from the string, which assumes that the "" are always at the first and last position.
Note: Grismar gives a good overview of what is happening under the hood as well
Try this:
VERSION = ["'pilot-2'", "'pilot-1'"]
VERSIONS_F = []
for item in VERSION:
temp = item.replace("'",'')
VERSIONS_F.append(temp)
print (VERSIONS_F)
it will print ['pilot-2','pilot-1']
When you print a list, Python will print the representation of the list, so the strings inside of the list are not printed like a string normally is:
>>> print('hello')
hello
Compared to:
>>> print(['hello'])
['hello']
Adding different quotes will cause Python to select the opposite quotes to represent the string:
>>> print(['\'hello\''])
["'hello'"]
>>> print(["\"hello\""])
['"hello"']
Beginning Python programmers often make the mistake of confusing what is printed on the console with an actual value. print(x) doesn't show you the actual value of x (whatever that may be), but its text string representation.
For example:
>>> x = 0xFF
>>> print(x)
255
Here, a value is assigned as its hexadecimal representation, but of course the actual value is just 255 (in decimal representation) and the decimal representation is the standard representation chosen when printing an integer value.
The 'real' value of the variable is an abstract numerical value, choices made when representing it don't affect that.
In your case, you defined the strings as having single quotes as part of the string using VERSION = ["'pilot-2'", "'pilot-1'"]. So, if you want to remove those single quotes, you could:
VERSION = ["'pilot-2'", "'pilot-1'"]
VERSIONS_F = []
for item in VERSION:
temp = item.replace("'",'')
VERSIONS_F.append(temp)
print (VERSIONS_F)
Result:
['pilot-2']
['pilot-2', 'pilot-1']
Or, more simply:
VERSIONS_F = [v.strip("'") for v in VERSION]
In response to the comment:
VERSION = ["'pilot-2'", "'pilot-1'"]
temp_list = ['pilot-1', 'test-3']
print(any(x in [v.strip("'") for v in VERSION] for x in temp_list))

Would a Python dictionary be the equivalent data structure to a Rexx compound variable?

I'm working on rewriting a lengthy Rexx script into a Python program and I am trying to figure out the best way to emulate the functionality of a Rexx compound variable. Would a dictionary be the best bet? Obviously, a dictionary will behave differently and won't be exactly the same as a compound variable.
Python dictionaries and Rexx stems are both associative arrays. They differ a bit in how they behave. Rexx's rules are very simple:
An array reference is split into the "stem" and the "tail", separated by a single dot.
The stem is a variable name, case-independently. This is the dictionary.
The tail is processed to identify an element of the array. It is split into one or more dot-separated substrings. Each substring is treated as a variable: if there is a variable with that case-independent name, its value is used instead of its name. Otherwise the name is uppercased and used. The string is put back together, dots and all. This is the key.
The array can have a default value, set by stem. = value, which applies to all unset elements.
So, the result of a an array reference stem.tailpart1.tailpart2.tailpart3 in Python is:
def evaluate_tail(tail, outer_locals):
result = []
for element in tail.split('.'):
if element in outer_locals:
result.append(str(outer_locals[element]))
else:
result.append(str(element).upper())
return '.'.join(result)
array_default_value = 4
stem = {'A.B.C': 1, 'A.9.C': 2, 'A..q': 3}
b = 9
d = 'q'
tail1 = 'a.b.c'
tail2 = 'a..b'
tail3 = 'a..d'
stem.get(evaluate_tail(tail1,locals()), array_default_value) # 'stem.a.b.c' >>> stem['A.9.C'] >>> 2
stem.get(evaluate_tail(tail2,locals()), array_default_value) # 'stem.a..b' >>> stem['A..9'] (not found) >>> (default value) >>> 4
stem.get(evaluate_tail(tail3,locals()), array_default_value) # 'stem.a..d' >>> stem['A..q'] >>> 3
Rexx-Stem variable and python-dictionaries are similar but there are differences.
Considder creating a RexxStem class based on a dictionary
Simple Stem expressions
a.b
can be translated to python as
a[b]
Compound Stem expressions
From my experience
a.b.c.d
would be translated to python as
a[b + '.' + c + '.' + d]
Try running the following rexx with your current interpretter and see what you
get:
a.2.3 = 'qwerty'
zz = 2'.'3
say a.zz
in some rexx interpreters you would get 'qwerty'. Not sure if that is all
Initializing a Stem Variables
in rexx you can initialize a stem variable lic
a. = 'abc'
Some common uses are
no = 0
yes = 1
found. = no
if ... then do
found.v = yes
end
....
if found.y = yes then do
..
end
or
counts. = 0
do while ...
if ... then do
counts.v = counts.v + 1;
end
end
Initial Value of a stem variable
Like all Rexx variables, the default/initial value of a variable so the default value of a.2.3 is A.2.3. If you are coming from another language this may seem strange but it can be quite handy in debugging - if a variable name pops up unexpectedly --> you have not initiated. It also means numeric expressions crash if you do not initialize a variable.
This not something you need to implement, just be aware of.
I am not a Python person but I know what a Dictionary is.
Depending on how complex the Rexx compound variable is, yes.
a.b
...is easily translatable to a dictionary.
a.b.c.d.e.f.g.h
...is less easily translatable to a dictionary. Perhaps a dictionary within a dictionary within a dictionary within a dictionary within a dictionary within a dictionary within a dictionary.

TypeError: 'str' object does not support item assignment (Python)

So this is what I'm trying to do:
input: ABCDEFG
Desired output:
***DEFG
A***EFG
AB***FG
ABC***G
ABCD***
and this is the code I wrote:
def loop(input):
output = input
for index in range(0, len(input)-3): #column length
output[index:index +2] = '***'
output[:index] = input[:index]
output[index+4:] = input[index+4:]
print output + '\n'
But I get the error: TypeError: 'str' object does not support item assignment
You cannot modify the contents of a string, you can only create a new string with the changes. So instead of the function above you'd want something like this
def loop(input):
for index in range(0, len(input)-3): #column length
output = input[:index] + '***' + input[index+4:]
print output
Strings are immutable. You can not change the characters in a string, but have to create a new string. If you want to use item assignment, you can transform it into a list, manipulate the list, then join it back to a string.
def loop(s):
for index in range(0, len(s) - 2):
output = list(s) # create list from string
output[index:index+3] = list('***') # replace sublist
print(''.join(output)) # join list to string and print
Or, just create a new string from slices of the old string combined with '***':
output = s[:index] + "***" + s[index+3:] # create new string directly
print(output) # print string
Also note that there seemed to be a few off-by-one errors in your code, and you should not use input as a variable name, as it shadows the builtin function of the same name.
In Python, strings are immutable - once they're created they can't be changed. That means that unlike a list you cannot assign to an index to change the string.
string = "Hello World"
string[0] # => "H" - getting is OK
string[0] = "J" # !!! ERROR !!! Can't assign to the string
In your case, I would make output a list: output = list(input) and then turn it back into a string when you're finished: return "".join(output)
In python you can't assign values to specific indexes in a string array, you instead will probably want to you concatenation. Something like:
for index in range(0, len(input)-3):
output = input[:index]
output += "***"
output += input[index+4:]
You're going to want to watch the bounds though. Right now at the end of the loop index+4 will be too large and cause an error.
strings are immutable so don't support assignment like a list, you could use str.join concatenating slices of your string together creating a new string each iteration:
def loop(inp):
return "\n".join([inp[:i]+"***"+inp[i+3:] for i in range(len(inp)-2)])
inp[:i] will get the first slice which for the first iteration will be an empty string then moving another character across your string each iteration, the inp[i+3:] will get a slice starting from the current index i plus three indexes over also moving across the string one char at a time, you then just need to concat both slices to your *** string.
In [3]: print(loop("ABCDEFG"))
***DEFG
A***EFG
AB***FG
ABC***G
ABCD***

Why am I seeing "TypeError: string indices must be integers"?

I'm playing with both learning Python and am trying to get GitHub issues into a readable form. Using the advice on How can I convert JSON to CSV?, I came up with this:
import json
import csv
f = open('issues.json')
data = json.load(f)
f.close()
f = open("issues.csv", "wb+")
csv_file = csv.writer(f)
csv_file.writerow(["gravatar_id", "position", "number", "votes", "created_at", "comments", "body", "title", "updated_at", "html_url", "user", "labels", "state"])
for item in data:
csv_file.writerow([item["gravatar_id"], item["position"], item["number"], item["votes"], item["created_at"], item["comments"], item["body"], item["title"], item["updated_at"], item["html_url"], item["user"], item["labels"], item["state"]])
Where "issues.json" is the JSON file containing my GitHub issues. When I try to run that, I get
File "foo.py", line 14, in <module>
csv_file.writerow([item["gravatar_id"], item["position"], item["number"], item["votes"], item["created_at"], item["comments"], item["body"], item["title"], item["updated_at"], item["html_url"], item["user"], item["labels"], item["state"]])
TypeError: string indices must be integers
What am I missing here? Which are the "string indices"? I'm sure that once I get this working I'll have more issues, but for now, I'd just love for this to work!
When I tweak the for statement to simply
for item in data:
print item
what I get is ... "issues" -- so I'm doing something more basic wrong. Here's a bit of my JSON content:
{"issues": [{"gravatar_id": "44230311a3dcd684b6c5f81bf2ec9f60", "position": 2.0, "number": 263, "votes": 0, "created_at": "2010/09/17 16:06:50 -0700", "comments": 11, "body": "Add missing paging (Older>>) links...
when I print data, it looks like it is getting munged really oddly:
{u'issues': [{u'body': u'Add missing paging (Older>>) lin...
The variable item is a string. An index looks like this:
>>> mystring = 'helloworld'
>>> print mystring[0]
'h'
The above example uses the 0 index of the string to refer to the first character.
Strings can't have string indices (like dictionaries can). So this won't work:
>>> mystring = 'helloworld'
>>> print mystring['stringindex']
TypeError: string indices must be integers
item is most likely a string in your code; the string indices are the ones in the square brackets, e.g., gravatar_id. So I'd first check your data variable to see what you received there; I guess that data is a list of strings (or at least a list containing at least one string) while it should be a list of dictionaries.
TypeError for Slice Notation str[a:b]
Short Answer
Use a colon : instead of a comma , in between the two indices a and b in str[a:b]:
my_string[0,5] # wrong ❌
my_string[0:5] # correct ✅
Long Answer
When working with strings and slice notation (a common sequence operation), it can happen that a TypeError is raised, pointing out that the indices must be integers, even if they obviously are.
Example
>>> my_string = "Hello, World!"
>>> my_string[0,5]
TypeError: string indices must be integers
We obviously passed two integers for the indices to the slice notation, right? So what is the problem here?
This error can be very frustrating - especially at the beginning of learning Python - because the error message is a little bit misleading.
Explanation
We implicitly passed a tuple of two integers to the slice notation when we called my_string[0,5]. 0,5 evaluates to the same tuple as (0,5) does - even without the parentheses. Why though?
A trailing comma , is actually enough for the Python interpreter to evaluate something as a tuple:
>>> my_variable = 0,
>>> type(my_variable)
<class 'tuple'>
So what we did there, this time explicitly:
>>> my_string = "Hello, World!"
>>> my_tuple = 0, 5
>>> my_string[my_tuple]
TypeError: string indices must be integers
Now, at least, the error message makes sense.
Solution
We need to replace the comma , with a colon : to separate the two integers correctly, not having them interpreted as a tuple:
>>> my_string = "Hello, World!"
>>> my_string[0:5]
'hello'
A clearer and more helpful error message could have been something like:
TypeError: string indices must be integers not tuple
^^^^^
(actual type here)
A good error message should show the user directly what they did wrong! With this kind of information it would have been much more easier to find the root cause and solve the problem - and you wouldn't have had to come here.
So next time, when you find yourself responsible for writing error description messages, remind yourself of this example and add the reason (or other useful information) to error message! Help other people (or maybe even your future self) to understand what went wrong.
Lessons learned
slice notation uses colons : to separate its indices (and step range, i.e., str[from:to:step])
tuples are defined by commas , (i.e., t = 1,)
add some information to error messages for users to understand what went wrong
data is a dict object. So, iterate over it like this:
Python 2
for key, value in data.iteritems():
print key, value
Python 3
for key, value in data.items():
print(key, value)
I had a similar issue with Pandas, you need to use the iterrows() function to iterate through a Pandas dataset Pandas documentation for iterrows
data = pd.read_csv('foo.csv')
for index,item in data.iterrows():
print('{} {}'.format(item["gravatar_id"], item["position"]))
note that you need to handle the index in the dataset that is also returned by the function.
As a rule of thumb, when I receive this error in Python I compare the function signature with the function execution.
For example:
def print_files(file_list, parent_id):
for file in file_list:
print(title: %s, id: %s' % (file['title'], file['id']
So if I'll call this function with parameters placed in the wrong order and pass the list as the 2nd argument and a string as the 1st argument:
print_files(parent_id, list_of_files) # <----- Accidentally switching arguments location
The function will try to iterate over the parent_id string instead of file_list and it will expect to see the index as an integer pointing to the specific character in string and not an index which is a string (title or id).
This will lead to the TypeError: string indices must be integers error.
Due to its dynamic nature (as opposed to languages like Java, C# or Typescript), Python will not inform you about this syntax error.
How to read the first element of this JSON?
when the file appears like this
for i in data[1]:
print("Testing"+i['LocalObservationDateTime'])
This is not working for me.
Below is the JSON file
[
{
"LocalObservationDateTime":"2022-09-15T19:05:00+02:00",
"EpochTime":1663261500,
"WeatherText":"Mostly cloudy",
"WeatherIcon":6,
"HasPrecipitation":false,
"PrecipitationType":"None",
"IsDayTime":true,
"Temperature":{
"Metric":{
"Value":11.4,
"Unit":"C",
"UnitType":17
},
"Imperial":{
"Value":52.0,
"Unit":"F",
"UnitType":18
}
},
"RealFeelTemperature":{
"Metric":{
"Value":8.4,
"Unit":"C",
"UnitType":17,
"Phrase":"Chilly"
}
}
},
{
"LocalObservationDateTime":"2022-09-16T19:05:00+02:00",
"EpochTime":1663261500,
"WeatherText":"Mostly cloudy",
"WeatherIcon":6,
"HasPrecipitation":false,
"PrecipitationType":"None",
"IsDayTime":true,
"Temperature":{
"Metric":{
"Value":11.4,
"Unit":"C",
"UnitType":17
},
"Imperial":{
"Value":52.0,
"Unit":"F",
"UnitType":18
}
},
"RealFeelTemperature":{
"Metric":{
"Value":8.4,
"Unit":"C",
"UnitType":17,
"Phrase":"Chilly"
}
}
}
]
This can happen if a comma is missing. I ran into it when I had a list of two-tuples, each of which consisted of a string in the first position, and a list in the second. I erroneously omitted the comma after the first component of a tuple in one case, and the interpreter thought I was trying to index the first component.
Converting the lower case letters to upper:
str1 = "Hello How are U"
new_str = " "
for i in str1:
if str1[i].islower():
new_str = new_str + str1[i].upper()
print(new_str)
Error :
TypeError: string indices must be integers
Solution :
for i in range(0, len(str1))
// Use range while iterating the string.

Categories