diff options
Diffstat (limited to 'python.html.markdown')
| -rw-r--r-- | python.html.markdown | 84 | 
1 files changed, 61 insertions, 23 deletions
| diff --git a/python.html.markdown b/python.html.markdown index d9eda60c..326ddb95 100644 --- a/python.html.markdown +++ b/python.html.markdown @@ -685,8 +685,8 @@ print(math.sqrt(16))  # => 4.0  # You can get specific functions from a module  from math import ceil, floor -print(ceil(3.7))   # => 4.0 -print(floor(3.7))  # => 3.0 +print(ceil(3.7))   # => 4 +print(floor(3.7))  # => 3  # You can import all functions from a module.  # Warning: this is not recommended @@ -733,7 +733,9 @@ class Human:          self.name = name          # Initialize property -        self._age = 0 +        self._age = 0   # the leading underscore indicates the "age" property is  +                        # intended to be used internally +                        # do not rely on this to be enforced: it's a hint to other devs      # An instance method. All methods take "self" as the first argument      def say(self, msg): @@ -876,7 +878,8 @@ if __name__ == '__main__':      if type(sup) is Superhero:          print('I am a superhero') -    # Get the Method Resolution search Order used by both getattr() and super() +    # Get the "Method Resolution Order" used by both getattr() and super() +    # (the order in which classes are searched for an attribute or method)      # This attribute is dynamic and can be updated      print(Superhero.__mro__)    # => (<class '__main__.Superhero'>,                                  # => <class 'human.Human'>, <class 'object'>) @@ -958,8 +961,7 @@ class Batman(Superhero, Bat):  if __name__ == '__main__':      sup = Batman() -    # Get the Method Resolution search Order used by both getattr() and super(). -    # This attribute is dynamic and can be updated +    # The Method Resolution Order      print(Batman.__mro__)       # => (<class '__main__.Batman'>,                                  # => <class 'superhero.Superhero'>,                                  # => <class 'human.Human'>, @@ -1016,31 +1018,67 @@ gen_to_list = list(values)  print(gen_to_list)  # => [-1, -2, -3, -4, -5] -# Decorators -# In this example `beg` wraps `say`. If say_please is True then it -# will change the returned message. -from functools import wraps +# Decorators are a form of syntactic sugar. +# They make code easier to read while accomplishing clunky syntax. +# Wrappers are one type of decorator. +# They're really useful for adding logging to existing functions without needing to modify them. -def beg(target_function): -    @wraps(target_function) +def log_function(func):      def wrapper(*args, **kwargs): -        msg, say_please = target_function(*args, **kwargs) -        if say_please: -            return "{} {}".format(msg, "Please! I am poor :(") -        return msg - +        print("Entering function", func.__name__) +        result = func(*args, **kwargs) +        print("Exiting function", func.__name__) +        return result      return wrapper +@log_function               # equivalent: +def my_function(x,y):       # def my_function(x,y): +    return x+y              #   return x+y +                            # my_function = log_function(my_function) +# The decorator @log_function tells us as we begin reading the function definition +# for my_function that this function will be wrapped with log_function. +# When function definitions are long, it can be hard to parse the non-decorated +# assignment at the end of the definition. + +my_function(1,2) # => "Entering function my_function" +                 # => "3" +                 # => "Exiting function my_function" + +# But there's a problem. +# What happens if we try to get some information about my_function? + +print(my_function.__name__) # => 'wrapper' +print(my_function.__code__.co_argcount) # => 0. The argcount is 0 because both arguments in wrapper()'s signature are optional. + +# Because our decorator is equivalent to my_function = log_function(my_function) +# we've replaced information about my_function with information from wrapper + +# Fix this using functools + +from functools import wraps + +def log_function(func): +    @wraps(func) # this ensures docstring, function name, arguments list, etc. are all copied +                 # to the wrapped function - instead of being replaced with wrapper's info +    def wrapper(*args, **kwargs): +        print("Entering function", func.__name__) +        result = func(*args, **kwargs) +        print("Exiting function", func.__name__) +        return result +    return wrapper -@beg -def say(say_please=False): -    msg = "Can you buy me a beer?" -    return msg, say_please +@log_function                +def my_function(x,y):        +    return x+y               +                             +my_function(1,2) # => "Entering function my_function" +                 # => "3" +                 # => "Exiting function my_function" +print(my_function.__name__) # => 'my_function' +print(my_function.__code__.co_argcount) # => 2 -print(say())                 # Can you buy me a beer? -print(say(say_please=True))  # Can you buy me a beer? Please! I am poor :(  ```  ### Free Online | 
