QST: ExtensionDtype made available with arguments to `astype` method
- [x] I have searched the [[pandas] tag](https://stackoverflow.com/questions/tagged/pandas) on StackOverflow for similar questions.

- [ ] I have asked my usage related question on [StackOverflow](https://stackoverflow.com).

---

#### Question about pandas
Hello, 

I have been attempting to create a new ExtensionDtype and ExtensionArray.  The Dtype can take in arguments. I was looking into how to replicate the behaviour of `Categorical` when assigning a dtype to a series. 

If the user does not provide arguments 
```python
pd.Series(['a', 'b', 'c']).astype('category')  # or pd.Series(['a', 'b', 'c']).astype(pd.CategoricalDtype())
```
Returns:
```
0      a
1      b
2     c
dtype: category
Categories (2, object): ['a', 'b']
```

If the user provides the `categories` list:
```python
pd.Series(['a', 'b', 'c']).astype(pd.CategoricalDtype(['a', 'b'])) 
```
Then the argument is given to the Array constructor which now returns a missing value:
```
0      a
1      b
2    NaN
dtype: category
Categories (2, object): ['a', 'b']
```

But for now, with my custom Dtype called in a similar fashion, the default values are used no matter the given arguments: 
Running:
```python
pd.Series([1, 2, 3]).astype(DiscreteNumericalDtype(lower=0, upper=3, inc=1))
```
expected to return
```
0   1.0
1   2.0
2   3.0
dtype: discrete
```

but actually returns:
```
0   1.0
1   NaN
2   NaN
dtype: discrete
```
which is the results of using the default argument (lower=0, upper=1, inc=.1)

### More detail about the custom types:
The goal is to create an array where float values have to be between a min and a max value, [lower, upper] and at an interval `inc`. For example, [0, 1, 5.3] mapped onto [1, 6] with an inc=1 should return: [NaN, 1, 5], and with an inc=0.2 should return [NaN, 1, 5.2].

Here is the full code I have so far.

I did not ask the question on StackOverflow as I believe the answer to this question should be added into panda's Documentation as well.

**Note**: If you'd still like to submit a question, please read [this guide](
https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) detailing how to provide the necessary information for us to reproduce your question.

```python
from typing import Type, List, Optional

import numpy as np
from druid.pandas.dtypes import DiscreteNumericalDtype
from pandas._typing import DtypeObj
from pandas.core.arrays import ExtensionArray
from pandas.core.dtypes.base import register_extension_dtype, ExtensionDtype


class DiscreteNumericalDtypeType(type):
    """
    the type of DiscreteNumericalDtype, this metaclass determines subclass ability
    """

    pass


@register_extension_dtype
class DiscreteNumericalDtype(ExtensionDtype):

    name = 'discrete'
    type: Type[DiscreteNumericalDtypeType] = DiscreteNumericalDtypeType
    base = np.dtype("O")

    def __init__(self, lower: float = 0., upper: float = 1., inc: float = 0.1):
        self.lower = lower
        self.upper = upper
        self.inc = inc

    @property
    def type(self) -> Type:
        return np.float

    @classmethod
    def construct_array_type(cls) -> Type['DiscreteNumericalArray']:
        from druid.pandas.arrays import DiscreteNumericalArray
        return DiscreteNumericalArray

    def _is_numeric(self) -> bool:
        return True

    def _is_boolean(self) -> bool:
        return False

    def _get_common_dtype(self, dtypes: List[DtypeObj]) -> Optional[DtypeObj]:
        raise NotImplementedError('TODO')



class DiscreteNumericalArray(ExtensionArray):
    """
    Represent a Continuous value into bins between [Lower, Upper] and a step size.
    """
    _dtype = DiscreteNumericalDtype()
    ndim: int = 1

    def __init__(self,
                 values,
                 lower: Optional[float] = 0.,
                 upper: Optional[float] = 1.,
                 inc: float = 0.1):
        values = np.asarray(values, dtype=float)
        if lower is None:
            lower = np.min(values)
        if upper is None:
            upper = np.max(values)

        values[values > upper] = np.nan
        values[values < lower] = np.nan

        self._dtype = DiscreteNumericalDtype(lower=lower, upper=upper + inc, inc=inc)
        bins = self.bins
        self.codes = np.searchsorted(bins, values, side='right') - 1
        self.codes[np.isnan(values)] = -1

    @property
    def values(self):
        values = self.bins[self.codes]
        values[self.codes == -1] = np.nan
        return values

    @property
    def dtype(self) -> DiscreteNumericalDtype:
        return self._dtype

    @property
    def bins(self):
        return np.arange(start=self.dtype.lower,
                         stop=self.dtype.upper,
                         step=self.dtype.inc,
                         dtype=float)

    @classmethod
    def _from_sequence(cls, scalars, *, dtype=None, copy=False):
        return DiscreteNumericalArray(scalars)

    @property
    def _constructor(self) -> Type['DiscreteNumericalArray']:
        return DiscreteNumericalArray

    @classmethod
    def _from_factorized(cls, values, original):
        return original._constructor(values,
                                    lower=original.dtype.lower,
                                    upper=original.dtype.upper,
                                    inc=original.dtype.inc)

    def astype(self, dtype, copy=True):
        raise NotImplementedError('TODO')

    def isna(self):
        return self.codes == -1

    def __len__(self):
        return len(self.codes)

    def __getitem__(self, key):
        return self.values[key]


```
