def METHOD_NAME(self, args, target_type=ZR):
    """hashes objects into ZR or G
    Different object types may hash to the same element, e.g., the ASCII
    string 'str' and the byte string b'str' map to the same element."""
    def hash_encode(arg):
        """encode a data type to bytes"""
        if type(arg) is bytes:
            s = arg
        elif type(arg) is ec_element:
            s = serialize(arg)
        elif type(arg) is str:
            s = arg.encode('utf-8')
        elif type(arg) is int:
            s = arg.to_bytes((arg.bit_length() + 7) // 8, 'little')
        elif isinstance(args, tuple):
            # based on TupleHash (see NIST SP 800-185)
            def left_encode(x):
                # This implictly checks for validity conditions:
                # An exception is raised if n > 255, i.e., if len(x) > 2**2040
                n = (x.bit_length() + 7 ) // 8
                return n.to_bytes(1, 'little') + x.to_bytes(n, 'little')
            s = b''
            for arg in args:
                z = hash_encode(arg)
                # concat with encode_string(z)
                s += left_encode(len(z)) + z
        else:
            raise ValueError("unexpected type to hash: {}".format(type(arg)))
        return s
    return hashEC(self.ec_group, hash_encode(args), target_type)