In Python we can unpack a list or a dictionary as function arguments using *
and **
.
def print_numbers(x, y):
print x
print y
list = [1, 2]
dict = {'x': 1, 'y': 2}
print_numbers(*list)
print_numbers(**dict)
Decorators allow to wrap a function or method in another function that can add functionality, modify arguments, results, etc. We write decorators one line above the function definition, beginning with "at" sign (@).
def print_args(fun):
def wrapper(*args, **kwargs):
print 'Arguments:', args, kwargs
return fun(*args, **kwargs)
return wrapper
@print_args
def write(text):
print text
write('foo')
Warning with this
def foo(x=[]):
x.append(1)
print x
def foo(x=None):
if x is None:
x = []
x.append(1)
print x
They're the magic behind a whole bunch of core Python features.
When you use dotted access to look up a member (eg, x.y), Python first looks for the member in the instance dictionary. If it's not found, it looks for it in the class dictionary. If it finds it in the class dictionary, and the object implements the descriptor protocol, instead of just returning it, Python executes it. A descriptor is any class that implements the __get__
, __set__
, or __delete__
methods.
Here's how you'd implement your own (read-only) version of property using descriptors:
class Property(object):
def __init__(self, fget):
self.fget = fget
def __get__(self, obj, type):
if obj is None:
return selfIt's great for things like adding up numbers:
return self.fget(obj)
and you'd use it just like the built-in property():
class MyClass(object):
@Property
def foo(self):
return "Foo!"
Descriptors are used in Python to implement properties, bound methods, static methods, class methods and slots, amongst other things. Understanding them makes it easy to see why a lot of things that previously looked like Python 'quirks' are the way they are.
Raymond Hettinger has an excellent tutorial that does a much better job of describing them than I do.
Dictionaries have a 'get()' method. If you do d['key'] and key isn't there, you get an exception. If you do d.get('key'), you get back None if 'key' isn't there. You can add a second argument to get that item back instead of None.
It's great for things like adding up numbers:
sum[value] = sum.get(value, 0) + 1