I have a number of objects that I need to print out to the terminal (for debugging). The normal print function is almost perfect, except that some objects are too large, so print would create millions of lines of output. I'd like to create a function that does what print does, except that the output is truncated after a predefined number of characters, replacing the rest with ....
What's a good way to do that?
Note that performance is a concern, so ideally I'd prefer not to save a gigabyte-sized string and then take the first few characters from it; similarly, pprint is a bit of a problem since it sorts keys in dictionaries (and with millions of keys it takes a while).
Example:
obj = [ [1, 2, 3], list(range(1000000)) ]
my_print(obj, 20)
# should output:
# [[1, 2, 3], [0, 1, 2...
Python 3, if it matters.
The reprlib module (Python 3.x only) suggested by #m0nhawk is made exactly for this purpose. Here's how you would use it:
If you're fine with the default limits, you can simply use reprlib.repr(obj):
import reprlib
obj = [[1, 2, 3], list(range(10000))]
print(reprlib.repr(obj))
Output:
[[1, 2, 3], [0, 1, 2, 3, 4, 5, ...]]
In order to customize the available limits, simply create a reprlib.Repr instance and set the appropriate instance attributes:
r = reprlib.Repr()
r.maxlist = 4 # max elements displayed for lists
r.maxstring = 10 # max characters displayed for strings
obj = [[1, 2, 3], list(range(10000)), 'looooooong string', 'a', 'b', 'c']
print(r.repr(obj))
Output:
[[1, 2, 3], [0, 1, 2, 3, ...], 'lo...ing', 'a', ...]
If you're dealing with sequence objects that refer to themselves, you can use Repr.maxlevel to limit the recursion depth:
lst = [1, 2, 3]
lst.append(lst) # oh my!
r = reprlib.Repr()
r.maxlevel = 5 # max recursion depth
print(r.repr(lst))
Output:
[1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [...]]]]]]
Note that reprlib.repr() returns a string, but doesn't print it (unless you're in an interactive console where the result of every expression you enter gets evaluated and its representation displayed).
Why not just make a simple slice wrapper over the print function?
def my_print(obj, depth):
print(str(obj)[:depth])
print does the same thing as str before writing to the output stream. So what you want to do is do that casting early, before passing it into print, and then slice off a chunk of it that has a max size of whatever you want.
Python slicing is graceful, so a string slice like 'xyz'[:30000] evaluates simply to 'xyz' rather than raising an error.
Related
I have narrowed down the problem this much. I have a list [1, 3, 2, 1] and I am looking to store that list in a variable, remove one item index 2 and store the result in another variable. This is the code:
sequence = [1, 3, 2, 1]
temporary_list = sequence
del temporary_list[2]
print(sequence)
print(temporary_list)
However both sequence and temporary_list print the same values ([1, 3, 1]). What am I doing wrong? What would be the right way to get [1, 3, 2, 1] and [1, 3, 1]?
Python 2.x:
temporary_list = sequence[:]
If python 3.x:
Temporary_list = sequency.copy()
Python assigned objects are just a binding between a target and a object, if you want a new object you must "copy" it to create a new object. Look at the official docs for more info:https://docs.python.org/3/library/copy.html
I know there are similar posts to this topic, however they often focus on the list items being letters and so the outcome often means they are wrapped in double quotes.
However, I am dealing with lists of numbers and I have been unable to find a solution that addresses my need for converting a string representation of a list of numerical lists ...
"[1,2,3,4,5,6],[5,1,4,6,3,2],[3,6,4,1,5,2]"
... into an actual list of numerical lists, as I mentioned I am dealing with numerical items for math.
list_string = "[1,2,3,4,5,6],[5,1,4,6,3,2],[3,6,4,1,5,2]"
ini_list = "[" + list_string + "]"
goal = list(ini_list)
print(goal)
#Desired Outcome:
#goal = [[1,2,3,4,5,6],[5,1,4,6,3,2],[3,6,4,1,5,2]]
You can use exec() function, that executes python code.
>>> exec("a = [[1,2,3,4,5,6],[5,1,4,6,3,2],[3,6,4,1,5,2]]")
>>> a
[[1, 2, 3, 4, 5, 6], [5, 1, 4, 6, 3, 2], [3, 6, 4, 1, 5, 2]]
If you take list(string) you will just split string into chars. For example list('[1, 2]') = ['[', '1', ',', ' ', '2', ']'].
But what you have is a string containing a python literal (a piece of code that describes a value). And you need to turn it into actual value. For that there is eval function. So just do goal = eval(ini_list). Hope I helped you.
A very simple (and safe/robust) approach is to use the ast.literal_evel function.
In this case, the ast.literal_eval function is a safe way to evaluate strings and convert them to their intended type, as there is logic in the function to help remove the risk of evaluating malicious code.
Use:
import ast
list_string = "[1,2,3,4,5,6],[5,1,4,6,3,2],[3,6,4,1,5,2]"
result = ast.literal_eval(f'[{list_string}]')
Output:
[[1, 2, 3, 4, 5, 6], [5, 1, 4, 6, 3, 2], [3, 6, 4, 1, 5, 2]]
Here is one faster way to do so using list comprehension and split():
list_string = "[1,2,3,4,5,6],[5,1,4,6,3,2],[3,6,4,1,5,2]"
goal = [[int(num) for num in sublist.split(",")] for sublist in list_string[1:-1].split("],[")]
print(goal) # [[1, 2, 3, 4, 5, 6], [5, 1, 4, 6, 3, 2], [3, 6, 4, 1, 5, 2]]
We separate the string at each ],[, to retrieve the different sublists.
Then, we separate each sublist at , and finally convert the separated numbers to integers.
The alternative with for loops would be:
goal = []
for sublist in list_string[1:-1].split("],["):
new_sublist = []
for num in sublist.split(","):
new_sublist.append(int(num))
goal.append(new_sublist)
print(goal)
Is there a way in Python to sort a list where there are strings, floats and integers in it?
I tried to use list.sort() method but of course it did not work.
Here is an example of a list I would like to sort:
[2.0, True, [2, 3, 4, [3, [3, 4]], 5], "titi", 1]
I would like it to be sorted by value by floats and ints, and then by type: floats and ints first, then strings, then booleans and then lists. I would like to use Python 2.7 but I am not allowed to...
Expected output:
[1, 2.0, "titi", True, [2, 3, 4, [3, [3, 4]], 5]]
Python's comparison operators wisely refuse to work for variables of incompatible types. Decide on the criterion for sorting your list, encapsulate it in a function and pass it as the key option to sort(). For example, to sort by the repr of each element (a string):
l.sort(key=repr)
To sort by type first, then by the contents:
l.sort(key=lambda x: (str(type(x)), x))
The latter has the advantage that numbers get sorted numerically, strings alphabetically, etc. It will still fail if there are two sublists that cannot be compared, but then you must decide what to do-- just extend your key function however you see fit.
The key-argument to list.sort or sorted can be used to sort it the way you need it, first you need to define how you want to order the types, easiest (and probably fastest) is a dictionary with types as keys and order as value
# define a dictionary that gives the ordering of the types
priority = {int: 0, float: 0, str: 1, bool: 2, list: 3}
To make this work one can use the fact that tuples and lists compare by first comparing the first element and if that is equal compare the second element, if that's equal compare the third (and so on).
# Define a function that converts the items to a tuple consisting of the priority
# and the actual value
def priority_item(item):
return priority[type(item)], item
Finally you can sort your input, I'm going to shuffle it because it's already sorted (as far as I understand your question):
>>> l = [1, 2.0, "titi", True, [2, 3, 4, [3, [3, 4]], 5]]
>>> import random
>>> random.shuffle(l)
>>> print(l)
[True, [2, 3, 4, [3, [3, 4]], 5], 'titi', 2.0, 1]
>>> # Now sort it
>>> sorted(l, key=priority_item)
[1, 2.0, 'titi', True, [2, 3, 4, [3, [3, 4]], 5]]
I want to create a function that takes list of any size and returns a list without duplicates.
Let functionl be the function, I want that functionl([1, 2, 3, 1]) returns [1, 2, 3].
I was wondering if a function that accepts a list of any size would be really be as simply as:
def functionl([argument]):
or would i have to just leave some type of variable and append it to a list assigned to that variable.
def function1(argument):
argument = int
argument = []
I can't seem to wrap my head around lists just yet so any advice and knowledge that you all can add would be very much appreciated.
Check the documentation for sets, which are unordered collections without duplicates.
print set([1]) # set([1])
print set([1, 2, 3, 1]) # set([1, 2, 3])
If you want to create a function, since you don't specify types in Python, it's as simple as:
def functionl(lst):
return list(set(lst))
print functionl([1]) # [1]
print functionl([1, 2, 3, 1]) # [1, 2, 3]
Another way is to use the star argument which collects all the arguments in a list:
def functionl(*args):
return list(set(args))
print functionl(1) # [1]
print functionl(1, 2, 3, 1) # [1, 2, 3]
this is the function for which is the unittest written for:
def swap_k(L, k):
""" (list, int) -> NoneType
Precondtion: 0 <= k <= len(L) // 2
Swap the first k items of L with the last k items of L.
>>> nums = [1, 2, 3, 4, 5, 6]
>>> swap_k(nums, 2)
>>> nums
[5, 6, 3, 4, 1, 2]
"""
this is the unittest code:
def test_swap_k_list_length_6_swap_2(self):
"""Test swap_k with list of length 6 and number of items to swap 2.
Also allow for the fact that there are potentially four alternate
valid outcomes.
"""
list_original = [1, 2, 3, 4, 5, 6]
list_outcome_1 = [5, 6, 3, 4, 1, 2]
list_outcome_2 = [5, 6, 3, 4, 2, 1]
list_outcome_3 = [6, 5, 3, 4, 1, 2]
list_outcome_4 = [6, 5, 3, 4, 2, 1]
valid_outcomes = [list_outcome_1, list_outcome_2, list_outcome_3, list_outcome_4]
k = 2
a1.swap_k(list_original,k)
self.assertIn(list_original, valid_outcomes)
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
the unittest code passes and I don't understand why since I think the only valid outcome would be list_outcome_1 judging by the docstring of swap_k...
First of all, the test can pass even if "valid_outcomes" contains more than what's valid. (In your opinion, list_outcome_1). It just means it sometimes won't fail when it should.
Second, I think the test is correct: the doc doesn't say that the first "k" items will be placed last in their original order, nor does it guarantee the same for the last "k" items. So any order of [1,2] could appear at the end of the list, and any order of [5,6] could appear at the beginning.
In general, if something is not guaranteed then I prefer not to assume it, even if it seems logical (a list is ordered, after all, so it's almost natural to assume that).
"Fixing" the unittest would also mean fixing the doc to guarantee order.
self.assertEqual(list_original, list_outcome_1)
and
self.assertIn(list_original, valid_outcomes)
both satisfies the test. Here you are testing whether the true outcome is in list of outcome which is true, so the test is valid.
However as per docstring
self.assertEqual(list_original, list_outcome_1)
would have been better as it checks the equality.