<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Python Metaprogramming Quick Reference
Table Of Contents
<a href="#1.-Decorator-Implementation">Decorator Implementation</a>
<a href="#2.-Advanced-Decorators">Advanced Decorators</a>
<a href="#3.-Metaclasses">Metaclasses</a>
1. Decorator Implementation
At their heart, decorators are functions that take a function as input and return a wrapping function as output
Step1:  2. Advanced Decorators
Step2:  3. Metaclasses
<ASSISTANT_TASK:>
Python Code:
def hello_world():
    print('hello world')
    
# wrap hello world in a function that does logging
def wrap_hello():
    print('Enter: hello_world')
    hello_world()
    print('Exit: hello_world')
    
wrap_hello()
# to wrap any function at all, write a generic wrapper that takes the a function as input
def logthis(func):
    print('Enter: {}'.format(func.__name__))
    func()
    print('Exit: {}'.format(func.__name__))
    
logthis(hello_world)
# add the ability to handle arbitrary parameters and return types
def logthis(func):
    def wrapper(*args, **kwargs):
        print('Enter: {}'.format(func.__name__))
        result = func(*args, **kwargs)
        print('Exit: {}'.format(func.__name__))
        return result
    return wrapper  # return the inner function
logged_hello = logthis(hello_world)
logged_hello()
# now you can replace hello_world with the wrapped function
hello_world=logged_hello
hello_world()
# the only problem is that function metadata is wrong
hello_world.__name__
#instead use functools.wraps and a decorator on your function, which otherwise is equivalent
from functools import wraps
def logthis(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('Enter: {}'.format(func.__name__))
        result = func(*args, **kwargs)
        print('Exit: {}'.format(func.__name__))
        return result
    return wrapper  # return the inner function
hello_world=None
@logthis
def hello_world():
    print('hello world')
    
hello_world()
#if you use wraps, you can also access the raw undecorated function using __wrapped__
raw_hello = hello_world.__wrapped__
raw_hello()
Explanation: Python Metaprogramming Quick Reference
Table Of Contents
<a href="#1.-Decorator-Implementation">Decorator Implementation</a>
<a href="#2.-Advanced-Decorators">Advanced Decorators</a>
<a href="#3.-Metaclasses">Metaclasses</a>
1. Decorator Implementation
At their heart, decorators are functions that take a function as input and return a wrapping function as output
End of explanation
# Decorator that takes arguments
def logged(prefix):
    prefix = prefix if prefix else ''
    logprefix = prefix + ':' if len(prefix) > 0 else prefix
    def decorate(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print('{}Enter:{}'.format(logprefix, func.__name__))
            result = func(*args, **kwargs)
            print('{}Exit:{}'.format(logprefix, func.__name__))
            return result
        return wrapper
    return decorate
@logged('logger')
def hello_world():
    print('hello world')
hello_world()
# always declare classmethod and staticmethod decorators first (so they are applied last)
class Spam:
    @logthis
    def instance_method(self, n):
        print(self, n)
        while n > 0:
            n -= 1
    @classmethod
    @logthis
    def class_method(cls, n):
        print(cls, n)
        while n > 0:
            n -= 1
    @staticmethod
    @logthis
    def static_method(n):
        print(n)
        while n > 0:
            n-=1
s = Spam()
s.instance_method(4)
Spam.class_method(10)
Explanation: 2. Advanced Decorators
End of explanation
# Singleton metaclass
class Singleton(type):
    def __init__(self, *args, **kwargs):
        self.__instance = None
        super().__init__(*args, **kwargs)
    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super().__call__(*args, **kwargs)
            return self.__instance
        else:
            return self.__instance
# Example
class Spam(metaclass=Singleton):
    def __init__(self):
        print('Creating Spam')
a = Spam()   #generates 'Creating Spam'
b=Spam()     #no print message produced
b is a
# Metaclass to cache objects by string provided in ctor
import weakref
class Cached(type):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__cache = weakref.WeakValueDictionary()
    def __call__(self, *args):
        if args in self.__cache:
            return self.__cache[args]
        else:
            obj = super().__call__(*args)
            self.__cache[args] = obj
            return obj
# Example
class Spam(metaclass=Cached):
    def __init__(self, name):
        print('Creating Spam({!r})'.format(name))
        self.name = name
        
a =Spam('a')
b=Spam('b')
b2 = Spam('b')
a is b
b is b2
Explanation: 3. Metaclasses
End of explanation
<END_TASK>