__dict__
is not a method - is an attribute - and is the way implemented, officially, in the language of storing instance attributes in objects.
It is a common dictionary, and you can use any code that would operate in a common dictionary with the __dict__
one-instance.
Your use to directly access the attributes content of the instance is not encouraged - even if it has no side effects. As a rule, you can say: if you don’t need it, don’t use it directly .__dict__
. (There are other ways to store attribute values in instances - and how this is done can be customized with the use of property
or by implementing __setattr__
and __getattribute__
or with the use of __slots__
, for example.
Now, your example has another thing that draws attention - is the use of the two __
to prefix your attributes.
Rather older Python material (and perhaps some more recent material from those who have studied this ancient material), usually says that "using two '__' is the Python equivalent of having a private attribute, as it exists in other object-oriented languages". That statement, or variations of it, are essentially wrong.
The use of two __
It does fire an automatic rename effect of attributes and methods, but that most likely will cause you problems than help you. Python simply does not have the concept of private attributes supported by language itself - what exists is the convention that attributes and methods begin with a single _
are private, in the sense that they should not be used except for the same project that implements the class (and not for other projects that make use of that class).
In other words: the use of __
for "private attributes" is more a functionality created by someone who missed private things for more than 25 years, and ended up in a dead end that is hardly used in serious projects.
what the use of "__" does: (I write more below to not stay before more important things)
I suggest heavily that you aggregate more language learning sources and don’t try to artificially use private attributes until you understand well how language works.
Customizing the representation of a class
That said, I recommend you focus on really cool language features and features - for example, if you
create the special method __repr__
he will be called to convert the
instances of your class for a string for viewing purposes.
In your case, it could be so:
class Pessoa:
def __init__(self, nome, idade, altura):
"""Método construtor da classe Pessoa"""
self.nome = nome
self.idade = idade
self.altura = altura
def __repr__(self):
return f"Pessoa(nome={self.nome}, idade={self.idade}, altura={self.altura})"
With that, simply print(pessoa)
will give a very readable output, as the Voce wants.
If you don’t want to keep repeating this for each class and each attribute, you can create a base class with these features - something like:
class AutoAttributes:
attrs = ()
def __init__(self, **kwargs):
"""Método construtor genérico"""
for attr in self.attrs:
if attr in kwargs:
setattr(attr, kwargs[attr])
def __repr__(self):
body = [f"{attr}={getattr(self, attr, None)}" for attr in self.attrs]
return f"{self.__class__.__name__}({', '.join(body)})"
class Pessoa(AutoAttributes):
attrs = ['nome', 'idade', 'altura']
And then yes, you’ll be studying Python, and the good parts of object orientation - seeing how "inheritance" helps.
But after learning and understanding, Python 3.7 add a feature that does what I do in the Base class above, and goes well beyond, with several other facilities for automatic attributes - see the module documentation dataclasses
(exists only from Python 3.7)
What "__" really does:
(remembering: as much as it is a "legal" mechanism, I do not personally recommend its use)
This triggers a "name mangling" mechanism that is "name mess" of attributes and methods. This is a mechanism that happens at compile time of the file ". py" (yes, Python is compiled for a special bytecode, just like Java and C# - only this happens in a transparent step for all users. In Java and C# it is necessary to call an explicit compilation step, which nowadays is hidden by Ides that do everything automatically). The purpose of emulating private attributes with this "name mangling" has never been to "not allow users outside the class to access attributes" - as it is taught briefly in O.O. classes - this gives no security for any code - is only so that an intermediate layer of a complex class hierarchy can have attributes that will not be over-written unintentionally by subclasses who inherit the same.
Let’s say I have a really big project, and in the middle, I have a class that has a validation layer with a method validate
which will validate the connection to the database available to the instance. At another point in the class hierarchy, I’ll have another class to use, which will have a method validate
to validate the same attributes (let’s assume that there were to check rules for the attributes "name", "age" of your person). In a single project, with non-cooperative methods, the validate
of this other subclass would overlap with the first validate
that would never be called. If the convention in that project would always use the __
, then the method would have the real name of _NetworkMixin__validate
and the other could have ended up with the name of _AttributeMixn_validate
and the two methods could be called independently.
In practice, it was noted that it is preferable (1) not to have hierarchies of such complex classes, with hundreds of methods competing with each other within the same object - and yes, simpler and generic objects that can be passed as parameters to others who do things as distinct as "validate the network connection". (2) using collaborative inheritance always using the super()
to call the methods of all superclasses - all methods that have the same name are called if this is well done.
Got, reading the dictionary and printing the way you want.
– Maniero
Wouldn’t it be better to use the method
__str__
than using the dictionary with__dict__
?– AlexCiuffa