Package: lockattrs
Locking Class AttributesMost object oriented languages (C++, Java, Dart, Kotlin, Swift)
include visibiliy modifiers. This enables
encapsulation where for example the inner workings of a class
can be detached from the outside world and thus protected from
direct modification.Python on the other hand does not have a language-backed concept
of privacy. Instead functions or variables with an identifier
that starts with an underscore are
deemed private and should not be modified or otherwise
relied upon since they may change in a future version of the module.In some cases, certain attributes may be crucial for the
correct working a class and the programmer might
want to pervent any inadvertent modification.The packagelockattrsprovides a decorator that can
be used with the method__setattr__to lock certain attributes
or all attributes.Note that despite the name similaritylockattrsis
not related to the packageattrsproviding
a concise way of creating and validating data classes.InstallationTo install the packagelockattrsuse the command:$pipinstalllockattrsUsageThis package provides the decorator functionprotectwhich can be
used to prevent modification of attributes
after they have been initially set.1. Locking Class AttributesThe intended use-case is demonstrated below. Locking the
instance attributes of a meta-class is equivalent to
locking the class attributes of the class (the meta-class instance).Using the decoratorprotectinvolves the following steps:Declare a meta-class.Override the method__setattr__.Decorate__setattr__with the functionprotect.Optionally: Specify which attributes should be locked and
what type of error should be raised during an attribute
modification attempt.fromlockattrsimportprotectclassAMeta(type):"""Meta class of A."""@protect(('data','id'),)def__setattr__(self,name:str,value:Any)->None:returnsuper().__setattr__(name,value)classA(metaclass=AMeta):id='a01'passA.id='b02'# Raises an error. Attribute 'id' is set and locked.A.data='initial-data'# First initiation is OK. Attribute 'data' is now locked.A.data='new-data'# Raises an error (default type: ProtectedAttributeError).A.name='A'A.name='A1'# OK, since the attribute 'name' is not locked.2. Locking Instance AttributesThe code below demonstrates how to use the decorator
function@protectto lock certain attributes of a class instance.fromlockattrsimportprotectclassB():"""Sample class with locked attributes."""id=57@protect(('data','id'),)# To lock all attributes use: @protect()def__setattr__(self,name:str,value:Any)->None:returnsuper().__setattr__(name,value)B.id=28# OK. Class attributes are not locked.# To lock class attributes see section above.# Creating an instance of B.b=B()b.id=77# Modification of the attribute 'id' via 'self' raises# an error since the annotated method `__setattr__` is# called.b.data='initial-data'# First initiation is OK. Attribute 'data' is now locked.b.data='new-data'# Raises an error (default type: ProtectedAttributeError).b.name='b'b.name='b1'# OK, since the attribute 'name' is not locked.PerformanceNote: Locking certain attributes may be prohibitively
costly in terms of computational time
when used with objects that are
instantiated often (for example in a loop)
and where attributes are set/modified frequently.The benchmarks below were produced using the packagepytest-benchmarkon a PC with 32GB RAM
and an Intel Core i5-6260U CPU running at 1.80GHz.
As the mean runtimes show, setting an attribute of classAtakes approximately 40 times as long compared to a standard class
(without an annotated__setattr__method).--------------------------------- benchmark: 2 tests -----------------------------------Name (time in ns)                   Mean              StdDev          Rounds  Iterations----------------------------------------------------------------------------------------test_benchmark_set_attrs        348.8611 (1.0)       66.8829 (1.0)         4       20000test_benchmark_set_attrs_A   13,496.0524 (38.69)    912.2178 (13.64)       4       20000----------------------------------------------------------------------------------------Features and bugsPlease file feature requests and bugs at theissue tracker.
Contributions are welcome.