简体   繁体   中英

There are no pointers in Python; then how to bulk assing values to variables without repeating myself?

Consider this snippet:

key1 = 5
key2 = "5"

for key in [key1, key2]:
    if isinstance(key, int) or isinstance(key, float):
        key = str(key)

print(type(key1))
print(type(key2))
print(key1 == key2)

Of course it prints out:

<class 'int'>
<class 'str'>
False

While I want to make certain that if key1 is a number and key2 is a string representing this number (or vice versa) they are both treated as equal.

Now I don't want to simply convert both keys to str because I don't want to have to consider in details what will happen if either key is a more complex type and if in such a case the comparison will still have the correct semantics. Hence the (unpythonic, isn't it? Sorry I'm kind of newbie to Python) type checking.

However, a naive implementation leads to code repetition:

if isinstance(key1, int) or isinstance(key1, float):
    key1 = str(key1)
if isinstance(key2, int) or isinstance(key2, float):
    key2 = str(key2)

It may be sufferable in this particual case, but if the comparison semantics grow and the conditions in if and/or conversions become more and more complex, then this repetition may become unacceptable.

However, this is Python, so of course I can't take a pointer to either key and operate on that. See the first snippet failing to provide correct semantics. And of course there are no ref parameters in Python either.

So, what is the correct way to avoid code repetition here?

EDIT: Since many people asked me for the bigger picture:

What I'm doing is, pretty much, fixing references. I'm dealing with an API that returns JSON objects. Sadly, this API is pretty much inconsistent and I have to deal with this.

For example, this API may return an object of this sort:

"GroupsOfFoo": [
{
    "group_id": '5',
    "group_name": "Awesome Group",
    "some_other_detail_of_the_group": {...}
}, {
    "group_id": '3',
    "group_name": "Joyful Group",
    "some_other_detail_of_the_group": {...}
}, ...
]

"Foos": [
{
    "foo_id": 'foo1',
    "group_id": 5,
    "some_other_detail_of_foo": {...}
},
{
    "foo_id": 'foo2',
    "group_id": 5,
    // Yep field "some_other_detail_of_foo" may be inconsisntetly present or absent but I'm digressing
},
{
    "foo_id": 'foo3',
    "group_id": 3,
    "some_other_detail_of_foo": False
},
...
]

So I'm now on my quest to fix these references. I want to add a field foos to the each group object that will be a list of foos of this group. Consistently, I want to make the field group_id in the foo object be a reference to the correct group and not an int or string.

Since we also have Groups of Bars and Groups of Bazs and whatever else, and in Bars the id of the group is bar.info.type and not bar.group_id as in foos, and since the code for fixing these references is getting repetitive in all those models already, I'm moving this code from all those models to a (pretty generic) function that takes a group object, list of members of this group, name of the attribute of the group that is the id of this group, name of the attribute of the member of the group that points to this group, quite a few other arguments that specify binding semantics...

And this function needs to compare the id of the group as present in the group object to the id of the group as present in the object representing a member of this group. Here I am.

Just do in-line casting without assigning the casted values to the variables. Like this:

key1 = 5
key2 = "5"

print(type(key1))
print(type(key2))
print(key1 == key2)
print(str(key1) == str(key2))
print(int(key1) == int(key2))

Of course, if you have a leading zero on the string, eg key1 = "05" and key2 = 5 then str(key1) == str(key2) will return False, whereas int(key1) == int(key2) will return True.

looking at your snippet, if you parsed it with json.loads it looks like you would end up with a list of dicts, which is pretty much the ideal situation for this.

something like

for item in my_json_list:
    # item here is a dict
    if 'group_id' in item.keys(): # check whether the key is in this dict
        item['group_id'] = str(item['group_id'])
        # cast the value as a str (if it's a string to start with it doesn't change)

since lists and dictionaries are mutable changing the object you're referring to will change it in the list / dictionary (in some senses there are no pointers in python, but in some senses everything in python is a pointer..)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM