Passed argument memory context - python

I came across this while coding:
def interpret(command):
# comment1: command.replace("()","o").replace("(al)","al")
# comment2: print(command)
res = command.replace("()","o").replace("(al)","al")
print(res)
interpret("G()(al)")
In the above code, I was expecting the string to be replaced at 'comment1' but, I got the same value passed as an argument i.e. "G()(al)" but on storing it in a different location (here, 'res') I was able to get the expected result.
Could you please point out what made Python remember the 'command' original value or is there something like JavaScript's closure or I am unable to see the simple point here?

According to the official documentation:
str.replace(old, new[, count])
Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.
Meaning that a new string is created for the data to be stored in. And since you did not store the result of the replacement operations back into the command parameter, the result is never used. Storing the data in another variable res also works and might provide more bug-resistance if you want to perform multiple operations on command that you might re-arrange later on.

Related

What does the f'+{value}' do? I was solving Roman to integer problem and I came across it

This is the code.
The second line doesn't make much sense to me. Can anyone please help?
for key, value in roman_map.items():
s = s.replace(key, f'+{value}')
return eval(s)
It's just for formatting the string, for example if the variable value is 3, then f'+{value}' would result as a formatted string '+3'. If this doesn't satisfy you, then I think I know what's confusing you, the line s = s.replace(key, f'+{value}') is a simple line which is for replacing a part of a string. As I see it, s is a pre defined variable with a string(it's written s = s.replace in the line, the replace method belongs to a string so most likely s is a string variable) so what this line does is, in the for loop, you see the key variable, now the replace method takes two parameters, the first one asks the user which part of the string to replace and the second specifies what to replace it with, henceforth I can say this much that this line replaces the part of the string which is same as whatever value the variable key holds during the current iteration(in simple english, the current loop number) with f'+{value}'.(Read my answer from the starting in case you forgot what that line means or if your confused, if this still doesen't satisfy you, try googling the string replace method and f strings in python)

Replace Strings in Python 3

I'm trying to replace a string in python like this:
private_ips.replace("{",'')
The error I get back is this:
Traceback (most recent call last):
File ".\aws_ec2_list_instances.py", line 39, in <module>
private_ips.replace("{",'')
AttributeError: 'set' object has no attribute 'replace'
What am I doing wrong?
private_ips is set object. You can use replace only on strings.
To represent set as string take this code snippet:
private_ips_as_string = '{' + ', '.join(str(elem) for elem in private_ips) + '}'
Let's back up a little ...
tree = objectpath.Tree(instance)
private_ips = set(tree.execute('$..PrivateIpAddress'))
Your initial problem is that you specifically converted the return value into a set. If you don't want a set, then don't convert it to one, or convert it back to something more useful to you. Since you've failed to provide a Minimal, complete, verifiable example, we can't fix everything, but I'll use an intuitive leap here ...
tree.execute returns a list of IP addresses.
You're using set to remove duplicate addresses in a list.
If so, you're fine up to this point. To get the address as a string, I think you want to iterate through the items in the set:
for ip_addr in private_ips:
# Handle ip_addr, a single IP address seen as a str.
If you need the addresses lined up, you can always convert back to a list with
private_ips = list(private_ips)
... and if you know there is exactly one addr that you want as a string, you can grab it in one step with
single_ip = list(private_ips)[0]
... or just grab it directly from your function's return value:
single_ip = tree.execute('$..PrivateIpAddress')[0]
To explain what did happen to you:
You called a function that return a sequence of some sort.
You converted that sequence to a set, a common technique for removing duplicates.
You tried to remove braces from the set, as if it were a string.
The problem is that a set does not have braces. Those braces are a notational convenience; they exist only in the __repr__ (output string representation) of the data type, not in the set itself. You cannot manipulate that representation. This would be something like trying to remove the up-vote and down-vote arrows from this question by editing the question text: you can't do it, because those are part of the delivery framework.
Similarly, you cannot remove the quotation marks from the ends of a string, because they're not part of the string.
To get rid of the braces, you quit using a set: reach inside and pull out the contents as an individual element.

How to convert a MS Word paragraph object (from VBA) into python string

So what I'm trying to do is to access the Microsoft Word API (which is written in VBA) from python with "pywin32" module. Specifically I need to iterate through the whole .docx file and find the location where a certain string shows up and add some text after it. I successfully fetched some paragraphs from the file with Document.Paragraphs.Items(index) and print them out, but when I try to compare it with my hard-coded string to see whether they matches or not, it always false, I did some type check to the paragraph I got from the .docx file then realized it is not a python string, that should be why it never matches with my string. Below is some code I wrote to show what is happening:
word = win32.gencache.EnsureDispatch('Word.Application')
word.Documents.Open('xxxxxxxxx.docx')
string = word.Documents(1).Paragraphs.Item(3)
print string
if string == "My Hard Coded String":
print "True"
else:
print "False"
So the above code snippet always gives me False even if the string that gets printed out at line 4 is exactly "My Hard Coded String", I'm reading the VBA documentation but there seems no any object or methods which has anything to do with converting the paragraph instance into python string (this might be a strange statement since VBA has nothing to do with python but...trying to summarize my question more clearly), any idea about how should I achieve this? Thanks in advance!
More Edit:
Somebody has answered my question but I do not know where can I find all the objects/properties that Paragraph.Range has. I have been looking at MSDN and I don't think they lists any properties that belongs to "Range".
The Word object model is not written in VBA (although the documentation is targeted at VBA developers). It is written as a language-agnostic binary object API which can be accessed from multiple languages. (See here for a comparison between using VBA and Python to access the object model.)
In your case, this:
word.Documents(1).Paragraphs.Item(3)
returns an instance of a Paragraph object, which is not equivalent to a string. This makes sense because a Word paragraph is more than just a string -- it may include paragraph-level formatting, drop caps etc, character-level formatting etc.
You need to start by getting the Range object corresponding to the paragraph, via the Paragraph's Range property. The Range object:
corresponds to a contiguous area of the document
Then you need the Text property of the Range object.
Like so:
word = win32.gencache.EnsureDispatch('Word.Application')
word.Documents.Open('xxxxxxxxx.docx')
string = word.Documents(1).Paragraphs(3).Range.Text
print string
if string == "My Hard Coded String":
print "True"
else:
print "False"
NB. I haven't tested, but I don't think you need to explicitly call Paragraphs.Item. The object model supports a concept called default properties, which means that (in Python, at least) you can pass arguments to an object with a default property and those arguments will be passed to the property. In other words, the following are equivalent:
string = word.Documents(1).Paragraphs(3).Range.Text
string = word.Documents.Item(1).Paragraphs.Item(3).Range.Text
I think this is also why print string in your code prints out the string. Not because string is a different kind of string, but because the default property chain is as follows: Paragraph.Range.Text; and when a simple value (as opposed to an object) is expected, the chain is followed until the end, which is a string at the Text property.
Reference:
Paragraphs collection, Paragraphs.Item method
Paragraph object, Paragraph.Range property
Range object, Range.Text property
Note that (in the current documentation formatting) the left side has a list of objects, each of which can be expanded to list the specific object's properties/methods.

Function to express an integer as its reciprocal in fraction form

I am writing a small function that turns a integer into its reciprocal in its fraction form. This is how I've defined my function so far:
def reciprocal (number):
return "1/",number
This sort of works but the problem is that it doesn't print the answer on the screen as I'd like to because say i did print reciprocal(3) it would show ('1/', 3) on the screen instead of 1/3. I have tried all sorts of combinations of speech marks and brackets in the code but the answer has still got extra brackets and back-ticks around it. I am using python 2.7.10, is there any way to get rid of these? Or is there any other simple way to express an integer as its reciprocal in fraction form that would get rid of them? Thank you
Yes. Because what this line is actually doing is returning a tuple:
return "1/",number
If you simply print:
type(reciprocal(3))
You will see the result will be tuple.
In order to keep the functionality of:
print(reciprocal(3))
You would want to do something like this instead:
return "1/{}".format(number)
Now, the above will actually return you a string instead of a tuple. The above is using the string format method, which you can read about here. Ultimately what you are doing is creating a string that will look like 1/x, where x will be number. The way to denote the x is by using the curly braces which is then used a placeholder that will set whatever you passed to format. Read more in the documentation to understand how it works.
To help expand it, what it actually looks like when separated is this:
s = "1/"
Now, you want to be able to set your argument number. The string object supports several methods, one of which, is format. So you can actually simply call it: s.format(). However, that won't simply work the way you want it. So, per the documentation, in order to use this format method, you need to set in your string where exactly you want to set your argument that you want to place in your string. This is done by using the placeholder characters {} to indicate this. So:
s = "1/"
Will now be
s = "1/{}".format(number)
We set our {} as the placeholder of where we want number to be, and we assigned what will be in that placeholder by passing number to format.
You can further see how now you have a string if you in fact print the type of the result:
print(type(reciprocal(3)))
You will see it is now a str type.
As a note in Python, you can create a tuple with comma separated values:
>>> d = 1, 2
>>> type(d)
<class 'tuple'>
This is exactly why your function returns the tuple, because of the fact you are returning two values simply separated by a comma.
You can try this:
def reciprocal (number):
return "1/{}".format(number)
print reciprocal(4)
print reciprocal(100)
Output:
1/4
1/100
Right now you're returning a tuple made of the string "1/" and your number because of the comma. I think what you want to do is return just a string.
Something like return "1/" + str(number)

Python pandas: use of DataFrame.replace function with a function as a value

Using Python pandas, I have been attempting to use a function, as one of a few replacement values for a pandas.DataFrame (i.e. one of the replacements should itself be the result of a function call). My understanding is that pandas.DataFrame.replace delegates internally to re.sub and that anything that works with it should also work with pandas.DataFrame.replace, provided that the regex parameter is set to True.
Accordingly, I followed the guidance provided elsewhere on stackoverflow, but pertaining to re.sub, and attempted to apply it to pandas.DataFrame.replace (using replace with regex=True, inplace=True and with to_replace set as either a nested dictionary, if specifying a specific column, or otherwise as two lists, per its documentation). My code works fine without using a function call, but fails if I try to provide a function as one of the replacement values, despite doing so in the same manner as re.sub (which was tested, and worked correctly). I realize that the function is expected to accept a match object as its only required parameter and return a string.
Instead of the resultant DataFrame having the result of the function call, it contains the function itself (i.e. as a first-class, unparameterized, object).
Why is this occurring and how can I get this to work correctly (return and store the function's result)? If this is not possible, I would appreciate if a viable and "Pandasonic" alternative could be suggested.
I provide an example of this below:
def fn(match):
id = match.group(1)
result = None
with open(file_name, 'r') as file:
for line in file:
if 'string' in line:
result = line.split()[-1]
return (result or id)
data.replace(to_replace={'col1': {'string': fn}},
regex=True, inplace=True)
The above does not work, in that it replaces the right search string, but replaces it with:
<function fn at 0x3ad4398>
For the above (contrived) example, the expected output would be that all values of "string" in col1 are substituted for the string returned from fn.
However, import re; print(re.sub('string', fn, 'test string')), works as expected (and as previously depicted).
My current solution (which seems sub-optimal and ad hoc to me) is as follows (ellipses indicate irrelevant additional code, which has been omitted; specific data used are contrived):
def _fn(match):
...
return ...
def _multiple_replace(text, repl_dictionary):
"""Adapted from: http://stackoverflow.com/a/15175239
Returns the result for the first regex that matches
the provided text."""
for pattern in repl_dictionary.keys():
regex = re.compile(pattern)
res, num_subs = regex.subn(repl_dictionary[pattern], text)
if num_subs > 0:
break
return res
repl_dict = {'ABC.*(\w\w\w)': _fn, 'XYZ': 'replacement_string'}
data['col1'] = data['col1'].apply(_multiple_replace,
repl_dictionary=repl_dict)

Categories