Allow atomic transformation (sequence of wrapping) for vectorized environment
diff --git a/gym/vector/__init__.py b/gym/vector/__init__.py
index 89e35bf4473..764ea1978e7 100644
--- a/gym/vector/__init__.py
+++ b/gym/vector/__init__.py
@@ -1,10 +1,15 @@
+try:
+    from collections.abc import Iterable
+except ImportError:
+    Iterable = (tuple, list)
+
 from gym.vector.async_vector_env import AsyncVectorEnv
 from gym.vector.sync_vector_env import SyncVectorEnv
 from gym.vector.vector_env import VectorEnv
 
 __all__ = ['AsyncVectorEnv', 'SyncVectorEnv', 'VectorEnv', 'make']
 
-def make(id, num_envs=1, asynchronous=True, **kwargs):
+def make(id, num_envs=1, asynchronous=True, wrappers=None, **kwargs):
     """Create a vectorized environment from multiple copies of an environment,
     from its id
 
@@ -20,6 +25,10 @@ def make(id, num_envs=1, asynchronous=True, **kwargs):
         If `True`, wraps the environments in an `AsyncVectorEnv` (which uses 
         `multiprocessing` to run the environments in parallel). If `False`,
         wraps the environments in a `SyncVectorEnv`.
+        
+    wrappers : Callable or Iterable of Callables (default: `None`)
+        If not `None`, then apply the wrappers to each internal 
+        environment during creation. 
 
     Returns
     -------
@@ -38,6 +47,15 @@ def make(id, num_envs=1, asynchronous=True, **kwargs):
     """
     from gym.envs import make as make_
     def _make_env():
-        return make_(id, **kwargs)
+        env = make_(id, **kwargs)
+        if wrappers is not None:
+            if callable(wrappers):
+                env = wrappers(env)
+            elif isinstance(wrappers, Iterable) and all([callable(w) for w in wrappers]):
+                for wrapper in wrappers:
+                    env = wrapper(env)
+            else:
+                raise NotImplementedError
+        return env
     env_fns = [_make_env for _ in range(num_envs)]
     return AsyncVectorEnv(env_fns) if asynchronous else SyncVectorEnv(env_fns)

Fix #1560