Sphinx generates internal members of #dataclass - python

I have a python internal class that looks like this:
class TopClass:
#my_decorator
class InternalClass:
"""Persistent state."""
a: int
b: int
c: int
in this case my_decorator is a thin wrapper around #dataclass. Running sphinx however writes in the docs things like:
__dataclass_params__= _DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False, frozen=False)
__dict__= mappingproxy({'__module__': 'my_module.try', '__annotations__': {'a': 'int', 'b': 'int', 'c': 'int'}, '__doc__': 'Persistent state.', '__dict__': <attribute '__dict__' of 'InternalClass' objects>, '__weakref__': <attribute '__weakref__' of 'State' objects>, '__dataclass_params__': _DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False,frozen=False), '__dataclass_fields__': {'a': Field(name='a',type='int',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD), 'b': Field(name='b',type='int',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD), 'c': Field(name='c',type='int',default=<dataclasses._MISSING_TYPE object>,default_factory=<dataclasses._MISSING_TYPE object>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD)}, '__init__': <function __create_fn__.<locals>.__init__>, '__repr__': <function __create_fn__.<locals>.__repr__>, '__eq__': <function __create_fn__.<locals>.__eq__>, '__hash__': None})
__eq__(other)
Return self==value.
__hash__= None
__init__(a, b, c)
How can I avoid this?

Related

Equivalent implementation using f-strings and eval

x = type.__dict__
x is x
gives,
True
but,
x = type.__dict__
operator = 'is'
eval(f'{x} {operator} {x}')
gives,
SyntaxError: invalid syntax
even,
operator = 'is'
eval(f'{x!r} {operator} {x!r}')
gives,
SyntaxError: invalid syntax
how to get True as output using eval and f-strings?
When using eval you are executing exactly what you wrote in the string. By formatting with the curly brakets you are inserting in the string the value of "x", or at least whatever is returned by the "__str__" method of x.
print(f"{x}")
gives
{'__repr__': <slot wrapper '__repr__' of 'type' objects>, '__call__': <slot wrapper '__call__' of 'type' objects>, '__getattribute__': <slot wrapper '__getattribute__' of 'type' objects>, '__setattr__': <slot wrapper '__setattr__' of 'type' objects>, '__delattr__': <slot wrapper '__delattr__' of 'type' objects>, '__init__': <slot wrapper '__init__' of 'type' objects>, '__new__': <built-in method __new__ of type object at 0x908780>, 'mro': <method 'mro' of 'type' objects>, '__subclasses__': <method '__subclasses__' of 'type' objects>, '__prepare__': <method '__prepare__' of 'type' objects>, '__instancecheck__': <method '__instancecheck__' of 'type' objects>, '__subclasscheck__': <method '__subclasscheck__' of 'type' objects>, '__dir__': <method '__dir__' of 'type' objects>, '__sizeof__': <method '__sizeof__' of 'type' objects>, '__basicsize__': <member '__basicsize__' of 'type' objects>, '__itemsize__': <member '__itemsize__' of 'type' objects>, '__flags__': <member '__flags__' of 'type' objects>, '__weakrefoffset__': <member '__weakrefoffset__' of 'type' objects>, '__base__': <member '__base__' of 'type' objects>, '__dictoffset__': <member '__dictoffset__' of 'type' objects>, '__mro__': <member '__mro__' of 'type' objects>, '__name__': <attribute '__name__' of 'type' objects>, '__qualname__': <attribute '__qualname__' of 'type' objects>, '__bases__': <attribute '__bases__' of 'type' objects>, '__module__': <attribute '__module__' of 'type' objects>, '__abstractmethods__': <attribute '__abstractmethods__' of 'type' objects>, '__dict__': <attribute '__dict__' of 'type' objects>, '__doc__': <attribute '__doc__' of 'type' objects>, '__text_signature__': <attribute '__text_signature__' of 'type' objects>}
Meaning that's what you are trying to execute, which is indeed invalid syntax.
You should instead do:
eval("x is x")
Works for me:
>>> d = {"a":42}
{'a': 42}
>>> print(f"{d} is {d}")
{'a': 42} is {'a': 42}
>>> {'a': 42} is {'a': 42}
False
>>> eval(f"{d} is {d}")
False
This works just fine with dicts.
However, calling str.__dict__ returns something completely different than you'd probably expect:
>>> str.__dict__
mappingproxy({
'__new__': <built-in method __new__ of type object at 0x00007FFC55D1AC60>,
'__repr__': <slot wrapper '__repr__' of 'str' objects>,
--- snip for readability ---
This "dict-representation" is actually a MappingProxy as you can verify with type(str.__dict__) and cannot exactly be re-interpreted by eval() as <built-in method __new__... is obviously a syntax error, when used without quotes. You can easily verify this by pasting this into a Python interpreter:
>>> {"myKey": <built-in method __new__ of type object at 0x00007FFC55D1AC60>}
File "<stdin>", line 1
{"myKey": <built-in method __new__ of type object at 0x00007FFC55D1AC60>}
^
SyntaxError: invalid syntax
What you're trying to do requires not only type (whatever this might be at runtime) to have a dict-representation, but also every member to have one - recursively! This is hard to assume in a general case.
I'm convinced what you're trying to achieve can be done using a different way - if you want elaborate your task at hand, there might be a more suitable way.
If you insist on the eval() way, take a look at repr() and eval(), as generally, repr tries to produce a string, which can be fed into eval to produce the very same object again.
However, this is possible only, if the object implements repr to do exactly that - which is not guaranteed. There might be objects which cannot be serialized that way.
myDict = {"myKey": "myVal"}
myDict == eval(repr(myDict))
# Output: True
To get the same as x is x through eval you need the name of the variable as a string "x" instead of the variable itself. How to get it is answered here: Getting the name of a variable as a string
Here is a solution for your case:
x = type.__dict__
operator = 'is'
x_name = f'{x=}'.split('=')[0]
eval(f'{x_name} {operator} {x_name}')
Resulting in:
> True

Python : Using class variables incorrectly?

I have the following classes:
class A(object):
x = 1
class B(A):
pass
class C(A):
pass
When I print the value of x from each class I get:
>>>A.x, B.x, C.x
(1,1,1)
Then I assign 2 to B.x
B.x = 2
A.x, B.x, C.x
>>>(1,2,1)
Everything was normal but when I assigned 3 to A.x I got this :
A.x=3
A.x, B.x, C.x
>>>(3,2,3)
I thought it would return (3,2,1).
This is fundamentally how inheritance works in Python: for class-level variables, it first checks' the classes namespace, then the namespace of every class in the method resolution order. So, both B and C inherit x from A:
In [1]: class A(object):
...: x = 1
...: class B(A):
...: pass
...: class C(A):
...: pass
...:
In [2]: vars(A)
Out[2]:
mappingproxy({'__module__': '__main__',
'x': 1,
'__dict__': <attribute '__dict__' of 'A' objects>,
'__weakref__': <attribute '__weakref__' of 'A' objects>,
'__doc__': None})
In [3]: vars(B)
Out[3]: mappingproxy({'__module__': '__main__', '__doc__': None})
In [4]: vars(C)
Out[4]: mappingproxy({'__module__': '__main__', '__doc__': None})
When you ask for B.x or C.x, it looks into that class namespace, doesn't find any "x", then tries A's namespace, finds it, and returns it.
Now, when you assign a variable to B.x = 2, that adds it to B's class namespace directly:
In [5]: B.x = 2
...:
In [6]: vars(B)
Out[6]: mappingproxy({'__module__': '__main__', '__doc__': None, 'x': 2})
And similarly, when you assign it to A.x=3, it overwrites the old value:
In [7]: A.x=3
...:
In [8]: vars(A)
Out[8]:
mappingproxy({'__module__': '__main__',
'x': 3,
'__dict__': <attribute '__dict__' of 'A' objects>,
'__weakref__': <attribute '__weakref__' of 'A' objects>,
'__doc__': None})
In [9]: vars(B)
Out[9]: mappingproxy({'__module__': '__main__', '__doc__': None, 'x': 2})
In [10]: vars(C)
Out[10]: mappingproxy({'__module__': '__main__', '__doc__': None})
So now, same as before, when you look for C.x, it doesn't find it's own, then it looks for x inside A, and finds it.
Note, inheritance works like this with instances too, just it checks the instance namespace first, then the instances class's namespace, then all the namespace of the classes in it's method resolution order.
I think it's because of this fact that you did not set "a" field for instance of the "C" class.
Thus it gets its default value from the superclass ("Parent class").
If you set the value of "a" in the c instance, You will get "(3,2,1)".

Class variable scope for static vs class methods

I discovered a weird behaviour (at least weird for me) on python class variables.
class Base(object):
_var = 0
#classmethod
def inc_class(cls):
cls._var += 1
#staticmethod
def inc_static():
Base._var += 1
class A(Base):
pass
class B(Base):
pass
a = A()
b = B()
a.inc_class()
b.inc_class()
a.inc_static()
b.inc_static()
print(a._var)
print(b._var)
print(Base._var)
The output is 1 1 2.
This is surprising me (I was expecting 4 4 4) and I'm wondering why?
When decorated with #classmethod the first argument cls to inc_class(cls) is, well, the class. <class '__main__.A'> and <class '__main__.B'> respectively for A and B. So cls._var refers to A's _var, and similarly for B. In inc_static, decorated with #staticmethod there is no argument, you're explicitly referring to <class '__main__.Base'>, a different _var.
Note the '_var': 0 attribute in Base's and A's __dict__. #classmethod is doing what you'd expect it to do, binding members to classes, in this case A and B.
>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 0, 'inc_class': <classmethod
object at 0x7f23037a8b38>, 'inc_static': <staticmethod object at
0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base' objects>,
'__weakref__': <attribute '__weakref__' of 'Base' objects>, '__doc__': None})
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})`
After calling Base.inc_static():
>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 1, 'inc_class':
<classmethod object at 0x7f23037a8b38>, 'inc_static': <staticmethod
object at 0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base'
objects>, '__weakref__': <attribute '__weakref__' of 'Base' objects>,
'__doc__': None})
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})
After calling A.inc_class():
>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 1, 'inc_class':
<classmethod object at 0x7f23037a8b38>, 'inc_static': <staticmethod
object at 0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base'
objects>, '__weakref__': <attribute '__weakref__' of 'Base' objects>,
'__doc__': None})
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None, '_var': 1})
What's interesting is how A's _var is initialised. Note that you do cls._var += 1 before cls._var has been defined. As explained here, cls._var += 1 is equivalent to cls._var = cls._var; cls._var += 1. Because of the way python does lookup the first read of cls._var will fail in A and continue to find it in Base. At the assignment _var is added to A's __dict__ with the value of Base._var, and then all is fine.
>>> class Base(object):
... _var = 10
... #classmethod
... def inc_class(cls):
... cls._var += 1
...
>>> class A(Base):
... pass
...
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})
>>> A.inc_class()
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None, '_var': 11})
Even though the two classes inherit from the Base class, they are completely different objects. Through the instantiation of a and b, you have two objects that belong to two separate classes. When you call
a.inc_class()
b.inc_class()
you increment the _var attribute of class A once, and then you do the same for class B. Even though they share the same name, they are different objects. If you had a second instance of class A, say a2, and you would call the function again, then both calls would manipulate the same variable. This explains how you get your first two outputs.
The third output refers to the Base class object. Again, even though it is the same name, it is a different object. You increment the 3rd object twice, therefore you get 2 as the answer.

How does a object in python find its available methods?

please help me on this topic : If I try to print object.dict, it only shows instance variables and not the methods where as classes do show it's variable and method functions.
If I consider powershell objects, then it does show it's method and properties and many more attributes.
example : powershell_object | get-member
you can use dir(obj) and get the methods and instance variables, then you can filter them to only functions like this:
object_functions = {}
for obj_member in dir(obj):
if callable(getattr(obj, obj_member)):
object_functions[obj_member] = getattr(obj, obj_member)
Methods are functions that belong to the objects's __class__, and to all the classes in it's class method-resolution order, which you can introspect using: __class__.__mro__
So consider:
In [15]: class A(object):
...: def amethod(self): pass
...: class B(A):
...: def bmethod(self): pass
...: class C(A):
...: def cmethod(self): pass
...: class D(B, C):
...: def dmethod(self): pass
...:
In [16]: d = D()
In [17]: vars(D)
Out[17]:
mappingproxy({'__module__': '__main__',
'dmethod': <function __main__.D.dmethod(self)>,
'__doc__': None})
Note, vars just returns __dict__. Notice, D.__dict__ only has dmethod. Now consider:
In [18]: D.__mro__
Out[18]: (__main__.D, __main__.B, __main__.C, __main__.A, object)
In [19]: from pprint import pprint
In [20]: for klass in D.__mro__:
...: print(klass, end=' '); pprint(vars(klass))
...:
<class '__main__.D'> mappingproxy({'__doc__': None,
'__module__': '__main__',
'dmethod': <function D.dmethod at 0x106e72048>})
<class '__main__.B'> mappingproxy({'__doc__': None,
'__module__': '__main__',
'bmethod': <function B.bmethod at 0x106e72ea0>})
<class '__main__.C'> mappingproxy({'__doc__': None,
'__module__': '__main__',
'cmethod': <function C.cmethod at 0x106e72158>})
<class '__main__.A'> mappingproxy({'__dict__': <attribute '__dict__' of 'A' objects>,
'__doc__': None,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'A' objects>,
'amethod': <function A.amethod at 0x106e72400>})
<class 'object'> mappingproxy({'__class__': <attribute '__class__' of 'object' objects>,
'__delattr__': <slot wrapper '__delattr__' of 'object' objects>,
'__dir__': <method '__dir__' of 'object' objects>,
'__doc__': 'The most base type',
'__eq__': <slot wrapper '__eq__' of 'object' objects>,
'__format__': <method '__format__' of 'object' objects>,
'__ge__': <slot wrapper '__ge__' of 'object' objects>,
'__getattribute__': <slot wrapper '__getattribute__' of 'object' objects>,
'__gt__': <slot wrapper '__gt__' of 'object' objects>,
'__hash__': <slot wrapper '__hash__' of 'object' objects>,
'__init__': <slot wrapper '__init__' of 'object' objects>,
'__init_subclass__': <method '__init_subclass__' of 'object' objects>,
'__le__': <slot wrapper '__le__' of 'object' objects>,
'__lt__': <slot wrapper '__lt__' of 'object' objects>,
'__ne__': <slot wrapper '__ne__' of 'object' objects>,
'__new__': <built-in method __new__ of type object at 0x104ebe518>,
'__reduce__': <method '__reduce__' of 'object' objects>,
'__reduce_ex__': <method '__reduce_ex__' of 'object' objects>,
'__repr__': <slot wrapper '__repr__' of 'object' objects>,
'__setattr__': <slot wrapper '__setattr__' of 'object' objects>,
'__sizeof__': <method '__sizeof__' of 'object' objects>,
'__str__': <slot wrapper '__str__' of 'object' objects>,
'__subclasshook__': <method '__subclasshook__' of 'object' objects>})

`__dict__` of classes in Python

Code goes first,
#Python 2.7
>>>class A(object):
pass
>>>a1 = A()
>>>a2 = A()
>>>A.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
Question
1.what is dict_proxy and why use it?
2.A.__dict__ contains an attr -- '__dict': <attribute '__dict__' of 'A' objects>. What is this? Is it for a1 and a2? But objects of A have their own __dict__, don't they?
For your fist question I quote from Fredrik Lundh: http://www.velocityreviews.com/forums/t359039-dictproxy-what-is-this.html:
a CPython implementation detail, used to protect an internal data structure used
by new-style objects from unexpected modifications.
For your second question:
>>> class A(object):
pass
>>> a1 = A()
>>> a2 = A()
>>> a1.foo="spam"
>>> a1.__dict__
{'foo': 'spam'}
>>> A.bacon = 'delicious'
>>> a1.bacon
'delicious'
>>> a2.bacon
'delicious'
>>> a2.foo
Traceback (most recent call last):
File "<pyshell#314>", line 1, in <module>
a2.foo
AttributeError: 'A' object has no attribute 'foo'
>>> a1.__dict__
{'foo': 'spam'}
>>> A.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'A' objects>, 'bacon': 'delicious', '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
Does this answer your question?
If not, dive deeper: https://stackoverflow.com/a/4877655/1324545
dict_proxy prevents you from creating new attributes on a class object by assigning them to the __dict__. If you want to do that use setattr(A, attribute_name, value).
a1 and a2 are instances of A and not class objects. They don't have the protection A has and you can assign using a1.__dict__['abc'] = 'xyz'

Categories