Python: print variable name and value easily - python

I want to use a function that can automatically print out the variable and the value. Like shown below:
num = 3
coolprint(num)
output:
num = 3
furthermore, it would be cool if it could also do something like this:
variable.a = 3
variable.b = 5
coolprint(vars(variable))
output:
vars(variable) = {'a': 3, 'b': 5}
Is there any function like this already out there? Or should I make my own? Thanks

From Python 3.8 there is a = for f-strings:
#!/usr/bin/env python3
python="rocks"
print(f"{python=}")
This would output
# python=rocks

This lambda-based solution works well enough for me, though perhaps not in every case. It is very simple and only consumes one line.
coolprint = lambda *w: [print(x,'=',eval(x)) for x in w]
Exmaple..
coolprint = lambda *w: [print(x,'=',eval(x)) for x in w]
a, *b, c = [1, 2, 3, 4, 5]
coolprint('a')
coolprint('b','c')
coolprint('a','b','c')
coolprint('c','b','b','a','b','c')
which produces..
a = 1
b = [2, 3, 4]
c = 5
a = 1
b = [2, 3, 4]
c = 5
a = 1
b = [2, 3, 4]
c = 5
c = 5
b = [2, 3, 4]
b = [2, 3, 4]
a = 1
b = [2, 3, 4]
c = 5

An official way to accomplish this task sadly doesn't exist even though it could be useful for many people. What I would suggest and I have used it sometimes in the past is the following(I am not sure if this is the best way to do it).
Basically what you can do is to create a custom object that mimics one Python's data type per time. Bellow you can find an example for an integer.
class CustomVariable(object):
def __init__(self, name, value):
self.name = name
self.value = value
def __str__(self):
return "{} = {}".format(self.name, self.value)
def __add__(self, val) :
return self.value + val
myVar = CustomVariable("myVar", 15)
print myVar
myVar = myVar + 5
print myVar
Output:
myVar = 15
myVar = 20
Check the special method named "___str____"

I'm just appending my custom print which accepts a list or a dict of expressions, adding the globals at the lateral case (excuse the PEP violation, I just love single-liners, especially with lambdas):
pp = lambda p: print(' | '.join([f"{x} = {eval(x)}" for x, v in {**p, **dict(**globals())}.items() if not x.startswith('_')])) if type(p)==dict else print(' | '.join([f"{x} = {eval(x)}" for x in p if not x.startswith('_')]))
# Some Variables:
z = {'a':100, 'b':200}
a = 1+15
# Usage with dict & all the variables in the script:
pp(dict(**locals()))
# Usage with list, for specific expressions:
pp(['a', "z['b']", """ {x:x+a for x in range(95, z['a'])} """])
Note that f'{x =}' won't work correctly, since the evaluation takes scope inside the function.

I have discovered the answer is No. There is no way to do this. However, your best bet is something like this:
from pprint import pprint
def crint(obj, name):
if isinstance(obj, dict):
print '\n' + name + ' = '
pprint(obj)
else:
print '\n' + name + ' = ' + str(obj)
that way you can just do:
crint(vars(table.content[0]), 'vars(table.content[0])')
or:
j = 3
crint(j, 'j')

Related

Is there a way to "fork" a list in two based on a condition [duplicate]

This question already has answers here:
How can I partition (split up, divide) a list based on a condition?
(41 answers)
Closed 4 years ago.
I have seen a pattern repeated a couple times in my team's code, it looks like this
numbers = [1, 2, 3, 4]
even_numbers = [n for n in numbers if n % 2 == 0]
odd_numbers = [n for n in numbers if n % 2 != 0]
I was wondering if there is a function somewhere (I have looked around but haven't been able to find it) that would do something like this
numbers = [1, 2, 3, 4]
even_numbers, odd_numbers = fork(numbers, lambda x: x % 2 == 0)
So, this function I am looking for, would receive an iterable and a function, and return two lists, one would be the values that match a provided condition, and the other would be the ones that didn't.
Is there something around python's standard library that achieves this?
I usually call this sift, but partition is fine too.
Another, itertools-less implementation might be
def sift(iterable, predicate):
t = []
f = []
for value in iterable:
(t if predicate(value) else f).append(value)
return (t, f)
even, odd = sift([1, 2, 3, 4, 5], lambda x: x % 2 == 0)
EDIT: for a slightly more complex implementation that is about 30% faster (on my Python installation anyway):
def sift2(iterable, predicate):
t = []
f = []
ta = t.append
fa = f.append
for value in iterable:
(ta if predicate(value) else fa)(value)
return (t, f)
You can use the following function:
from itertools import filterfalse, tee
def fork(pred, iterable):
'Use a predicate to partition entries into false entries and true entries'
t1, t2 = tee(iterable)
return list(filterfalse(pred, t1)), list(filter(pred, t2))
Source: itertools
I did not find anything in standard library performing what you want. I suggest you this user-defined implementation, which is not optimized at all but very simple and easy to read:
def myFunc(iterable, func):
first = [i for i in iterable if func(i)]
second = [i for i in iterable if not func(i)]
return first,second
numbers = [1, 2, 3, 4]
even_numbers, odd_numbers = myFunc(numbers, lambda x: x % 2 == 0)
print(even_numbers) # [2, 4]
print(odd_numbers) # [1, 3]
Full code following #jonrsharpe suggestion.
import itertools
def fork(iterable):
"Returns list of even, odd elements of a list"
t1, t2 = itertools.tee(iterable)
pred = lambda i: i % 2 == 0
return list(filter(pred, t2)), list(itertools.filterfalse(pred, t1))
odd, even = fork([1,2,3,4,5])
print(odd)
print(even)
Alternative numpy version which might be faster for big arrays
import numpy as np
def fork(iterable):
"Returns array of even, odd elements of an array"
iterable_array = np.asarray(iterable)
mask = (iterable_array % 2 == 0)
return iterable_array[~mask], iterable_array[mask]
You can create your own function:
l = [1, 2, 3, 4]
def fork(l,key):
return list(filter(key,l)), [i for i in l if i not in list(filter(key,l))]
even_numbers, odd_numbers = fork(l, lambda x: x % 2 == 0)
print(even_numbers)
print(odd_numbers)
Output:
[2, 4]
[1, 3]

Printing variable label in function

How would I return a variable name in a function. E.g. If I have the function:
def mul(a,b):
return a*b
a = mul(1,2); a
b = mul(1,3); b
c = mul(1,4); c
This would return:
2
3
4
I would like it to return:
a = 2
b = 3
c = 4
How would I do this?
Unfortunately, you are unable to go "backwards" and print the name of a variable. This is explained in much further detail in this StackOverflow post.
What you could do is put the variable names in a dictionary.
dict = {"a":mul(1,2), "b":mul(1,3), "c":mul(1,4)}
From there you could loop through the keys and values and print them out.
for k, v in dict.items():
print(str(k) + " = " + str(v))
Alternatively, if you wanted your values ordered, you could put the values into a list of tuples and again loop through them in a for loop.
lst = [("a", mul(1,2)), ("b", mul(1,3)), ("c",mul(1,4))]
Here is how to do it with python-varname package:
from varname import varname
def mul(a, b):
var = varname()
return f"{var} = {a*b}"
a = mul(1,2)
b = mul(1,3)
c = mul(1,4)
print(a) # 'a = 2'
print(b) # 'b = 2'
print(c) # 'c = 2'
The package is hosted at https://github.com/pwwang/python-varname.
I am the author of the package. Let me know if you have any questions using it.

Storing every value of a changing variable

I am writing a piece of code that takes an input that varies according to discrete time steps. For each time step, I get a new value for the input.
How can I store each value as a list?
Here's an example:
"""when t = 0, d = a
when t = 1, d = b
when t = 2, d = c"""
n = []
n.append(d) #d is the changing variable
for i in range(t):
n.append(d)
What I expect to get is:
for t = 0, n = [a]; for t = 1, n = [a,b]; and for t = 2, n = [a,b,c]
What I actually get is:
for t = 0, n = [a], for t = 1, n = [b,b]; and for t = 2, n = [c,c,c]
See comment below, but based on the additional info you've provided, replace this:
n.append(d)
with this:
n.append(d[:])
Which type is the variable 'd'? If it is, for instance a list, the code you are showing pushes onto tbe list 'n' a reference to the variable 'd' rather than a copy of it. Thus, for each iteration of the loop you add a new reference of 'd' (like a pointer in C) to 'n', and when 'd' is updated all the entries in 'n' have, of course, the same value
To fix it you can modify the code so as to append a copy of 'd', either:
n.append(d[:])
n.append(list(d))
n.append(tuple(d))
You can simply do this
n = []
for i in range(t + 1):
n.append(chr(i+ord('a'))
And if you do not want to store the characters in the list rather some specific values which are related with d, then you have to change d in the for loop
n = []
d = 1
for i in range(t + 1):
n.append(d)
d += 2
It is difficult to say without seeing the code. But if d is not an int, this could happen. If d is a list for instance, it is passed by reference
n = []
d = [1]
n.append(d)
d[0] = 2
n.append(d)
print(n)
>>>> [[2], [2]]
So if each new d is just modified, your probleme arise. You can solve it by copying d :
from copy import copy
n = []
d = [1]
n.append(copy(d))
d[0] = 2
n.append(copy(d))
print(n)
>>>> [[1], [2]]
If you just wrap the variable inside an object you can watch what is being set to the variable by overriding __setattr__ method. A simple example.
class DummyClass(object):
def __init__(self, x):
self.history_of_x=[]
self.x = x
self._locked = True
def __setattr__(self, name, value):
self.__dict__[name] = value
if name == "x":
self.history_of_x.append(value)
d = DummyClass(4)
d.x=0
d.x=2
d.x=3
d.x=45
print d.history_of_x
Output :-
[4, 0, 2, 3, 45]

Efficient way of counting True and False

This may be a trivial problem, but I want to learn more about other more clever and efficient ways of solving it.
I have a list of items and each item has a property a whose value is binary.
If every item in the list has a == 0, then I set a separate variable b = 0.
If every item in the list has a == 1, then I set b = 1.
If there is a mixture of a == 0 and a == 1 in the list, then I set
b = 2.
I can use a set to keep track of the types of a value, such that if there are two items in the set after iterating through the list, then I can set b = 2, whereas if there is only one item in the set I just retrieve the item (either 0 or 1) and use it to set b.
Any better way?
One pass through the list, and no extra data structures constructed:
def zot(bs):
n, s = len(bs), sum(bs)
return 1 if n == s else 2 if s else 0
I would suggest using any and all. I would say that the benefit of this is readability rather than cleverness or efficiency. For example:
>>> vals0 = [0, 0, 0, 0, 0]
>>> vals1 = [1, 1, 1, 1, 1]
>>> vals2 = [0, 1, 0, 1, 0]
>>> def category(vals):
... if all(vals):
... return 1
... elif any(vals):
... return 2
... else:
... return 0
...
>>> category(vals0)
0
>>> category(vals1)
1
>>> category(vals2)
2
This can be shortened a bit if you like:
>>> def category(vals):
... return 1 if all(vals) else 2 if any(vals) else 0
...
This works with anything that can be interpreted by __nonzero__ (or __bool__ in Python 3) as having a true or false value.
Somebody mentioned code golf, so can't resist a variation on #senderle's:
[0,2,1][all(vals) + any(vals)]
Short explanation: This uses the boolean values as their integer equivalents to index a list of desired responses. If all is true then any must also be true, so their sum is 2. any by itself gives 1 and no matches gives 0. These indices return the corresponding values from the list.
If the original requirements could be modified to use 1 for any and 2 for all it would be even simpler to just return the integer of any + all
Using a dictionary:
zonk_values = {frozenset([0]): 0, frozenset([1]): 1, frozenset([0, 1]): 2}
def zonk(a):
return zonk_values[frozenset(a)]
This also only needs a single pass through the list.
you could also use sets.
s = set([i.a for i in your_list])
if len(s) == 1:
b = s.pop()
else:
b = 2
def zot(bs):
return len(set(bs)) if sum(bs) else 0
You can define two boolean vars hasZero and hasOne and set them to True if corresponding value was met while iterating the list. Then b = 2 if hasZero and hasOne, b = 1 if only hasOne and b = 0 if only hasZero.
Another way: you can sum all the a values along the list. If sumA == len(list) then b = 1, if sumA == 0 then b = 0 and if 0 < sumA < len(list) then b = 2.
Short-circuiting solution. Probably the most efficient way you can do it in Python.
EDIT: Included any and all as per suggestion in comments.
EDIT2: It's now a one-liner.
b = 1 if all(A) else 2 if any(A) else 0
This is similar to senderle's suggestion, but written to access the objects' a properties.
from random import randint
class Item(object):
def __init__(self, a):
self.a = a
all_zeros = [Item(0) for _ in xrange(10)]
all_ones = [Item(1) for _ in xrange(10)]
mixture = [Item(randint(0, 1)) for _ in xrange(10)]
def check(items):
if all(item.a for item in items):
return 1
if any(item.a for item in items):
return 2
else:
return 0
print 'check(all_zeros):', check(all_zeros)
print 'check(all_ones):', check(all_ones)
print 'check(mixture):', check(mixture)
You can use list iterators:
>>> L = [0, 0, 0, 0, 0]
>>> L1 = [1, 1, 1, 1, 1]
>>> L2 = [0, 1, 0, 1, 0]
>>> def fn(i):
... i = iter(i)
... if all(i): return 1
... return 2 if any(i) else 0
...
>>> fn(L)
0
>>> fn(L1)
1
>>> fn(L2)
2

Create a Python list filled with the same string over and over and a number that increases based on a variable.

I'm trying to create a list that is populated by a reoccurring string and a number that marks which one in a row it is. The number that marks how many strings there will be is gotten from an int variable.
So something like this:
b = 5
a = range(2, b + 1)
c = []
c.append('Adi_' + str(a))
I was hoping this would create a list like this:
c = ['Adi_2', 'Adi_3', 'Adi_4', 'Adi_5']
Instead I get a list like this
c = ['Adi_[2, 3, 4, 5]']
So when I try to print it in new rows
for x in c:
print"Welcome {0}".format(x)
The result of this is:
Welcome Adi_[2, 3, 4, 5]
The result I want is:
Welcome Adi_2
Welcome Adi_3
Welcome Adi_4
Welcome Adi_5
If anybody has Ideas I would appreciate it.
You almost got it:
for i in a:
c.append('Adi_' + str(i))
Your initial line was transforming the whole list a as a string.
Note that you could get rid of the loop with a list comprehension and some string formatting:
c = ['Adi_%s' % s for s in a]
or
c = ['Adi_{0}'.format(s) for s in a] #Python >= 2.6
Or as a list comprehension:
b = 5
a = range(2, b + 1)
c = ["Adi_" + str(i) for i in a]
Using list comprehensions:
b = 5
a = range(2, b + 1)
c = ['Adi_'+str(i) for i in a]
for x in c:
print"Welcome {0}".format(x)
Or all on one line:
>>> for s in ['Welcome Adi_%d' % i for i in range(2,6)]:
... print s
...
Welcome Adi_2
Welcome Adi_3
Welcome Adi_4
Welcome Adi_5

Categories

Resources