Back to Blog
Python

Python Public Attribute: Definition and Access Control

python public attribute: Understand Python public attributes, naming conventions, and how to use properties to control attribute access in your classes.

python attributespropertiesencapsulationobject-oriented programmingaccess control
Illustration of a Python class with public attributes and property access, showing a lock icon for private attributes.

python public attribute requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

In Python, a public attribute is an instance or class attribute that is intended to be accessed directly from outside the class. Unlike Java or C++, Python does not enforce access modifiers. Every attribute is public by default; the underscore conventions are advisory. This article explains how to define public attributes, how to use properties to control access, and the practical tradeoffs involved.

Default Visibility: Everything Is Public

Python has no public, private, or protected keywords. When you define an attribute in a class, it is immediately accessible from anywhere. For example:

class User: def __init__(self, name): self.name = name # public attribute user = User("Alice") print(user.name) # direct access works

Here, name is a public attribute. There is no compile-time check that prevents external code from reading or writing it. This simplicity is intentional: Python relies on developer discipline and conventions rather than language-enforced barriers.

Defining Public Attributes in a Class

Public attributes can be instance-level or class-level. Instance attributes are typically set in __init__ and are unique to each object. Class attributes are shared across all instances.

class Counter: count = 0 # class-level public attribute def __init__(self): self.increments = [] # instance-level public attribute

Accessing Counter.count returns the shared value, while counter.increments is a separate list for each instance. Both are public. The choice between them depends on whether the data should be shared or per-instance.

Naming Conventions: Underscore Prefixes

Python uses underscore prefixes to signal intent, not to enforce access. A single leading underscore, such as _rate, indicates that the attribute is internal to the class or module. It is still a public attribute in the sense that it can be accessed directly, but the underscore tells other developers to treat it as an implementation detail.

class BankAccount: def __init__(self, balance): self.balance = balance # public self._rate = 0.05 # internal, but still accessible

A double leading underscore triggers name mangling, which makes the attribute harder to accidentally access from outside the class, but it is not true privacy. For example, self.__secret becomes _ClassName__secret at runtime. This is a mechanism to avoid accidental overrides in subclasses, not a security boundary.

When to Use Properties Instead of Plain Attributes

Plain public attributes are fine when you simply store data. But if you need validation, computed values, or a read-only interface, a property is a better fit. Properties allow you to expose a public attribute name while controlling how it is read and written.

class Temperature: def __init__(self, celsius): self._celsius = celsius @property def celsius(self): return self._celsius @celsius.setter def celsius(self, value): if value < -273.15: raise ValueError("Temperature below absolute zero") self._celsius = value

Here, celsius is a public attribute from the caller's perspective. The underlying _celsius is private by convention. The property ensures that invalid values are rejected.

How Properties Change Attribute Access

When you use @property, you create a descriptor object. Accessing obj.celsius invokes the getter method, and assigning obj.celsius = 20 invokes the setter. This is fundamentally different from a plain attribute, which stores a value directly in the instance dictionary.

The public attribute name is the property itself, not the underlying _celsius. This means you can start with a plain attribute and later replace it with a property without changing the external interface, as long as you keep the same name. This backward compatibility is one of the main reasons to use properties for evolving APIs.

Public Attributes and Encapsulation: Tradeoffs

Making every attribute public can lead to tight coupling between classes. If external code directly modifies an attribute, changing the internal representation later becomes difficult. Properties mitigate this by providing a controlled access point, but they add boilerplate.

A reasonable rule is to use a plain public attribute for simple data that is unlikely to change. Use a property when you need to enforce invariants, compute values on the fly, or hide a different internal representation. For example, a Rectangle class might expose width and height as plain attributes, but area as a property because it is derived.

Runtime Cost of Properties

Properties introduce a method call on every access. In Python, this overhead is small but not zero. In performance-critical loops, repeated property access can be measurably slower than direct attribute access. If you are profiling and find that property access is a bottleneck, consider reading the underlying attribute directly or caching the computed value.

However, the cost is usually negligible compared to the maintainability benefit. Do not avoid properties for performance reasons unless you have evidence that they matter in a specific hot path.

Choosing Between Plain Attributes and Properties

The decision comes down to whether the attribute is a simple data holder or requires logic. Use a plain public attribute when:

  • The value is stored and retrieved without transformation.
  • No validation is required.
  • The attribute is unlikely to change in the future.

Use a property when:

  • You need to validate input.
  • The value is computed from other attributes.
  • You want to provide a read-only interface.
  • You expect to change the internal implementation later.

In practice, many classes start with plain attributes and migrate to properties as requirements evolve. Because Python's property mechanism preserves the attribute name, this migration is straightforward and does not break existing callers.

python public attribute: Practical Usage and Code Examples | RYUSLOG DEV