Reputation: 19
I am modifying the print function like:
cg = "\u001b[32;1m"
stop = "\u001b[0m"
_print = print
def print(*args, **kw):
#color the word "CommandGeek" green
args = (arg.replace('CommandGeek', f'{cg}CommandGeek{stop}') if isinstance(arg, str) else arg for arg in args)
_print(*args, **kw)
What I want to do is add some code like so:
cg = "\u001b[32;1m"
stop = "\u001b[0m"
_print = print
def print(*args, **kw):
#color the word "CommandGeek" green
args = (arg.replace('CommandGeek', f'{cg}CommandGeek{stop}') if isinstance(arg, str) else arg for arg in args)
#Color entire the message green if "CommandGeek:" is in it.
if "CommandGeek:" in args:
args = cg + args + stop
_print(*args, **kw)
But this doesn't work, and it just prints nothing. I also tried to just put in the if statement without the modification to args, and it still did nothing. What is happening here, and how do I change the value that will be printed if "CommandGeek:" is in the message?
Upvotes: 0
Views: 207
Reputation: 9377
Without advanced constructs like generator, list-comprehension or similar.
First we need to understand that *args
is a parameter named args
defined as varargs (multiple parameters as tuple). See
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
See also this answer which explains it very well:
Using
*args
in the function signature packs all of the positional arguments into a single tuple args. If you then say*args
in another function call within your the function body, it spreads it back into multiple arguments, [..]
This is used in your function definition def print(*args, **kw):
to mimic the same signature (parameters) as the built-in print
function, originally in Python. With the re-definition _print = print
before this can be seen as interceptor.
The effect will be a print
function that automatically highlights words or output using ANSI-colors (ANSI-escape code) when certain keyword (here "CommandGeek" found).
Implement the comments (tasks) inside the function body:
#color the word "CommandGeek" green
# locate the word
# surround it with ANSI-color code
#Color entire the message green if "CommandGeek:" is in it.
# locate the word
# surround the entire message with ANSI-color code
Your input (the message(s) containing words or commands) is given by parameter *args
which we know is to pack all positional arguments into a tuple (varargs). The tuple is named args
.
GREEN = "\u001b[32;1m"
RESET = "\u001b[0m"
WORD = "CommandGeek"
# a testable function with debug-prints
def color(*args):
print(len(args))
colored = []
for a in args:
s = str(a)
if s.__contains__(WORD):
print("Found it in: " + s)
colored.append(s.replace(WORD, f"{GREEN}{WORD}{RESET}"))
else:
colored.append(a)
return colored
colored = color('Hello', 'World', 'CommandGeek')
print(colored) # prints the list or tuple (not colored)
print(*colored) # prints all with color if found (because unpacked)
Prints (bold was originally green in console):
3
Found it in: CommandGeek
Hello World CommandGeek
Now we have one word colored. Next let's color the entire message (= all args) if at least one contains the word.
GREEN = "\u001b[32;1m"
RESET = "\u001b[0m"
WORD = "CommandGeek"
def contains_word(*args):
for a in args:
s = str(a)
if s.__contains__(WORD):
return True
return False
tuple = ('Hello', 'World', 'CommandGeek') # define a tuple
should_color = contains_word(*tuple) # unpack a tuple as multiple args (varargs)
if should_color:
print(GREEN, *tuple, RESET) # prints all elements in color (unpacked)
else:
print(*tuple) # prints the tuple (unpacked, not colored)
Prints (bold was originally green in console):
** Hello World CommandGeek**
Update: complete solution (fixed leading space)
GREEN = "\u001b[32;1m"
RESET = "\u001b[0m"
KEYWORD = "CommandGeek"
def color_word(*args):
colored = []
for a in args:
if isinstance(a, str):
colored.append(a.replace(KEYWORD, f"{GREEN}{KEYWORD}{RESET}"))
else:
colored.append(a)
return colored
print(*color_word('Hello', 1, 'World', True, '_CommandGeek_'))
def contains_word(*args):
for a in args:
if str(a).__contains__("CommandGeek"):
return True
return False
def color_message(*args):
if contains_word(*args): # unpack a tuple as multiple args (varargs)
# surround tuples with color-code and reset-code
colored = (f"{GREEN}{args[0]}",) + args[1:] # prepend to first element (new colored tuple)
colored = colored[0:-1] + (f"{colored[-1]}{RESET}",) # and append on last element (replace colored tuple)
return colored
return args
print(*color_message('Hello', 1, 'World', True, '_CommandGeek_'))
print(*color_message('Hello: CommandGeek'))
Prints on a console supporting ANSI-colors:
builtins
can be used to e.g. builtin.print()
when redefining the original name locallycolorama
or termcolor
Upvotes: 1
Reputation: 6857
When you do the replacement, you're setting args
to a generator expression, since you're using generator expression syntax. args
needs to be a tuple
. All you have to do is add the word tuple
to the front of the statement and it will work just fine:
args = tuple(arg.replace('CommandGeek', f'{cg}CommandGeek{stop}') if isinstance(arg, str) else arg for arg in args)
To test this I did:
cg = "_Testing_"
stop = "_123_"
_print = print
def print(*args, **kw):
#color the word "CommandGeek" green
args = tuple(arg.replace('CommandGeek', f'{cg}CommandGeek{stop}') if isinstance(arg, str) else arg for arg in args)
#Color entire the message green if "CommandGeek:" is in it.
if "CommandGeek:" in args:
args = cg + args + stop
_print(*args, **kw)
print('Test CommandGeek Test','CommandGeek','BlahBlah')
Output:
Test _Testing_CommandGeek_123_ Test _Testing_CommandGeek_123_ BlahBlah
Upvotes: 0