<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def copytree(self, dest_dir, src=None, newname=None, exclude=None, overwrite=False):
 """ Copy this directory or just one contained object into another directory. Parameters dest_dir : string or Directory The destination directory. src : string, optional (default=None) If ``src`` is None then this entire directory is copied recursively otherwise if ``src`` is a string path to an object relative to this directory, only that object will be copied. The copied object can optionally be given a ``newname``. newname : string, optional (default=None) An optional new name for the copied object. exclude : callable, optional (default=None) ``exclude`` can optionally be a function which takes ``(path, object_name)`` and if returns True excludes objects from being copied if the entire directory is being copied recursively. overwrite : bool, optional (default=False) If True, then overwrite existing objects with the same name. """

        def copy_object(obj, dest, name=None):
            if name is None:
                name = obj.GetName()
            if not overwrite and name in dest:
                raise ValueError(
                    "{0} already exists in {1} and `overwrite=False`".format(
                        name, dest._path))
            dest.cd()
            if isinstance(obj, ROOT.R.TTree):
                new_obj = obj.CloneTree(-1, "fast")
                new_obj.Write(name, ROOT.R.TObject.kOverwrite)
            else:
                obj.Write(name, ROOT.R.TObject.kOverwrite)

        with preserve_current_directory():
            if isinstance(src, string_types):
                src = asrootpy(self.Get(src))
            else:
                src = self
            if isinstance(dest_dir, string_types):
                try:
                    dest_dir = asrootpy(self.GetDirectory(dest_dir))
                except DoesNotExist:
                    dest_dir = self.mkdir(dest_dir)
            if isinstance(src, ROOT.R.TDirectory):
                # Copy a directory
                cp_name = newname if newname is not None else src.GetName()
                # See if the directory already exists
                if cp_name not in dest_dir:
                    # Destination directory doesn't exist, so make a new one
                    new_dir = dest_dir.mkdir(cp_name)
                else:
                    new_dir = dest_dir.get(cp_name)
                # Copy everything in the src directory to the destination
                for (path, dirnames, objects) in src.walk(maxdepth=0):
                    # Copy all the objects
                    for object_name in objects:
                        if exclude and exclude(path, object_name):
                            continue
                        thing = src.Get(object_name)
                        copy_object(thing, new_dir)
                    for dirname in dirnames:
                        if exclude and exclude(path, dirname):
                            continue
                        rdir = src.GetDirectory(dirname)
                        # Recursively copy objects in subdirectories
                        rdir.copytree(
                            new_dir,
                            exclude=exclude, overwrite=overwrite)
            else:
                # Copy an object
                copy_object(src, dest_dir, name=newname)