syntax pytorch.nn functions neural networks, class or functions?
I am puzzled by the syntax of the functions used in neural networks in pytorch.
Here is an example of how one can define a linear transformation layer: (cf. https://pytorch.org/docs/stable/generated/torch.nn.Linear.html)
m = nn.Linear(20, 30)
input = torch.randn(128, 20)
output = m(input)
print(output.size())
torch.Size([128, 30])

Can someone explain me where the expression nn.Linear(20,30)(input) comes from ? It disturbs me a bit.
Indeed, one can define a class neural network with such cosntructor : (for example)
class NeuralNet(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes, p=0):
        super(NeuralNet, self).__init__()
        self.fc1            = nn.Linear(input_size, hidden_size, bias=True)
        self.fc2            = nn.Linear(hidden_size, hidden_size, bias=True)
        self.fc3            = nn.Linear(hidden_size, hidden_size, bias=True)
        self.fc4            = nn.Linear(hidden_size, num_classes, bias=False)
        self.dropout        = nn.Dropout(p=p)

and I was trying to write an attribute using numpy function, like:
  self.enter_reshape  = np.reshape(-1, input_size * input_size)
  self.exit_reshape   = np.reshape(input_size, num_classes / input_size)

or, using the view function from pytorch:
self.reshape = view(-1, self.num_flat_features())

The closest thing I know about is the partial function and closures, where one could write f(z)(x)(y). I looked into the definition of Linear, and I saw that linear is an object, but I don't see where they redefined __call__ magic function, which I thought would be used here when one calls the object.
So basically, can one explain what is up with such writting, and also, would it be possible to give to the neural network the numpy or view functions as attributes?

torch.nn.Linear inherits from torch.nn.Module (see source code), which in turn defines __call__ method.
You can see source code for torch.nn.Module here. This class allows users to make their own Modules by inheritance (as you did in your example) and is a base for all PyTorch defined modules like nn.Linear (see available methods, documentation here).
Its __call__ essentially calls forward but running registered hooks (and registering), checking torchscript etc. (see source code here, with relevant line here.

would it be possible to give to the neural network the numpy or view
functions as attributes?

From the example you've given, what you are trying to do is probably partial function (or lambda as in the example below) saved as attribute (though that is pretty uncommon and never seen it tbh), like this:
import torch


class MyModule(torch.nn.Module):
    def __init__(self, shape: int = -1):
        super().__init__()  # required
        self.reshape = lambda tensor: torch.reshape(tensor, (shape,))

    def forward(self, tensor):
        return self.reshape(tensor)


module = MyModule()
module(torch.randn(4, 5, 6)).shape # [120] shape

You shouldn't use numpy with pytorch unless you really need it and/or there is no sensible pytorch counterpart (although you can if you transform torch.Tensor to numpy). Also you shouldn't do anything like the code above as it's really confusing, just save attributes (anything like input_shape, hidden_dim, output_size) and use it in forward:
class MyModule(torch.nn.Module):
    def __init__(self, shape: int = -1):
        super().__init__()  # required
        self.shape = shape

    def forward(self, tensor):
        return torch.reshape(tensor, (self.shape,))

