Repository: microsoft/Qcodes

Issue:
bug
### Steps to reproduce
1. make parameter class that inherits from `Parameter` with `instrument=None`
2. have an attribute in this class called `self.instrument` 

### Expected behaviour
this should work

### Actual behaviour
upon making a json snapshot, an error occurs. this happens because the instrument attribute interferes with
```python
       for attr in set(self._meta_attrs):
           if attr == 'instrument' and self._instrument:
               state.update({
                   'instrument': full_class(self._instrument),
                   'instrument_name': self._instrument.name
               })

           elif hasattr(self, attr):
               val = getattr(self, attr)
               attr_strip = attr.lstrip('_')  # eg _vals - do not include _
               if isinstance(val, Validator):
                   state[attr_strip] = repr(val)
               else:
                   state[attr_strip] = val
```
from
`_baseparameter` line 193
### System
**operating system**
win10
**qcodes branch**
master
**qcodes commit**
commit 6aabf835bc0dcdcb32a46285bd082f2c43d4eff7



Discussion:
@damazter  it'd be nice to see a MWE or a stack trace! 
@giulioungaretti 
The stacktrace I got did not contain any qcodes code. The problem is that the `station.snapshot()` returns non-serializable data if `self.instrument` contains something non-serializable (following the steps above).

The problem occurs because
```
           if attr == 'instrument' and self._instrument:
```
returns False (`self._instrument` is `None`)
So we enter
```
elif hasattr(self, attr):
```
with `attr` equal to `instrument` which will put the `instrument` attribute in the snapshot (and this was non-serializable)

I hope this is a little bit more clear

MWE is a parameter like `AlazarParameter`
```python
class AlazarParameter(Parameter):
    """
    This class represents of many parameters that are relevant for the Alazar
    driver. This parameters only have a private set method, because the values
    are set by the Alazar driver. They do have a get function which return a
    human readable value. Internally the value is stored as an Alazar readable
    value.

    These parameters also keep track the up-to-dateness of the value of this
    parameter. If the private set_function is called incorrectly, this parameter
    raises an error when the get_function is called to warn the user that the
    value is out-of-date

    Args:
        name: see Parameter class
        label: see Parameter class
        unit: see Parameter class
        instrument: see Parameter class
        value: default value
        byte_to_value_dict: dictionary that maps byte values (readable to the
            alazar) to values that are readable to humans
        vals: see Parameter class, should not be set if byte_to_value_dict is
            provided
    """
    def __init__(self, name=None, label=None, unit=None, instrument=None,
                 value=None, byte_to_value_dict=None, vals=None):
        if vals is None:
            if byte_to_value_dict is None:
                vals = validators.Anything()
            else:
                # TODO(damazter) (S) test this validator
                vals = validators.Enum(*byte_to_value_dict.values())

        super().__init__(name=name, label=label, units=unit, vals=vals)
        self.instrument = instrument
        self._byte = None
        self._uptodate_flag = False
```

I know this problem can be solved by changing to
```python
        super().__init__(name=name, label=label, units=unit, vals=vals, instrument=instrument)
```
But it feels a bit weird that qcodes requires that parameters don't have an `self.instrument` as attribute

Resolving patch:
diff --git a/qcodes/instrument_drivers/AlazarTech/ATS.py b/qcodes/instrument_drivers/AlazarTech/ATS.py
--- a/qcodes/instrument_drivers/AlazarTech/ATS.py
+++ b/qcodes/instrument_drivers/AlazarTech/ATS.py
@@ -793,7 +793,8 @@ def __init__(self, name=None, label=None, unit=None, instrument=None,
                 # TODO(damazter) (S) test this validator
                 vals = validators.Enum(*byte_to_value_dict.values())
 
-        super().__init__(name=name, label=label, units=unit, vals=vals)
+        super().__init__(name=name, label=label, units=unit, vals=vals,
+                         instrument=instrument)
         self.instrument = instrument
         self._byte = None
         self._uptodate_flag = False


Test patch: