Skip to content

Attributes

Overview

privates.py will look for the __private__, __protected__, __readonly__ attributes on a supported type (more on that in a moment). Each of these must be any iterable of strings, but in these examples it will be done with a tuple.

A supported type is something that privates.py has hooked on to. This is done automatically by the private and class_modifier decorators, but if you don't want to limit instantiation of your class, then you may support access-modified attributes with the supports_private decorator:

from privates import supports_private

@supports_private
class ClassWithPrivateAttributes:
    ...

Private

Private attributes may be accessed in methods of the class only. You generally don't want to set the __private__ attribute manually, but instead just prefix your attribute with _:

from privates import supports_private

@supports_private
class Foo:
    def __init__(self) -> None:
        self._bar = "hello world"

    def print_bar(self) -> None:
        print(self._bar)

foo = Foo()
foo._bar  # AccessError

Protected

Protected attributes may be accessed in methods of the class, and by methods of any classes that inherit from it. You must explicitly define the __protected__ attribute for these. Note that you do not need to use the @supports_private decorator on the child class:

from privates import supports_private

@supports_private
class Foo:
    __protected__ = "bar",

    def __init__(self) -> None:
        self.bar = "hello world"

    def print_bar(self) -> None:
        print(self.bar)

class Bar(Foo):
    def __init__(self) -> None:
        super().__init__()
        self.bar = "hello, world!"

bar = Bar()
bar.print_bar()

Read Only

Read only attributes may accessed anywhere, but only written to by methods of the class (or by any classes that inherit from it). Once again, __readonly__ must be defined:

from privates import supports_private

@supports_private
class Foo:
    __readonly__ = "bar",

    def __init__(self) -> None:
        self.bar = "hello world"

foo = Foo()
print(foo.bar)
foo.bar = "hello, world!"  # AccessError

Friends

Similar to how friends work with private, class_modifier, and function_modifier, you may give a function or type private access with the friend decorator:

from privates import supports_private

@supports_private
class Foo:
    def __init__(self) -> None:
        self._bar = "hello world"

@friend(Foo)
def use_foo():
    foo = Foo()
    print(foo._bar)

use_foo()

You might be wondering, "don't you have to be more than friends to touch privates?" Hey, I don't make the rules, I only follow them!