<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nadim Jendoubi</title>
    <description>The latest articles on DEV Community by Nadim Jendoubi (@algoryst).</description>
    <link>https://dev.to/algoryst</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1070723%2F32f5393d-b035-49d8-a243-e97ed7e40a76.jpg</url>
      <title>DEV Community: Nadim Jendoubi</title>
      <link>https://dev.to/algoryst</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/algoryst"/>
    <language>en</language>
    <item>
      <title>Pythonic Techniques for Handling Sequences</title>
      <dc:creator>Nadim Jendoubi</dc:creator>
      <pubDate>Mon, 22 May 2023 10:02:05 +0000</pubDate>
      <link>https://dev.to/algoryst/pythonic-techniques-for-handling-sequences-1p19</link>
      <guid>https://dev.to/algoryst/pythonic-techniques-for-handling-sequences-1p19</guid>
      <description>&lt;p&gt;Sequences and Collections are an integral part of any programming language. Python particularly handles them uniformly, i.e. any type of sequence from Strings and XML elements to arrays, lists, and Tuples are handled in a uniform way.&lt;/p&gt;

&lt;p&gt;Understanding the variety of these sequences will spare us the reinvention of the wheel as the existing common sequence interface allows us to leverage and support any new sequence types.&lt;/p&gt;

&lt;h2&gt;
  
  
  The built-in sequences and how to group them
&lt;/h2&gt;

&lt;p&gt;There are 2 types of sequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The container sequences: these hold items of different types, including nested containers. Like list, tuple, and double-ended queues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The flat sequences: these hold items of simple types. Like str and byte.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A container sequence holds references to the objects it contains, which may be of any type, while a flat sequence stores the value of its contents in its own memory space, not as distinct Python objects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pgeke_fD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fe8n1tociorz3tv4v81q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pgeke_fD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fe8n1tociorz3tv4v81q.png" alt="Simplified memory diagrams for a tuple and an array, each with three items. The tuple has an array of references to its items. Each item is a separate" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another way to group sequences is Mutability VS Immutability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Mutable sequences: sequences that can change their values, for example, list, bytearray, array.array, and collections.deque.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Immutable sequences: sequences that can not change their values, for example, tuple, str, and bytes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s see what we can learn about Sequences! ✌️&lt;/p&gt;

&lt;h2&gt;
  
  
  List Comprehensions
&lt;/h2&gt;

&lt;p&gt;ListComp is a very concise way to create a list from an existing list, sometimes by operating on the existing items, using a simpler cleaner more compact syntax, all of this without having to deal with Python lambda.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fruits = ["apple", "banana", "cherry", "kiwi", "mango"]
newlistUsingForLoop = []
newlistUsingListComp = []

# using traditional for loop
for x in fruits:
  if "a" in x:
    newlistUsingForLoop.append(x)

print(newlistUsingForLoop) # ['apple', 'banana', 'mango']

# using ListComp
newlistUsingListComp = [x for x in fruits if "a" in x]

print(newlistUsingListComp) # ['apple', 'banana', 'mango']

# we can notice how easily readable the list comprehension version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generator Expressions
&lt;/h2&gt;

&lt;p&gt;A generator expression(GenExps) is an expression that returns a generator object, i.e. a function that contains a yield statement and returns a generator object.&lt;/p&gt;

&lt;p&gt;GenExps use the same syntax as ListComps, but are enclosed in parentheses rather than brackets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# create the generator object
squares_generator = (i * i for i in range(5))

# iterate over the generator and print the values
for i in squares_generator:
    print(i)

# this will output the square of numbers from 0 to 4 

colors = ['black', 'white']
sizes = ['S', 'M', 'L']
for tshirt in (f'{c} {s}' for c in colors for s in sizes):
    print(tshirt)

# black S
# black M
# black L
# white S
# white M
# white L
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tuples are Not Just Immutable Lists
&lt;/h2&gt;

&lt;p&gt;Python presents Tuples as Immutable Lists, only this does not do them justice as they can be used as immutable lists and also as records with no field names.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tuples as records:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tuples can serve as temporary records with no field names, this can be done only if the number of items is fixed and the order of items is respected as it is important.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coordinates = [(33.9425, -118.408056), (31.9425, -178.408056)]
for lat, _ in coordinates:
    print(f 'cordinate latitude: {lat}')

# this will print the latitude each time ignoring the longitude value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two ways of creating tuples with named fields but in this instance, they will be regarded as data classes and it is not what we want to discuss here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tuples as immutable lists:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tuples are also highly used in Python standard library for their immutability which brings clarity and performance optimization to the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a = (10, 'alpha', [1, 2])
b = (10, 'alpha', [1, 2])
print(a == b) 
# True
b[-1].append(99)
print(a == b) 
# False
print(b)
# (10, 'alpha', [1, 2, 99])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one caveat to mention, as portrayed above in the code example, only the references contained in the tuple are immutable, the objects held in the references can change their values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4lax2CLN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/341odlphr5347gk4jvl1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4lax2CLN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/341odlphr5347gk4jvl1.png" alt="The content of the tuple itself is immutable, if one of the referenced objects is mutable like a list its content may change. Image from the Book Fluent Python" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Changing the value of an item in a tuple can lead to serious bugs as tuples are hashable, it is better to use a different data structure for your specific use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unpacking Sequences and Iterables
&lt;/h2&gt;

&lt;p&gt;Unpacking is an operation that consists of assigning an iterable of values to a list of variables in a single assignment statement, it avoids unnecessary and error-prone use of indexes to extract elements from sequences.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coordinates = (33.9425, -118.408056)
latitude, longitude = coordinates # unpacking
print(latitude) 
# 33.9425
print(longitude) 
# -118.408056
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use the excess operator &lt;code&gt;*&lt;/code&gt; for tuples and the excess operator &lt;code&gt;**&lt;/code&gt; for dictionaries when unpacking too.&lt;/p&gt;

&lt;p&gt;The target of unpacking can use nesting, i.e. something like (a, b, (c, d)). Python will do the right thing if the value has the same nesting structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Tuple Example
fruits = ("apple", "mango", "papaya", "pineapple", "cherry")
(green, *tropic, red) = fruits
print(green)
# apple
print(tropic)
# ['mango', 'papaya', 'pineapple']
print(red)
# cherry

# Dictionary Example
def myFish(**fish):
    for name, value in fish.items():
        print(f'I have {value} {name}')

fish = {
    'guppies': 2,
    'zebras' : 5,
    'bettas': 10
}
myFish(**fish)

# I have 2 guppies
# I have 5 zebras
# I have 10 bettas

# Nested Unpacking Example
metro_areas = [
('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
('São Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
]

print(f'{"":15} | {"latitude":&amp;gt;9} | {"longitude":&amp;gt;9}')
for name, _, _, (lat, lon) in metro_areas:
    if lon &amp;lt;= 0:
        print(f'{name:15} | {lat:9.4f} | {lon:9.4f}')

#                     | latitude | longitude
# Mexico City         | 19.4333 | -99.1333
# New York-Newark     | 40.8086 | -74.0204
# São Paulo           | -23.5478 | -46.6358
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sequence Pattern Matching
&lt;/h2&gt;

&lt;p&gt;Pattern matching is done with the match/case statement. It is very similar to the if-elif-else statement only cleaner more readable and wields the power of Destructuring.&lt;/p&gt;

&lt;p&gt;Destructuring is a more advanced form of unpacking, as it allows writing sequence patterns as tuples or lists or any combination of both.&lt;/p&gt;

&lt;p&gt;Here’s a nice example I found on the &lt;a href="https://guicommits.com/python-match-case-examples"&gt;GUICommits&lt;/a&gt; website that could simplify pattern matching with sequences.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;baskets = [
    ["apple", "pear", "banana"], 
    ["chocolate", "strawberry"], 
    ["chocolate", "banana"], 
    ["chocolate", "pineapple"], 
    ["apple", "pear", "banana", "chocolate"],
]
match basket:

    # Matches any 3 items
    case [i1, i2, i3]: 
        print(f"Wow, your basket is full with: '{i1}', '{i2}' and '{i3}'")
    # Matches &amp;gt;= 4 items
    case [_, _, _, *_] as basket_items:
        print(f"Wow, your basket has so many items: {len(basket_items)}")

    # 2 items. First should be chocolate, second should be strawberry or banana
    case ["chocolate", "strawberry" | "banana"]:
        print("This is a superb combination")

    # Any amount of items starting with chocolate
    case ["chocolate", *_]:
        print("I don't know what you plan but it looks delicious")

    # If nothing matched before
    case _:
        print("Don't be cheap, buy something else")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing to point out, it’s that the &lt;code&gt;*_&lt;/code&gt; matches any number of items, without binding them to a variable. Using &lt;code&gt;*&lt;/code&gt; extra instead of &lt;code&gt;*_&lt;/code&gt; would bind the items to extra as a list with 0 or more items.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time to Slice them Up
&lt;/h2&gt;

&lt;p&gt;A common feature of list, tuple, str, and all sequence types in Python is the support of slicing operations.&lt;/p&gt;

&lt;p&gt;We slice a list like this: &lt;code&gt;seq[start, stop, step]&lt;/code&gt;, step is the number of items to skip. To evaluate the expression &lt;code&gt;seq[start:stop:step]&lt;/code&gt;, Python calls The Special Method &lt;code&gt;seq.getitem(slice(start, stop, step))&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# On a list
l = [10, 20, 30, 40, 50, 60]
l[:2] # [10, 20]
l[2:] # [30, 40, 50, 60]
l[:3] # [10, 20, 30]

# On a str
s = 'bicycle'
s[::3] # 'bye'
s[::-1] # 'elcycib'
s[::-2] # 'eccb'

# Add, Mul, Del, assign operations on slices
l = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l[2:5] = [20, 30] # [0, 1, 20, 30, 5, 6, 7, 8, 9]
del l[5:7] # [0, 1, 20, 30, 5, 8, 9]

print(5 * 'abcd') # 'abcdabcdabcdabcdabcd'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are different uses for different types of sequences, and depending on your use case, there are better options. Arrays, Memory views and Double ended queues are prime examples of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory Views
&lt;/h2&gt;

&lt;p&gt;The built-in memoryview class is a shared-memory sequence type that lets you handle slices of arrays without copying bytes. Using notation similar to the array module, the memoryview.cast method lets you change the way multiple bytes are read or written as units without moving bits around.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;memoryview.cast&lt;/code&gt; returns yet another &lt;code&gt;memoryview&lt;/code&gt; object, always sharing the same memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;octets = array('B', range(6)) # array of 6 bytes (typecode 'B')

m1 = memoryview(octets)
m1.tolist() # [0, 1, 2, 3, 4, 5]

m2 = m1.cast('B', [2, 3])
m2.tolist() # [[0, 1, 2], [3, 4, 5]]

m3 = m1.cast('B', [3, 2])
m3.tolist() # [[0, 1], [2, 3], [4, 5]]

m2[1,1] = 22
m3[1,1] = 33
print(octets) # array('B', [0, 1, 2, 33, 22, 5])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Python's Data Model, what to keep in mind when I'm coding?</title>
      <dc:creator>Nadim Jendoubi</dc:creator>
      <pubDate>Mon, 24 Apr 2023 12:33:31 +0000</pubDate>
      <link>https://dev.to/algoryst/pythons-data-model-what-to-keep-in-mind-when-im-coding-326g</link>
      <guid>https://dev.to/algoryst/pythons-data-model-what-to-keep-in-mind-when-im-coding-326g</guid>
      <description>&lt;p&gt;Python is such an easy language to learn but a very difficult one to master, one of the basics of the language is the Data Model.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is it and when do I use it?
&lt;/h2&gt;

&lt;p&gt;The Data Model is a set of interfaces that formalizes the building blocks of the Python language itself, such as sequences, functions, iterators, coroutines and so on. It is used all the time as you cannot write relevant Pythonic code without it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use it?
&lt;/h2&gt;

&lt;p&gt;The short answer is we implement the methods in these interfaces.&lt;/p&gt;

&lt;p&gt;When we want our objects to support and interact with fundamental language constructs like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collections&lt;/li&gt;
&lt;li&gt;Iteration&lt;/li&gt;
&lt;li&gt;Operator overloading&lt;/li&gt;
&lt;li&gt;Asynchronous programming and managed contexts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Special Methods
&lt;/h2&gt;

&lt;p&gt;You probably came across this method &lt;code&gt;__init__&lt;/code&gt; and others written with leading and trailing double underscores, this is a &lt;strong&gt;Special Method&lt;/strong&gt; serving as a Constructor for your Object.&lt;/p&gt;

&lt;p&gt;Special Methods are meant to be called by the Python Interpreter and not by us, we just implement them if needed and we use the syntactic sugar offered to us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var = 'hello'
var2 = ' world'

# this is how we should write
print(var + var2)         # hello world

# this is not how we should write, meant to be called by Python Interpreter
print(var.__add__(var2))  # hello world

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Python object should provide usable string representations of itself, one used for debugging and logging, and another for presentation to end users. These Special Methods are &lt;code&gt;__repr__&lt;/code&gt; and &lt;code&gt;__str__&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Point:

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

    def __str__(self):
        # Default implementation, to change depending on user needs
        return self.__repr__()


&amp;gt;&amp;gt;&amp;gt; p = Point(1, 2)
&amp;gt;&amp;gt;&amp;gt; p
Point(1, 2)
&amp;gt;&amp;gt;&amp;gt; p.x = 4
&amp;gt;&amp;gt;&amp;gt; p
Point(4, 2)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are more than 100 Special Methods, most of which implement Arithmetic, Bitwise, and Comparison Operators. Here’s a &lt;a href="https://docs.python.org/3/reference/datamodel.html#special-method-names"&gt;link&lt;/a&gt; to the full list.&lt;/p&gt;

&lt;p&gt;By implementing Special Methods, your objects can behave like the built-in types, enabling the expressive coding style the community considers Pythonic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Collections ABCs
&lt;/h2&gt;

&lt;p&gt;The Collection API is an Integral Module of the Python Data Model, this API offers us interfaces for these types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sequence, formalizing the interface of built-ins like &lt;code&gt;list&lt;/code&gt;and &lt;code&gt;str&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Mapping, implemented by &lt;code&gt;dict&lt;/code&gt;, &lt;code&gt;collections.defaultdict&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Set, the interface of the &lt;code&gt;set&lt;/code&gt;and &lt;code&gt;frozenset&lt;/code&gt; built-in types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N-087n-D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q44b59q0i5jqitvhi1z2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N-087n-D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q44b59q0i5jqitvhi1z2.png" alt="UML class diagram with fundamental collection types. Method names in italic are abstract, so they must be implemented by concrete subclasses such as list and dict" width="592" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the classes in the diagram are ABCs or Abstract Base Classes. Each of the top ABCs has a single special method. The Collection ABC unifies the three essential interfaces that every collection should implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Iterable&lt;/code&gt;to support &lt;code&gt;for&lt;/code&gt;, unpacking, and other forms of iteration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sized&lt;/code&gt;to support the &lt;code&gt;len&lt;/code&gt;built-in function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Container&lt;/code&gt;to support the &lt;code&gt;in&lt;/code&gt;operator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep in mind that it is not required to inherit from any of these ABCs, for example, any class that implements &lt;code&gt;len&lt;/code&gt; satisfies the &lt;code&gt;Sized&lt;/code&gt; interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;For a more detailed explanation regarding this article, you can head to the full article on my &lt;a href="https://www.algorystcorner.com/python-data-model/"&gt;Blog &lt;/a&gt;where you will find a list of other helpful resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The full article on my &lt;a href="https://www.algorystcorner.com/python-data-model/"&gt;Blog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The “Data Model” chapter of &lt;a href="https://amzn.to/3HEVa7B"&gt;The Python Language Reference&lt;/a&gt; is the canonical source for the subject of this chapter and much of this book.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://amzn.to/3HcGcE9"&gt;Python in a Nutshell, 3rd ed&lt;/a&gt;. by Alex Martelli, Anna Ravenscroft, and Steve Holden (O’Reilly) has excellent coverage of the data model.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://amzn.to/3wFlesR"&gt;Python Essential Reference&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://amzn.to/3wFloQZ"&gt;Python Cook‐ book, 3rd ed&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://amzn.to/3JEwH3J"&gt;The Art of the Metaobject Protocol&lt;/a&gt;, explains the concept of a metaobject protocol, of which the Python Data Model is one example.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
