> Not to be confused with [_decorator classes_](#decorator-classes)!
> Not to be confused with [_decorator classes_](#decorator-classes)!
In this practical, we have shown how decorators can be applied to functions
In this practical, we have shown how decorators can be applied to functions
and methods. But decorators can in fact also be applied to _classes_. This is
and methods. But decorators can in fact also be applied to _classes_. This is
a fairly niche feature that you are probably not likely to need, so we will
a fairly niche feature that you are probably not likely to need, so we will
only cover it briefly.
only cover it briefly.
Imagine that we want all objects in our application to have a globally unique
Imagine that we want all objects in our application to have a globally unique
(within the application) identifier. We could use a decorator which contains
(within the application) identifier. We could use a decorator which contains
the logic for generating unique IDs, and defines the interface that we can
the logic for generating unique IDs, and defines the interface that we can
use on an instance to obtain its ID:
use on an instance to obtain its ID:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
import random
import random
allIds = set()
allIds = set()
def uniqueID(cls):
def uniqueID(cls):
class subclass(cls):
class subclass(cls):
def getUniqueID(self):
def getUniqueID(self):
uid = getattr(self, '_uid', None)
uid = getattr(self, '_uid', None)
if uid is not None:
if uid is not None:
return uid
return uid
while uid is None or uid in set():
while uid is None or uid in set():
uid = random.randint(1, 100)
uid = random.randint(1, 100)
self._uid = uid
self._uid = uid
return uid
return uid
return subclass
return subclass
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Now we can use the `@uniqueID` decorator on any class that we need to
Now we can use the `@uniqueID` decorator on any class that we need to
have a unique ID:
have a unique ID:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
@uniqueID
@uniqueID
class Foo(object):
class Foo(object):
pass
pass
@uniqueID
@uniqueID
class Bar(object):
class Bar(object):
pass
pass
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
All instances of these classes will have a `getUniqueID` method:
All instances of these classes will have a `getUniqueID` method:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
f1 = Foo()
f1 = Foo()
f2 = Foo()
f2 = Foo()
b1 = Bar()
b1 = Bar()
b2 = Bar()
b2 = Bar()
print('f1: ', f1.getUniqueID())
print('f1: ', f1.getUniqueID())
print('f2: ', f2.getUniqueID())
print('f2: ', f2.getUniqueID())
print('b1: ', b1.getUniqueID())
print('b1: ', b1.getUniqueID())
print('b2: ', b2.getUniqueID())
print('b2: ', b2.getUniqueID())
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
<aclass="anchor"id="useful-references"></a>
<aclass="anchor"id="useful-references"></a>
## Useful references
## Useful references
*[Understanding decorators in 12 easy steps](http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/)
*[Understanding decorators in 12 easy steps](http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/)
*[The decorators they won't tell you about](https://github.com/hchasestevens/hchasestevens.github.io/blob/master/notebooks/the-decorators-they-wont-tell-you-about.ipynb)
*[The decorators they won't tell you about](https://github.com/hchasestevens/hchasestevens.github.io/blob/master/notebooks/the-decorators-they-wont-tell-you-about.ipynb)
*[Closures - Wikipedia][wiki-closure]
*[Closures - Wikipedia][wiki-closure]
*[Closures in Python](https://www.geeksforgeeks.org/python-closures/)
*[Closures in Python](https://www.geeksforgeeks.org/python-closures/)
*[Garbage collection in Python](https://www.quora.com/How-does-garbage-collection-in-Python-work-What-are-the-pros-and-cons)
*[Garbage collection in Python](https://www.quora.com/How-does-garbage-collection-in-Python-work-What-are-the-pros-and-cons)