Skip to main content

Locking Class Attributes

tests docs

Most 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 package lockattrs provides a decorator that can be used with the method __setattr__ to lock certain attributes or all attributes.

Note that despite the name similarity lockattrs is not related to the package attrs providing a concise way of creating and validating data classes.

Installation

To install the package lockattrs use the command:

$ pip install lockattrs

Usage

This package provides the decorator function protect which can be used to prevent modification of attributes after they have been initially set.

1. Locking Class Attributes

The 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 decorator protect involves the following steps:

  1. Declare a meta-class.
  2. Override the method __setattr__.
  3. Decorate __setattr__ with the function protect.
  4. Optionally: Specify which attributes should be locked and what type of error should be raised during an attribute modification attempt.
from lockattrs import protect

class AMeta(type):
    """
    Meta class of A.
    """
    @protect(('data','id'), )
    def __setattr__(self, name: str, value: Any) -> None:
        return super().__setattr__(name, value)

class A(metaclass=AMeta):
    id = 'a01'
    pass

A.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 Attributes

The code below demonstrates how to use the decorator function @protect to lock certain attributes of a class instance.

from lockattrs import protect

class B():
    """
    Sample class with locked attributes.
    """
    id = 57

    @protect(('data','id'), ) # To lock all attributes use: @protect()
    def __setattr__(self, name: str, value: Any) -> None:
        return super().__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.

Performance

Note: 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 package pytest-benchmark on 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 class A takes 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       20000
test_benchmark_set_attrs_A   13,496.0524 (38.69)    912.2178 (13.64)       4       20000
----------------------------------------------------------------------------------------

Features and bugs

Please file feature requests and bugs at the issue tracker. Contributions are welcome.

Release files for lockattrs 0.0.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lockattrs 0.0.5
File Size Uploaded
lockattrs-0.0.5.tar.gz 5.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lockattrs 0.0.5
File Interpreter ABI Platform
lockattrs-0.0.5-py3-none-any.whl Python 3 none any Details

Total release size: 11.3 kB

Release files / lockattrs-0.0.5.tar.gz

Download URL lockattrs-0.0.5.tar.gz
Size 5.8 kB
Tags Source
SHA-256 checksum
How to use checksums
bc5c593543c91da16c1a1feb71022c22b17458cb6c44a1f0451cc73c5cbfd68c
BLAKE2b-256 checksum
How to use checksums
e24df06e2e82c2dd7b71b8e09882d6a53a4807798e386a3e519d42dfc59e3caf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.7.0 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

Release files / lockattrs-0.0.5-py3-none-any.whl

Download URL lockattrs-0.0.5-py3-none-any.whl
Size 5.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1fb38ade9146cc4f131ed12674c1718d272a51cefe8b7eb4354c869c81d5c625
BLAKE2b-256 checksum
How to use checksums
1c32b8f5119be839d2c1e141407eb574ed6e6cad5797530f7b60dc7327088871
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.7.0 importlib_metadata/4.8.2 pkginfo/1.8.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

Release history Release notifications | RSS feed

This release

0.0.5 This release

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page