input: Write a function to develop a class in Python that can perform various matrix operations such as addition, subtraction, multiplication, and transpose. The class should be able to initialize a matrix from a list of numbers, represent the matrix as a string, and perform the operations in-place. If the given matrix is empty, return an empty matrix.
  assert Matrix.__dict__['__init__'] and Matrix.__dict__['__str__'] and Matrix.__dict__['add'] and Matrix.__dict__['sub'] and Matrix.__dict__['mul'] and Matrix.__dict__['transpose']
  assert str(Matrix(2, 2, [1, 2, 3, 4])) == "1 2 \n3 4 \n"
  assert str(Matrix(2, 2, [1, 2, 3, 4]).add(Matrix(2, 2, [5, 6, 7, 8]))) == "6 8 \n10 12 \n"
  assert str(Matrix(2, 2, [1, 2, 3, 4]).sub(Matrix(2, 2, [5, 6, 7, 8]))) == "-4 -4 \n-4 -4 \n"
  assert str(Matrix(2, 2, [1, 2, 3, 4]).mul(Matrix(2, 2, [5, 6, 7, 8]))) == "19 22 \n43 50 \n"
  assert str(Matrix(2, 2, [1, 2, 3, 4]).transpose()) == "1 3 \n2 4 \n"
  assert str(Matrix(0, 0, [])) == ""
output: def __init__(self, rows, cols, data):
      self.rows = rows
      self.cols = cols
      self.data = data if data else [0] * (rows * cols)
  
  def __str__(self):
      if not self.data:
          return ""
      return "\n".join(" ".join(str(self.data[r * self.cols + c]) for c in range(self.cols)) for r in range(self.rows)) + "\n"
  
  def add(self, other):
      if self.rows != other.rows or self.cols != other.cols:
          raise ValueError("Matrices must have the same dimensions")
      for i in range(len(self.data)):
          self.data[i] += other.data[i]
      return self
  
  def sub(self, other):
      if self.rows != other.rows or self.cols != other.cols:
          raise ValueError("Matrices must have the same dimensions")
      for i in range(len(self.data)):
          self.data[i] -= other.data[i]
      return self
  
  def mul(self, other):
      if self.cols != other.rows:
          raise ValueError("Number of columns in the first matrix must be equal to the number of rows in the second matrix")
      result = [0] * (self.rows * other.cols)
      for i in range(self.rows):
          for j in range(other.cols):
              for k in range(self.cols):
                  result[i * other.cols + j] += self.data[i * self.cols + k] * other.data[k * other.cols + j]
      self.data = result
      self.cols = other.cols
      return self
  
  def transpose(self):
      result = [0] * (self.cols * self.rows)
      for i in range(self.rows):
          for j in range(self.cols):
              result[j * self.rows + i] = self.data[i * self.cols + j]
      self.data = result
      self.rows, self.cols = self.cols, self.rows
      return self