Product
Introducing License Enforcement in Socket
Ensure open-source compliance with Socket’s License Enforcement Beta. Set up your License Policy and secure your software!
Python is inherently mutable, only a handful of builtin classes enjoy true
immutability such as int
\ , str
\ , and tuple
\ ; everything else is up for
grabs. This allows a lot of clever tricks, but it also leads to some
difficult bugs. Just think about code like this:
.. code-block:: python
class MyClass:
def __init__(self) -> None:
self._mylist: List[str] = []
def get_mylist(self) -> List[str]:
return self._mylist
What happens when someone gets that list and mutates it? Of course, you get bugs because MyClass now has something it doesn't expect. The easiest way to fix that is of course to do this:
.. code-block:: python
class MyClass:
def __init__(self) -> None:
self._mylist: List[str] = []
def get_mylist(self) -> List[str]:
return self._mylist.copy()
Problem solved, right? What if _mylist has a million entires? That can quickly become a huge bottle neck in your program. In most statically typed languages you have some kind of "const" or "immutable" modifier that tells the compiler/interpreter "don't let anyone modify this". Normally that would be impossible in python, but we have static type checkers like mypy, and Protocols. We can create a protocol that implements all of the methods that don't mutate a class, and expose only those. Then the static type checker can catch the mutation for us.
.. code-block:: python
from constprotocol import ConstList
class MyClass:
def __init__(self) -> None:
self._mylist: List[str] = []
def get_mylist(self) -> ConstList[str]:
return self._mylist
c = MyClass() c.get_mylist().append('foo') # Error: ConstList has not method append!
Of course, the underlying python values have not actually become immutable, but like C and C++ it's more of a promise that if you take a ConstList or return one that you're not going to modify it.
One of the goals of const protocol is to have 0 runtime performance impact. You could create an immutable proxy, that wraps a value and only exposes it's const methods, and all of it's attributes as read only (using properties and more proxies). But that has runtime overhead and adds code complexity. This approach adds zero run time overhead and very little complexity to the code.
You don't.
No seriously, if you say you're not going to modify it, don't.
What you probably want to do is copy the constified value, which will give you a mutable value:
.. code-block:: python
l: ConstList[str] = ['a', 'b', 'c'] ml = l.copy() reveal_type(ml)
Which will be List[str]
If you really, really, need to, you can use typing.cast
. of course, you get
to keep the pieces.
Right now there are four classes ConstSet
for set
\ , ConstList
for
list
\ , ConstMapping
for mappings
\ , and ContDict
for Dict
. There's
likely bugs, this is alpha quality software, and a kind of crazy idea to get
better error checking in cases where the author knows that someone shouldn't
be mutating their data.
Cool, file an issue.
Even better, open a Merge Request
FAQs
Unknown package
We found that constprotocol demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Ensure open-source compliance with Socket’s License Enforcement Beta. Set up your License Policy and secure your software!
Product
We're launching a new set of license analysis and compliance features for analyzing, managing, and complying with licenses across a range of supported languages and ecosystems.
Product
We're excited to introduce Socket Optimize, a powerful CLI command to secure open source dependencies with tested, optimized package overrides.