What's an equivalent in python of stringification C preprocessor macro # - python

https://gcc.gnu.org/onlinedocs/cpp/Stringification.html allows to stringify argument (before evaluation), which is useful for debugging. How would we do it in python?
eg:
def prettyprint(a):
#requires special function stringify
print(stringify('a') + ':' + str(a));
def test():
prettyprint(1+2)
# will print: 1+2:3

I don't think there is a way to do this without using strings. The C preprocessor really only processes text, so stringify is placing the expression in quotes and the rest is eval
def prettyprint(a):
print( a + ':' + str( eval(a) ) )
>>> prettyprint('1+2')
1+2:3
If you don't use strings, then the expression will be evaluated before the call and prettyprint has no way to figure out how the 3 it received came to be.

Related

Python str.format with string contatenation and continuation

I'd like to specify a string with both line continuation and catenation characters. this is really useful if I'm echoing a bunch of related values. Here is a simple example with only two parameters:
temp = "here is\n"\
+"\t{}\n"\
+"\t{}".format("foo","bar")
print(temp)
here's what I get:
here is
{}
foo
And here is what I expect:
here is
foo
bar
What gives?
You can try something like this :
temp = ("here is\n"
"\t{}\n"
"\t{}".format("foo","bar"))
print(temp)
Or like :
# the \t have been replaced with
# 4 spaces just as an example
temp = '''here is
{}
{}'''.format
print(temp('foo', 'bar'))
vs. what you have:
a = "here is\n"
b = "\t{}\n"
c = "\t{}".format("foo","bar")
print( a + b + c)
str.format is called before your strings are concatenated. Think of it like 1 + 2 * 3, where the multiplication is evaluated before the addition.
Just wrap the whole string in parentheses to indicate that you want the strings concatenated before calling str.format:
temp = ("here is\n"
+ "\t{}\n"
+ "\t{}").format("foo","bar")
Python in effect sees this:
Concatenate the result of
"here is\n"
with the resuslt of
"\t{}\n"
with the result of
"\t{}".format("foo","bar")
You have 3 separate string literals, and only the last one has the str.format() method applied.
Note that the Python interpreter is concatenating the strings at runtime.
You should instead use implicit string literal concatenation. Whenever you place two string literals side by side in an expression with no other operators in between, you get a single string:
"This is a single" " long string, even though there are separate literals"
This is stored with the bytecode as a single constant:
>>> compile('"This is a single" " long string, even though there are separate literals"', '', 'single').co_consts
('This is a single long string, even though there are separate literals', None)
>>> compile('"This is two separate" + " strings added together later"', '', 'single').co_consts
('This is two separate', ' strings added together later', None)
From the String literal concatenation documentation:
Multiple adjacent string or bytes literals (delimited by whitespace), possibly using different quoting conventions, are allowed, and their meaning is the same as their concatenation. Thus, "hello" 'world' is equivalent to "helloworld".
When you use implicit string literal concatenation, any .format() call at the end is applied to that whole, single string.
Next, you don't want to use \ backslash line continuation. Use parentheses instead, it is cleaner:
temp = (
"here is\n"
"\t{}\n"
"\t{}".format("foo","bar"))
This is called implicit line joining.
You might also want to learn about multiline string literals, where you use three quotes at the start and end. Newlines are allowed in such strings and remain part of the value:
temp = """\
here is
\t{}
\t{}""".format("foo","bar")
I used a \ backslash after the opening """ to escape the first newline.
The format function is only being applied to the last string.
temp = "here is\n"\
+"\t{}\n"\
+"\t{}".format("foo","bar")
Is doing this:
temp = "here is\n" + "\t{}\n"\ + "\t{}".format("foo","bar")
The key is that the .format() function is only happening to the last string:
"\t{}".format("foo","bar")
You can obtain the desired result using parentheses:
temp = ("here is\n"\
+"\t{}\n"\
+"\t{}").format("foo","bar")
print(temp)
#here is
# foo
# bar

exec with ';' in python

I am creating a string, to print the fields in a list, . the fields should be separated by ';', code snippet looks like this( simplified code, not actual )
list = ["abc","xyz","pqr"]
str = "print " + "list[0]" + ";" + "list[2]" # This is dynamically generated
exec (str)
My problem here is, with exec statement, it prints only "xyz" , because of the semi colon. what is the best way to solve this, so that the exec statement prints "xyz;pqr"
You are generating the following code:
print list[0];list[2]
Note that the ; is not quoted. Since a ; is used by Python to separate multiple simple statements on a line, Python executes the print list[0] first, then list[2] (which ends up doing nothing).
You'd have to generate this code instead:
print list[0] + ';' + list[2]
which you could do with:
str = "print " + "list[0]" + " + ';' + " + "list[2]"
However, you should not be using code generation at all. Use standard Python methods to join or format a string. You could use str.format():
print '{};{}'.format(list[0], list[2])
or you could use str.join():
print ';'.join([list[0], list[2]])
If you must vary what code is executed based on some other variables, try to avoid exec still. You could use from __future__ import print_function or encapsulate the print statement in a new function, then call functions dynamically. You can always use a dispatch table to map a string to a function to call, for example.
Try this:
str = "print" + "list[0]" + "';'" + "list[2]"
or
str = "print" + "list[0]" + "/;" + "list[2]"
The problem here is that Python optionally allows semicolons to delimit two separate statements (Compound statements). So when you use exec on the evaluated statement print "abc";"xyz", Python thinks they are two separate statements, hence, only printing "abc".
You could use single quotes around the semicolon to show that it is a string and concatenate them with their surrounding strings:
# Refrain from using list and str as they are built-ins
l = ["abc", "xyz", "pqr"]
s = "print " + "l[0]" + "+';'+" + "l[2]"
exec(s)

Multiline string containing """ (triple quotes)

How can I define python multi line string containing """ (3 double quotes)
my desired output is
"""
TEST
"""
Reason: I am writing a script to create some boilerplate code.
Use triple single quotes:
'''
"""Test"""
'''
The solution with ''' should work, but just for the case you need both of them in a string, you can predefine a string with one of them, such as
TRIPSING = "'''"
TRIPDOUB = '"""'
and then
MYSTRING = TRIPDOUB + "\nTEST\n" + TRIPDOUB
You can also try,
>>> a = "\"\"\"TEST\"\"\""
>>> print a
"""TEST"""
>>>

Function equivalent to prepending string with "r" in Python

It's great that I can write
s = r"some line\n"
but what is the functional equivalent to preprending with r? For example:
s = raw_rep( s )
There isn't one. The r is an integral part of the string literal token, and omitting it is a lossy operation.
For example, r'\n', r'\12' and r'\x0a' are three different strings. However, if you omit the r, they become identical, making it impossible to tell which of the three it was to begin with.
For this reason, this is no method that would reconstruct the original string 100% of the time.
def raw_rep(s):
quote = '"' if "'" in s else "'"
return 'r' + quote + s + quote
>>> print raw_rep(r'some line\n')
r'some line\n'

Python: Using strings as an object argument?

Essentially my problem is as follows...
In Python, I have a function that will return an output string in the following form:
'union(symbol(a), symbol(b))'
The function forms found within this string actually exist in an object class called RegExTree. Further this class contains a function to construct a tree data structure using the function "construct()" as shown below:
tree = RegExTree()
tree.construct(union(symbol(a), symbol(b))
The above two lines of code would work normally, constructing a tree based on parsing the arguments within the construct function. I want to pass in a string in a similar fashion, perhaps this line of code illustrates what I want:
tree = RegExTree()
expression = 'union(' + 'symbol(' + 'a' + ')' + ', ' + 'symbol(' + 'b' + ')' + ')'
tree.construct(expression)
Right now the way I have the code written as above it yields an error (in the Linux terminal) as follows:
$ Attribute Error: 'str' object has no attribute 'value'
Can you coerce Python to interpret the string as a valid argument/line of code. In essence, not as string, but as object constructors.
Is there a way to get Python to interpret a string as rather something that would have been parsed/compiled into objects and have it construct the objects from the string as if it were a line of code meant to describe the same end goal?
Is what I'm asking for some kind of back-door type conversion? Or is what I'm asking not possible in programming languages, specifically Python?
EDIT: Using Michael's solution posited below that involves "eval()", there is one way to hack this into form:
tree = RegExTree()
a = 'a'
b = 'b'
expression = 'union(' + 'symbol(' + a + ')' + ', ' + 'symbol(' + b + ')' + ')'
tree.construct(eval(expression))
Is there a better way of doing this? Or is it just that the nature of my output as string representing functions is just not a good idea?
[Thanks martineau for the correction for my solution edit!]
You can use the python built-in eval statement.
A word of caution though... you do not want to run eval() on a string that's coming into your program as external input provided by the user. That could create a security hole where users of your program could run arbitrary Python code of their own design.
In your example it'd look something like this:
tree = RegExTree()
expression = 'union(' + 'symbol(' + 'a' + ')' + ', ' + 'symbol(' + 'b' + ')' + ')'
tree.construct( eval(expression) ) # Notice the eval statement here

Categories

Resources