Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement packing/unpacking in an object

I have a class that only contains attributes and I would like packing/unpacking to work on it. What collections.abc should I implement to get this behaviour?

class Item(object):

    def __init__(self, name, age, gender)
        self.name = name
        self.age = age
        self.gender = gender

a, b, c = Item("Henry", 90, "male")

I would like to avoid using a namedtuple.

like image 366
Har Avatar asked Jun 15 '16 13:06

Har


People also ask

What is packing and unpacking?

Unpacking in Python refers to an operation that consists of assigning an iterable of values to a tuple (or list ) of variables in a single assignment statement. As a complement, the term packing can be used when we collect several values in a single variable using the iterable unpacking operator, * .

What do you mean by unpacking sequence?

Understanding Python Sequence Unpacking Sequence unpacking in python allows you to take objects in a collection and store them in variables for later use. This is particularly useful when a function or method returns a sequence of objects.

What is the unpacking operator in Python?

Both * and ** are the operators that perform packing and unpacking in Python. The * operator (quite often associated with args) can be used with any iterable (such as a tuple, list and strings), whereas the ** operator, (quite often associated with kwargs) can only be used on dictionaries.

What is packing in an argument?

Above operation is called 'packing” as it pack all the arguments into one single variable that this method call receives into a tuple called args. We can use name other than args, but args is the most common and pythonic way of doing things.


3 Answers

You can unpack any Iterable. This means you need to implement the __iter__ method, and return an iterator. In your case, this could simply be:

def __iter__(self):
    return iter((self.name, self.age, self.gender))

Alternatively you could make your class an Iterator, then __iter__ would return self and you'd need to implement __next__; this is more work, and probably not worth the effort.

For more information see What exactly are Python's iterator, iterable, and iteration protocols?


Per the question I linked above, you could also implement an iterable with __getitem__:

def __getitem__(self, index):
    return (self.name, self.age, self.gender)[index]
like image 187
jonrsharpe Avatar answered Oct 16 '22 14:10

jonrsharpe


A better option for unpacking Python 3.7+ dataclasses is as follows:

from dataclasses import astuple, dataclass

@dataclass 
class Item:
    name: str
    age: int
    gender: str

    def __iter__(self):
        return iter(astuple(self))

a, b, c = Item("Henry", 90, "male")
like image 23
Keith Avatar answered Oct 16 '22 15:10

Keith


Another option would be a named tuple

Item = collections.namedtuple('Item', ['name', 'age', 'gender']) 

So this works out of the box:

a, b, c = Item("Henry", 90, "male")

If you're on Python 3.7+, you could also take advantage of dataclasses which are more powerful. But you would need to explicitly call astuple:

@dataclasses.dataclass
class Item(object):
    name: str
    age: int
    gender: str

a, b, c = dataclasses.astuple(Item("Henry", 90, "male"))
like image 6
JBernardo Avatar answered Oct 16 '22 14:10

JBernardo