I'm new to Swift, and I'd like to know if the language has some equivalent to Python's decorator pattern.
For example:
import functools
def announce(func):
"""Print a function's arguments and return value as it's called."""
@functools.wraps(func)
def announced_func(*args, **kwargs):
rv = func(*args, **kwargs)
print('In: {0}, {1}'.format(args, kwargs))
print('Out: {}'.format(rv))
return rv
return announced_func
@announce # add = announce(add)
def add(a, b):
return a + b
add(2, 5)
# In: (2, 5), {}
# Out: 7
# 7
Perhaps I just haven't found it yet, but Swift doesn't seem to have a way to forward arbitrary arguments to functions or to preserve a wrapped function's information (as functools.wraps does).
Is there an equivalent, or is the pattern not meant to be used in Swift?
Example above updated for Swift 5.1+
@propertyWrapper
struct Announced<T, U> {
private let announcedFunction: (T) -> U
var wrappedValue: (T) -> U { announcedFunction }
init(wrappedValue: @escaping (T) -> U) {
announcedFunction = { args in
let rv = wrappedValue(args)
print("In: \(args)")
print("Out: \(rv)")
return rv
}
}
}
struct Test {
@Announced static var add: ((Int, Int)) -> Int = { $0.0 + $0.1 }
@Announced static var multiply: ((Int, Int)) -> Int = { $0.0 * $0.1 }
@Announced static var length : (String) -> Int = { (str: String) in str.count }
@Announced static var greet: (String) -> String = { "Hello, \($0)" }
}
Test.add((2, 5)) // In: (2, 5)\n Out: 7
Test.multiply((2, 5)) // In: (2, 5)\n Out: 10
Test.length("Hello world!") // In: Hello world!\n Out: 12
Test.greet("Paul") // In: Paul\n Out: Hello, Paul
[Edit] Actually, it can be simplified:
@propertyWrapper
struct Announced<T, U> {
let wrappedValue: (T) -> U
init(wrappedValue: @escaping (T) -> U) {
self.wrappedValue = { args in
let rv = wrappedValue(args)
print("In: \(args)")
print("Out: \(rv)")
return rv
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With