python-function
Advanced function feature
In python, function is an object
that means you can assign it to a variable or pass it as a parameter! we can also return a function inside another function, cool!
Assign functions to a variable
1 | def greet(name): |
Function can return other function
1 | def compose_greet_func(name): |
if nothing returns in function, None returned by default
descriptor(class method)
In general, a descriptor is an object attribute with "binding behavior"
whose access has been overridden by method in the descriptor protocol. Those methods are __get__(), __set__(), and __delete__()
. If any of those methods is defined for an object, it is said to be a descriptor
Calling property() is a succinct way of building a data descriptor that triggers function call upon access to an attribute
.
define a propertyproperty(fget=None, fset=None, fdel=None, doc=None) -> property attribute
we can also use decorator @property and @xx.setter to define a property, must define @property first!!!
1 | class Person: |
get_name() is called
jason
set_name() is called with name: kk
name getter is called
kk
function closure
if a function defines another function in its scope and returns it
, it’s a closure
1 | def welcome(name): |
wrapper is called with: jason
decorator
Python has built-in decorator like property
, to apply a decorator to a function by placing it just before the function definition. like
1 |
|
Decorator is needed when you want do something before a function run, place it anywhere that needs it.
Decorator can be a class or function, if it is class, must be callable, has __call__ function defined
.
below are the ways to create a custom decorator
function as a decorator.
decorator is applied when you define that function, later on when you call it, the wrapped function is called actually.
1 | def log(text): |
we got parameter for decorator: param1
inside aFunction jason
class as a decorator
decorator is applied when you define that function, later on when you call it, the wrapped function is called actually.
**Always use call as decorator, as it’s easy to understand.
class decorator without parameter
1 | class cDecorator: |
decorator is initialized
decorator is called
inside bFunction: hi josh
doc of class decorator
class decorator with parameter
1 | class cDecorator: |
decorator is initialized cool
wrapper parameter: cool
call original function
inside bFunction: hi josh
None
why use functools.wraps
when a function is decorated, getting the docstring and function signature return “wrapper”, the inner function, not the original function
, this is a problem, we can use “functool.wraps” decorator to decorate our inner function, By applying this “wraps” decorator to our inner function, we copy over func name, docstring, and signature to our inner function
, avoiding the issues.
1 | from functools import wraps |
execute call f()
hi josh
f
Generator vs Iterator
generator function returns a generator object, generator function is function that yield(like return) value when next()
call,it will execute until last yield point, most of time next()
is not called explictly but implicitly like this for elm in list
.
Iterator
An iterator is an object that implements the iterator protocol (don’t panic!). An iterator protocol is nothing but a specific class with __next__()
in Python which further has the __next__()
method.
While for iterable object, No need to __next__()
but mostly have __iter__() and __getitem__()
, __iter__()
allows to convert the object into an iterator, __getitem__()
will be called in iterator’s __next__()
function.
iter(object) will call object.__iter__() while next(object) will call object.__next__()
Generator
- Iterator is an object has
__next__()
method - generator is an object which implements
__next__()
, so that it’s an iterator! generator function is a function that uses yield as return
, when you call this function, itreturns a generator object!
more details about these two, refer to iterator-generator-descriptor.
Most uses case, you create a generator function which returns a generator object and for elm in generator_object
1 | def f(): |
<generator object f at 0x7f3e30235f90>
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
use next(generator_object)
start
middle
end
use for/in to iterate generator
start
middle
end
1 | # List is iterable, but it's not an Iterator! |
<__main__.MyIterator object at 0x7f3e30278d00>
1
2