![](https://i.imgur.com/skB4mgG.jpg) > Photo by <a href="https://unsplash.com/@stellacaraman?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Stella Caraman</a> on <a href="https://unsplash.com/s/photos/frozen-set?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a> # **Sets vs Frozensets** 🥶 ## What is set? ```python= st = 'python' print(set(st)) ``` > {'h', 'n', 'o', 't', 'y', 'p'} from the first look we can say that, `sets` doesn't keep the order of the original string ```python= new_list = ['python', 'go', 'ruby'] print(set(new_list)) ``` > {'ruby', 'python', 'go'} let's now write a tuple which exists same objects and then convert it to set ```python= cities = ("Paris", "Lyon", "London","Berlin","Paris","Birmingham") print(set(cities)) ``` > {'Birmingham', 'Lyon', 'Paris', 'Berlin', 'London'} So as we can see the duplicate object "Paris" has been reduced to only one. Interesting isn't it 🧐 ### sets cannot contain mutable objects. Python objects (booleans, integers, floats, strings, tuples) are immutable. Which means after you create the object and assign some value to it, you can’t modify that value. here, we are assigning a = 1 which is binding to a reference in memory but when we're changing the value to a = 2, it is referencing to another memory address. The old reference still exists in memory, but the binding is lost. The original object with value 1 still exists in memory but we cannot access it through the varible anymore. ![](https://i.imgur.com/y2DYkdz.png) ### Now we will be needed garbage collection. # how python automatically manages memory? ```python= import platform print(platform.python_implementation()) ``` > CPython `CPython` is the reference implementation of the Python programming language. Written in C and Python. CPython can be defined as both an interpreter and a compiler as it compiles Python code into bytecode before interpreting it. There are two ways to memory management and garbage collection in CPython: - Reference counting - Generational garbage collection At a very basic level, a Python object’s reference count is incremented whenever the object is referenced, and it’s decremented when an object is dereferenced. If an object’s reference count is 0, the memory for the object is deallocated. ```python= import sys a = 'hello world' print(sys.getrefcount(a)) b = [a] print(sys.getrefcount(a)) c = {'hello': a} print(sys.getrefcount(a)) ``` > 3 > 4 > 5 as we can see the reference count is increasing, we'll talk about more on this in the upcoming story, for now this will pique your interest [link]('https://www.quora.com/Why-doesnt-Apple-Swift-adopt-the-memory-management-method-of-garbage-collection-like-Java-uses#__w2_wTLUJRu99_answer'). #### Immutable datatypes in python Numbers (Integer, Rational, Float, Decimal, Complex & Booleans) Strings Tuples Frozen Sets ### A mutable object is an object whose value can change once created. Mutable objects are often objects that can store a collection of data. for example `Lists`, `Sets`, `Dictionaries` are mutable datatypes. ## Though sets cannot contain mutable objetcs, sets are mutable ```python= s1 = set(['paris', 'ibiza']) s1.add('melbourne') print(s1) ``` > {'ibiza', 'melbourne', 'paris'} # Frozensets are like sets except they are immutable ```python= fs = frozenset(["Frankfurt", "Basel","Freiburg"]) print(fs) ``` > frozenset({'Freiburg', 'Basel', 'Frankfurt'}) now if we try to add another city, it'll throw error we can define set without `set()` keyword ```python= cities = {"Winterthur","Schaffhausen","St. Gallen"} print(cities) cities_backup = cities.copy() print(cities_backup) ``` > {'St. Gallen', 'Winterthur', 'Schaffhausen'} > {'St. Gallen', 'Winterthur', 'Schaffhausen'} let's learn shallow `copy()` ```python= cities.clear() print(cities) print(cities_backup) ``` > set() {'St. Gallen', 'Winterthur', 'Schaffhausen'} The assignment "cities_backup = cities" copies the reference of the cities to the cities_backup object