Python – Why do both underscores and ‘normal’ variables appear in the dir() list?

Why do both underscores and ‘normal’ variables appear in the dir() list?… here is a solution to the problem.

Why do both underscores and ‘normal’ variables appear in the dir() list?

I’m looking at the Python encryption example (PyCriptodome).

>>> from Crypto.Hash import SHA256
>>> from Crypto.PublicKey import RSA
>>> from Crypto import Random

>>> keyPair = RSA.generate(1024, rg)
>>>  keyPair
RsaKey(n= 1369654035622035560087561720183078545969410506233191282082981412707535596417568809135795152527813181346050785907969653805738909099789733074847188152632060683963390400125301877382209170326172191918042419943741 61791078493422872990621865765998883789114504025315394014914290915546672772138647618404548805335792391, e=65537,  d= 1263341111942140311691000594855838657610981050426421914367704142670102793894167180558445106890860228761901979158899027611225980058322617214314242699949769659516429485209749757044802512732906340109215474520371 4692627489061877805907641329178852991389621069959872155452247708311950473622509963157700897012362793,  p=11087589806690192188252790347967677991722451309799179019881614471199138924752612698172266069109676252679178194446946306621193937032594190841131089738727723,  q=12353036678860482962550037314677881356813045811345498557987093840147921697669238214163344188705969863296242048445184466718647041921862285219953085737805717,  u=5930058794668004042843071106296071655835828106941133612195152599264918158827791715007378423398034795364513716281393195005242480751038879143818105780545780)

Next steps

dir(keyPair)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_ subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__ weakref__', '_d', '_decrypt', '_e', '_encrypt', '_n', '_p', '_q', '_u', 'blind', 'can_encrypt', 'can_sign', 'd', 'decrypt', 'e', 'encrypt', 'exportKey', 'export_key', 'has_private', 'n' , 'p', 'publickey', 'q', 'sign', 'size', 'size_in_bits', 'size_in_bytes', 'u', 'unblind', 'verify']

In my previous work, I learned that no parameter dir() returns a list of valid properties.

Why do I have both “_d” and “d”?

Solution

Because _d and d are valid (and different from each other), with or without underscores.

_d uses a naming convention that prevents you from using it from outside the class (inherited classes may have exceptions), but it is still valid and visible.

In this simple example:

class A:
    def __foo(self):
        pass
    def _bar(self):
        pass
    def bar(self):
        pass

a = A()
print(dir(a))

You get:

['_A__foo', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__ ', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bar', 'bar']

Pay attention to what you get

    All “double

  • underscore methods” (double underscore prefix and suffix methods for special operations).
  • _bar as it is
  • bar as is
  • Even __foo but name mangled is _A__foo (like all non-dunder double-underscore prefix attributes).

Read also What is the meaning of a single- and a double-underscore before an object name?

Related Problems and Solutions