Liam Deacon
Liam Deacon

Reputation: 894

How to unpack different values depending on number of variables to unpack into

I'm scratching my head over how to conditionally unpack variables from a class depending on the number of variables you are unpacking into e.g. I get a different set of variables unpacked depending on the number I set on the left hand side of the assignment.

For example, lets consider a class that has both x, y, z and latitude & longitude positions:

class LatLonOrXYZ:
    def __init__(self, x, y, z, lat, lon):
        self.x, self.y, self.z = x, y, z
        self.lat, self.lon = lat, lon

    def __iter__(self):
        # not sure...
        return iter([self.x, self.y, self.z, self.lat, self.lon])

Now I want to achieve something like the following:

pos = LatLonOrXYZ(x=0, y=1, z=2, lat=3, lon=4)

x, y, z = *pos  # 0, 1, 2
lat, lon = *pos  # 3, 4

Are there any deep python magics that could accomplish this sort of thing or am I better off just writing a couple of methods that feel so unnecessary?

As ever, any help, insights or advice would be greatly received :-)

Upvotes: 0

Views: 234

Answers (1)

Chris Larson
Chris Larson

Reputation: 1714

This is completely doable, but may not be the best application, in your example, of an iterable.

Basically, create a list from your iterable, as in list([*pos]), then slice it as desired like list([*pos])[0:3].

Here's your example code with this in operation:

class LatLonOrXYZ:
    def __init__(self, x, y, z, lat, lon):
        self.x, self.y, self.z = x, y, z
        self.lat, self.lon = lat, lon

    def __iter__(self):
        # not sure...
        return iter([self.x, self.y, self.z, self.lat, self.lon])

pos = LatLonOrXYZ(x=0, y=1, z=2, lat=3, lon=4)

x, y, z = list([*pos])[0:3]
lat, lon = list([*pos])[3:5]

print(x, y, z)
print(lat, lon)

Output:

0 1 2
3 4

As a side note, in your example code, you are calling your actual class object rather than your pos instance. It's important to understand the difference.

Rather than:

pos = LatLonOrXYZ(x=0, y=1, z=2, lat=3, lon=4)

x, y, z = *LatLonOrXYZ  # 0, 1, 2
lat, lon = *LatLonOrXYZ  # 3, 4

What you want to do is:

pos = LatLonOrXYZ(x=0, y=1, z=2, lat=3, lon=4)

x, y, z = *pos  # 0, 1, 2
lat, lon = *pos  # 3, 4

The first line creates an object based on the class definition that is an instance, or an object using the structure and behavior of the class that you'll be using as a position in your code.

Consider the following:

pos_1 = LatLonOrXYZ(x=0, y=1, z=2, lat=3, lon=4)
pos_2 = LatLonOrXYZ(x=4, y=3, z=2, lat=1, lon=0)

These are two different objects with their own characteristics, both structured as the LatLonOrXYZ class has laid out. Separate buildings based on the same blueprint.

This is a really basic description meant to just point out the gist of the thing. You can read more about python classes, here in technical form:

Python.org Classes Tutorial

Or, as an example of the decent explainers, but by far not the only excellent, accessible discussion regarding this stuff for which you should google lots :) , here:

OOP in Python - at Real Python

Upvotes: 1

Related Questions