Q:

random salt string in Python 3

I'm trying to migrate the following to Python 3.
def mkhash(password, salt=None):
    """
    Compute SHA256 hash of password with pbkdf2 algorithm.
    Call with salt=None for creating hash. To compute verification
    hash, supply salt stored in the user's row in auth_user.
    Args:
        password :
        salt=None :
    Returns: tuple (hash, salt)
    Raises:  Nothing
    """
    if salt is None:
        ## use a 16 char random string
        randchars = [random.choice(string.ascii_lowercase) for _ in range(16)]
        #salt = b''.join(randchars)# works in 2 but not 3
        salt = ''.join(randchars)  # works in 3 but result fails in hashlib call

    # See https://docs.python.org/2/library/hashlib.html
    dk = hashlib.pbkdf2_hmac('sha256', password, salt, 10000)
    pwhash = binascii.hexlify(dk)
    return (pwhash, salt)        

Here's a traceback of the failure in Python 3.
Traceback (most recent call last):
  File "auth.py", line 451, in <module>
    _ = mkhash('badpassword')
  File "auth.py", line 146, in mkhash
    dk = hashlib.pbkdf2_hmac('sha256', password, salt, 10000)
TypeError: a bytes-like object is required, not 'str'

What's the right way, in Python 3, to generate a salt of length N that's compatible with hashlib functions?
EDIT: Working version using accepted answer:
def mkhash(password, salt=None):
    """
    Compute SHA256 hash of password with pbkdf2 algorithm.
    Call with salt=None for creating hash. To compute verification
    hash, supply salt stored in the user's row in auth_user.
    Args:
        password :
        salt=None :
    Returns: tuple (hash, salt)
    Raises:  Nothing
    """
    if salt is None:
        salt = os.urandom(16)
    elif type(salt) is not bytes:
        salt = salt.encode('utf-8')

    # See https://docs.python.org/3/library/hashlib.html
    dk = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 10000)
    pwhash = binascii.hexlify(dk)
    return (pwhash, salt)                   

A:

You can use .encode() to turn a string object into bytes.
salt = salt.encode('utf-8')

But you shouldn't.
The random module doesn't produce cryptographically secure random numbers. That leaves a vulnerability in your code. If you're using Python 3.6, the secrets module is better.
salt = secrets.token_bytes(16)

If not, os.urandom() is also documented to be "unpredictable enough for cryptographic applications".
salt = os.urandom(16)

