Three things that make an object
Identity:
each object is unique, with an identity. To retrieve the identity, pass it to the id() function. Compare using the is operator. Merely the location in memory. Nothing (type or value) knows anything about identity.
Type:
Defined by an objects class and base classes that support it. Shared among all instances. Each object just contains a reference to its class
Value:
makes it distinct among its peers. Provided by the namespace dictionary, specific to object. Designed to work with type and do useful things.
Borg pattern
class Borg:
__ _namespace = {}
__ def __init__(self):
____self.__dict__ = Borg._namespace
____# do interesting stuff.
a = Borg()
b = Borg()
hasattr(a, ‘attribute’) ## False
b.attribute = ‘value’
hasattr(a, ‘attribute’) ## Now True, it’s “value”
Borg._namespace
{“attribute” : “value”}
________________________
Problems:
inheritance won’t work unless you call super() BEFORE any other work on subclasses. Otherwise they’d get overwritten
check notebook for more examples.
Garbage Collection
Python counts the number of references to an object, when it gets to zero, it is available for garbage collection.
so
>>> a = [1,2,3]
>>> b = a
>>> del a # a no longer exists, but…
>>> b
…[1,2,3]
deleting b makes the list available for gc.
Cyclical references
b = {}
b[‘example’] = [1,2,3]
b[‘example’].append(b) ## circular ref
the dictionary’s reference count is two
one from b, one from the list in b
del b # the dict’s reference is 1, it can’t be collected
likewise, the dict references the list, which also can’t be collected.
Python can recognize these references. It flags them.
Python doesn’t know which to delete first, though.
The extra work in programming requires more explicit. reliable behavior
Pickling
done with:
pickle.dump(any_object, file_like_object)
file must be open as write-binary
and pickle.dumps(any_object)
when pickling an object, it is recommended to have __setstate__ and __getstate__ dunder methods.
__getstate__ is called when pickling and limits the amount of stuff you need to save.
__setstate__ is what is executed when unpickling.
any attributes attached to methods should be redeclared here, because __init__ is not called. Basically, any setup stuff that doesn’t have to do with saving actual data.
copying
or
Mutable objects have a drawback.
Changes to an object are visible by all things pointing to it.
copying lists
a = [1,2,3]
b = list(copy(a))
b = a[:]
a = {1:2, 3:4}
b = a.copy()
1.
Shallow v. Deep Copies
copying arbitrary objects with copy
You can define a __copy__() method to specifiy which get copied and how
Deepcopy