How to remove extra list from the result in python - python

Result has extra brackets, how can I remove them in python?
I am calling two methods where one returns a tuple of dictionaries and the second returns a list of tuples of dictionaries.
print method_A() // ({'id': 6}, {'id': 9})
print method_B() // [({'id': 6}, {'id': 9})]
How can I remove the list from the result of second method?
I tried it with type checking and has worked but I want to know if there is any easy to way to do it.
I tried following code:
resultA = method_A() // ({'id': 6}, {'id': 9})
resultB method_B() // [({'id': 6}, {'id': 9})]
if type(resultA) == list:
resultA = resultA[0]
if type(resultB) == list:
resultB = resultB[0]
or directly I can use resultB[0] if I know it

If one of these methods always returns a list with the tuple element, just use indexing:
resultA = method_A()
resultB = method_B()[0]
If either method sometimes returns a list object and sometimes just the tuple, use a function:
def unwrap(v):
v[0] if isinstance(v, list) else v
and use that:
resultA = unwrap(method_A())
resultB = unwrap(method_B())
Then contact whomever created those methods and talk to them sternly about consistency in API design.

Related

Pythonic way of copying a dict without distinct attribute

In ECMAScript6 you can use the spread operator to destructure an object like this
const {a, ...rest} = obj;
Which does a shallow copy of obj to rest without attribute a.
Is there a clean way of doing the same in python?
Python dict literals can use the unpacking operator, like { **obj, 'a': 3 } to make a shallow copy overriding some particular properties, but there is no special syntax to omit a property from the unpacking. Also, while python can destructure sequences and nested sequences, you cannot use a dictionary pattern on the left-hand-side of an destructuring assignment.
However, it is possible to do this a bit more verbosely using a dict comprehension:
rest = { k: v for k, v in obj.items() if k != 'a' }
But for readability, two lines is probably better:
rest = dict(obj)
rest.pop('a', None)
Or if you expect the key 'a' to always appear in the original dictionary, and you'd like a KeyError when it's missing, you can use del:
rest = dict(obj)
del rest['a']
I wouldn't call it "clean", but we can (ab)use the function keyword parameter mechanism:
>>> obj = {'b': 2, 'a': 1, 'c': 3}
>>> (lambda a=None, **rest: rest)(**obj)
{'b': 2, 'c': 3}
Or if the goal was to assign to two variables a and rest (I'm not sure since I don't do ECMAScript):
obj = {'b': 2, 'a': 1, 'c': 3}
a, rest = (lambda a=None, **rest: (a, rest))(**obj)
print('a: ', a)
print('rest:', rest)
Output:
a: 1
rest: {'b': 2, 'c': 3}
An possible answer that works, but may not be the prettiest is:
new_dict= rest.copy() # create copy to delete keys
try:
del new_dict["a"]
except KeyError:
print("The key 'a' was not found.")

Check is the structure is empty (python)

I use a special class of objects and some method which returns me structures such as:
{'items': [{'_from': 12,
'bla': 3713,
'ff': 0.0,
'd': 45755,
'fdef': 1536},
{'_from': None,
'bla': 3712,
'ff': 0.0,
'd': 45838,
'fdef': 1536}]}
Sometimes this structure is empty and then I get the following;
{'items': []}
How can I check in my program if the returning structure is empty? It has no such attributes as length. It seems that I can access single elements of the structure only via the Loop (so nothing like structure['items']['bla'] is possible):
for k in myStructure.items:
idd=k.bla
How can I perform such a check in an elegant way?
Empty lists evaluate to False when used in an if-statement.
if myStructure.items:
for k in myStructure.items:
idd=k.bla
Example:
>>> if []:
print('here')
>>>
>>>
You can iterate directly over values. As I show below, you can get the length of the empty list, which is 0, or you can simply use if i which will be True if the list is not empty.
myStructure = {'items': []}
for i in myStructure.values():
if not i:
print ("list is empty")
print (len(i))

python list append method do not return expected results?

This is the code:
def appd():
atho = []
data = {'snm':None}
for i in range(5):
data['snm'] = i
atho.append(data)
return atho
I expect that the result will be like this:
[{'snm': 0}, {'snm': 1}, {'snm': 2}, {'snm': 3}, {'snm': 4}]
but the result I got in python 3 platform is:
[{'snm': 4}, {'snm': 4}, {'snm': 4}, {'snm': 4}, {'snm': 4}]
How does that happen?
A dictionary cannot have identical keys. So, every time you are doing data['snm'] = i you are replacing the value. Also, your append adds the same dictionary every time, not a copy. So, you list does not have 5 dictionaries, it has 5 references to the same dictionary. And, when it changes, all positions of your list change.
Short fix: add a new dict every time
for i in range(5):
atho.append({'snm': i})
Dictionary cannot hold duplicate keys. If you try adding duplicates, the last added value is added to the key.
>>> d = {'a': 1}
>>> d['a'] = 2
>>> d['a'] = 3
>>> d
{'a': 3}
>>>
With data['snm'] = i, you are basically doing the same thing and this dictionary is being added to list using append.
To fix it, define data = {} inside your loop, so every time you create a new dictionary before appending.
def appd():
atho = []
for i in range(5):
data = {}
data['snm'] = i
atho.append(data)
return atho
print(appd())
You are inserting the same dictionary again and again, instead of inserting a new dictionary whose key is snm.
On each iteration of the range, you are updating the value of the dictionary, therefore it gets updated for all the elements in the list, because all of them point to the same dictionary instance.
You must create a new dictionary on each iteration and then insert it.
Try this:
def appd():
atho = []
for i in range(5):
atho.append({'snm':i})
return atho
If you reuse the same oject, again and again, you are simply updating it's contents. The trick is either to explicitly copy the object or create a new one. You cannot simply keep overriting the same key and expect different values
You are actually appending a reference to the original dictionary.
The result you are seeing is the last iteration of your loop updating the dictionary, and thus all its references in your list.
Using atho.append(data.copy()) will work.

Return an input dictionary keep the reference

I have a program where a dictionary of some properties must be copied for each year in my simulation, and some few keys have to be updated. But, when I sent a dictionary to a function, change it inside the function and than return it, the returned dictionary keep as a reference to the original one. Let me show a simple example with the code below.
def change(dict_in):
dict_in['value'] = 50
return dict_in
props = [{'value':12}]
props.append(change(props[-1]))
props
[{'value': 50}, {'value': 50}]
However as one can see above, the property 'value' was changed in the first dict too.
When I use the copy.deepcopy function than it works as expected:
import copy
props = [{'value':12}]
props.append( change( copy.deepcopy(props[-1]) ) )
props
[{'value': 12}, {'value': 50}]
But is this the only way to make it work!?
If the problem you see with deepcopy and update is that a copy of the dictionary will be created after each iteration of your simulation, you could consider using an immutable dictionary type. Unfortunately, immutable dicts are not supplied by the python standard library. However, the data structure is available in libraries such as pyrsistent. From the pyristent docs of pmap:
>>> from pyrsistent import m, pmap, v
# No mutation of maps once created, instead they are
# "evolved" leaving the original untouched
>>> m1 = m(a=1, b=2)
>>> m2 = m1.set('c', 3)
>>> m3 = m2.set('a', 5)
>>> m1
pmap({'a': 1, 'b': 2})
>>> m2
pmap({'a': 1, 'c': 3, 'b': 2})
>>> m3
pmap({'a': 5, 'c': 3, 'b': 2})
>>> m3['a']
5
dict.update() approach
def change(dict_in):
new_dict = {}
new_dict.update(dict_in)
new_dict['value'] = 50
return new_dict
props = [{'value':12}]
props.append(change(props[-1]))
props
[{'value': 50}, {'value': 50}]
d1.update(d2) does not return the result, it modifies d1 in order to include d2 values. That's why I first create a new empty dict and copy the input values into it.
dict() approach
def change(dict_in):
new_dict = dict(dict_in)
new_dict['value'] = 50
return new_dict
props = [{'value':12}]
props.append(change(props[-1]))
props
[{'value': 50}, {'value': 50}]
Similar to the previous version but using the dict constructor
dict comprehension approach
def change(dict_in):
new_dict = {k: v for k, v in dict_in.items()}
new_dict['value'] = 50
return new_dict
props = [{'value':12}]
props.append(change(props[-1]))
props
[{'value': 50}, {'value': 50}]
And another copy method using dict comprehensions.
**kwargs approach
def change(**kwargs):
kwargs['value'] = 50
return kwargs
props = [{'value':12}]
props.append(change(**props[-1]))
props
[{'value': 50}, {'value': 50}]
The ** notation before a function formal parameter (in the def line) means that the keyword arguments that are not explicitely specified will be stored as a dict. kwargs is a common name for this variable. A single * works similar for positional arguments storing them in a list.
The ** notation when calling a function means the opposite, extract the dict values into keyword arguments. Same with * and lists.
This way we are extracting props[-1] which is the original dict into a set of keyword arguments and creating a new dict with **kwargs. I actually like this approach as you let Python handle the new dict creation but you have to remember to use the ** when calling change.
If it fits into your program, you can divide the data into two parts: the constant base which remains the same (and which you are now copying from one simulation round to the next) and the rest, i.e. the changes or updates. You can join the two parts using the ChainMap. It is available on Python 3, but it might be worth to backport it if you are using Python 2.
Here is an example.
from collections import ChainMap
base = dict(a=1, b=2, c=3, d=4)
updates = [
dict(a=99),
dict(b=99),
dict(a=0, b=0, c=0),
]
for i, update in enumerate(updates, 1):
combined = ChainMap(update, base)
print("#{}: a={}, b={} c={} d={}".format(
i, combined['a'], combined['b'], combined['c'], combined['d']))
#1: a=99, b=2 c=3 d=4
#2: a=1, b=99 c=3 d=4
#3: a=0, b=0 c=0 d=4

Simple 1 line For Loops

Typically I have used list comprehensions to iterate and filter by data (i.e dicts etc) within the need to write multiple line for loops.
[x['a']["b"] for x in s["items"] if x["car"] == "ford"]
However this returns a list such as :
[False]
Not a massive problem as I can write
[x['a']["b"] for x in s["items"] if x["car"] == "ford"][0]
However is there a way either with list comprehensions or another way to write a for loop which an if condition so that I only get a string returned ?
Edit : In other words how can I place the following onto a single line and return a string,
for x in s["items"]:
if x["car"] == "ford":
print x['a']['b']
Thanks,
If I understand correctly, you want to short-circuit at the first match. Use next along with a generator expression:
>>> s = {'items': [{'a': {'b': 'potato'}, 'car': 'ford'}, {'a': {'b': 'spam'}, 'car': 'honda'}]}
>>> next(x['a']['b'] for x in s['items'] if x['car'] == "ford")
'potato'
As you have not shown that dict s, i have tested it with the possible data and it works fine:
>>> s = {'items': [{'a': {'b': 1}, 'car': 'ford'}, {'a': {'b': 1}, 'car': 'honda'}]}
>>> print [x['a']['b'] for x in s['items'] if x['car'] == "ford"]
[1]
There is nothing in the syntax of your problem that guarantees that there is only value in s that satisfies the criterion. (I.E., for an arbitrary dict s, there could be more than one.)
You may be able to guarantee that to be the case, but that is external to (this part of) the code.
Hence python isn't going to be able to automatically enforce that.

Categories

Resources