def bind(self, values):
        """
        Binds a sequence of values for the prepared statement parameters
        and returns this instance.  Note that `values` *must* be:

        * a sequence, even if you are only binding one value, or
        * a dict that relates 1-to-1 between dict keys and columns

        .. versionchanged:: 2.6.0

            :data:`~.UNSET_VALUE` was introduced. These can be bound as positional parameters
            in a sequence, or by name in a dict. Additionally, when using protocol v4+:

            * short sequences will be extended to match bind parameters with UNSET_VALUE
            * names may be omitted from a dict with UNSET_VALUE implied.

        .. versionchanged:: 3.0.0

            method will not throw if extra keys are present in bound dict (PYTHON-178)
        """
        if values is None:
            values = ()
        proto_version = self.prepared_statement.protocol_version
        col_meta = self.prepared_statement.column_metadata

        # special case for binding dicts
        if isinstance(values, dict):
            values_dict = values
            values = []

            # sort values accordingly
            for col in col_meta:
                try:
                    values.append(values_dict[col.name])
                except __HOLE__:
                    if proto_version >= 4:
                        values.append(UNSET_VALUE)
                    else:
                        raise KeyError(
                            'Column name `%s` not found in bound dict.' %
                            (col.name))

        value_len = len(values)
        col_meta_len = len(col_meta)

        if value_len > col_meta_len:
            raise ValueError(
                "Too many arguments provided to bind() (got %d, expected %d)" %
                (len(values), len(col_meta)))

        # this is fail-fast for clarity pre-v4. When v4 can be assumed,
        # the error will be better reported when UNSET_VALUE is implicitly added.
        if proto_version < 4 and self.prepared_statement.routing_key_indexes and \
           value_len < len(self.prepared_statement.routing_key_indexes):
            raise ValueError(
                "Too few arguments provided to bind() (got %d, required %d for routing key)" %
                (value_len, len(self.prepared_statement.routing_key_indexes)))

        self.raw_values = values
        self.values = []
        for value, col_spec in zip(values, col_meta):
            if value is None:
                self.values.append(None)
            elif value is UNSET_VALUE:
                if proto_version >= 4:
                    self._append_unset_value()
                else:
                    raise ValueError("Attempt to bind UNSET_VALUE while using unsuitable protocol version (%d < 4)" % proto_version)
            else:
                try:
                    self.values.append(col_spec.type.serialize(value, proto_version))
                except (TypeError, struct.error) as exc:
                    actual_type = type(value)
                    message = ('Received an argument of invalid type for column "%s". '
                               'Expected: %s, Got: %s; (%s)' % (col_spec.name, col_spec.type, actual_type, exc))
                    raise TypeError(message)

        if proto_version >= 4:
            diff = col_meta_len - len(self.values)
            if diff:
                for _ in range(diff):
                    self._append_unset_value()

        return self
dataset/ETHPy150Open datastax/python-driver/cassandra/query.py/BoundStatement.bind