Python returns None at closure while using decorators - python-decorators

The Problem is that the inner function returns None instead of resulting the output if the second digit is not zero!
Why does it not act as a normal decorator?
Code:
def check(fun):
def inner_fun(a,b):
if b == 0:
print("0 is not valid")
return
fun(a,b)
return inner_fun #returns None
def divide(a,b):
return a / b
divide = check(divide)
print(divide(5, 0))
Output:
0 is not valid
None

The inner function does not return the value you expect because... it does not return. Instead, it implicitly returns None, as Python functions do when they reach the end of control flow.
You can edit the inner function to return f(a, b) in the normal case:
def check(fun):
def inner_fun(a,b):
if b == 0:
print("0 is not valid")
return # implicitly returns None
return fun(a,b) # note return
return inner_fun

Related

How to solve my Fibonaci recursive method in Ruby

def fibs_rec(n)
return 1 if n == 1 || n == 0
puts fibs_rec(n-1) + fibs_rec(n-2)
end
fibs_rec(5)
It's giving me the error
"undefined method '+' for nil:Nilclass"
I dont know what that means. How is it being turned to nil.
Make the method actually return the generated number:
def fibs_rec(n)
return 1 if n == 1 || n == 0
(fibs_rec(n-1) + fibs_rec(n-2)).tap do |result|
puts result
end
end
.tap lets you yield an object to a block and always return the object itself.
When you do recursion, the recursive function (or method in Ruby's term) must return a value. Ruby's puts method, on the other hand, returns nil.
You must move the puts method out of the recursion so that the fibs_rec method always returns a value.

Ruby passing arbitrary function and parameters into another function

I'm trying to learn Ruby. I want to pass an arbitrary function and an arbitrary list of arguments and keyword arguments into another function.
for example, I have this arbitrary function below
def dummy_func(a, b)
return a+b
end
And I have this wrapper function
def wrapper(func, *args, **kwargs)
func(args, kwargs))
end
I want it so I can pass my arguments in any of the following ways and still return the correct answer
wrapper(dummy_func, a=1, b=2)
wrapper(dummy_func, 1, b=2)
wrapper(dummy_func, a=1, b=2)
wrapper(dummy_func, 1, 2)
Is this possible in Ruby? What would be an idiomatic way of approaching it?
The idiomatic way is to instead yield to a block.
def dummy_func(a, b, key:)
return a+b+key
end
def wrapper
puts yield
end
a = 4
b = 5
c = 6
wrapper do
dummy_func(a ,b, key: c)
end
Since the block is closure it can see all the same variables that the call to wrapper can. Now there's no need to pass wrapper's arguments through.
If you really want to make your wrapper, you can do some introspection to determine what arguments the wrapped function takes.
def dummy_func(a, b=23, key: 42)
return a+b+key
end
def no_keys(a, b=23)
return a+b
end
def wrapper(func, *array, **hash)
method = self.method(func)
takes_array = method.parameters.any? { |p| [:req, :opt, :rest].include?(p[0]) }
takes_hash = method.parameters.any? { |p| [:keyreq, :key, :keyrest].include?(p[0]) }
if takes_array && takes_hash
self.send(func, *array, **hash)
elsif takes_array
self.send(func, *array)
elsif takes_hash
self.send(func, **hash)
else
self.send(func)
end
end
a = 4
b = 5
c = 6
puts wrapper(:dummy_func, a, b, key:c)
puts wrapper(:no_keys, a, b)
But this is quite a bit more complex and less flexible than yielding to a block. This also limits you to "functions" which are really methods on the main object (there are no function references in Ruby). That's why they're called with self.send. Blocks require no assumptions about what is being wrapped.
The closest you can get is keyword arguments:
https://www.justinweiss.com/articles/fun-with-keyword-arguments/
def hello_message(greeting, time_of_day, first_name:, last_name:)
"#{greeting} #{time_of_day}, #{first_name} #{last_name}!"
end
args = ["Morning"]
keyword_args = {last_name: "Weiss"}
hello_message("Good", *args, first_name: "Justin", **keyword_args)
=> "Good Morning, Justin Weiss!"

An integer I pass as an argument becomes a method

I am trying to write a function. Here is the code.
def get_sum(a,b)
if a == b do
return a
end
else
total = 0
for num in a...b
total += num
end
return total
end
end
I get this error:
undefined method `b' for main:Object (NoMethodError)
Can anyone tell me why I get this?
No do for ifs
if a == b
return a
end
Note that you can do the same thing so
def get_sum(a, b)
return a if a == b
(a...b).inject(:+)
end
It is because you have a block do ... end after b. Neither the keyword if nor the syntax sugar form ... == ... accepts a block. The only possibility left to interpret your code syntactically is to interpret b as a method that takes this do ... end block, and that is how it is parsed.

What does RubyMonk's calculate method do?

I'm learning Ruby on RubyMonk right now and am struggling with the code below: the calculate method -> def calculate(*arguments). Is it possible that you can explain to me each line of code? I think I know what each code line's syntax, but the logic doesn't make any sense to me?
def add(*numbers)
numbers.inject(0) { |sum, number| sum + number }
end
def subtract(*numbers)
sum = numbers.shift
numbers.inject(sum) { |sum, number| sum - number }
end
def calculate(*arguments)
# if the last argument is a Hash, extract it
# otherwise create an empty Hash
options = arguments[-1].is_a?(Hash) ? arguments.pop : {}
options[:add] = true if options.empty?
return add(*arguments) if options[:add]
return subtract(*arguments) if options[:subtract]
end
for example, the options is killing me...I don't know what result returns from the two lines...
Thank you so much!
options = arguments[-1].is_a?(Hash) ? arguments.pop : {}
arguments is an array. A negative array index starts counting from the end of the array, with -1 being the last element. So arguments[-1] is the last argument passed to the method. is_a?(Hash) tests if the argument is a hash. '?' and ':' make up the ternary operator. If the last argument is a hash, pop it from the array. If it is not, then just give us an empty hash.
options[:add] = true if options.empty?
This line is equivalent to:
if options.empty?
options[:add] = true
end
What it's saying here is that if the caller didn't specify what operation they wanted, then assume they wanted to perform addition.
return add(*arguments) if options[:add]
Call the add method and return the result if options[:add]. If the caller specified addition, or if the caller did not specify any operation, then this line will be executed and the method will return here. Nothing else will be executed.
return subtract(*arguments) if options[:subtract]
Call the subtract method and return the result if options[:subtract]. If the caller specified subtraction (and did not specify addition), then this line will be executed and the method will return here. Nothing else will be executed.
Note that it's possible to reach the end of this method without triggering either of the explicit return statements, basically by passing { :operation_not_supported => true } as the last argument. In which case, you get ruby's implicit return, which would be the value of the last line executed. Which would be the one that retrieves the options hash from the argument array. Short version: specifying an unsupported operation when you call this method will have the calculate method return your options hash.
It's just an implementation of this usage:
calculate(1, 2, 3, add: true) #=> 6 (1 + 2 + 3)
calculate(1, 2, 3, subtract: true) #=> -4 (1 - 2 - 3)
calculate(1, 2, 3) #=> 6 (option defaults to {add: true})

How do I recreate Enumerable's count method?

I'm trying to recreate Enumerable's count method as found in "Projects: Advanced Building Blocks".
The definition in the Ruby docs is that count
"Returns the number of items in enum through enumeration. If an argument is given, the number of items in enum that are equal to item are counted. If a block is given, it counts the number of elements yielding a true value."
What exactly is the default argument though?
The way I approached this so far is as follows:
The parameter is set to something when no argument is passed so:
Case, when self is not a string:
when argument given and block given (eg. [1,2,3].count(3) { |x| x == 3 }):
returns warning and count of the argument.
when argument given and no block (eg. [1,2,3].count(3)):
returns count of the argument.
when no argument and no block (eg. [1,2,3].count):
returns size of the instance.
else (no argument given and block given) (eg. [1,2,3].count { |x| x == 3 }:
returns count based on specifications given in block.
The two questions I have are basically:
What is the default argument for count?
What is the global variable used in warning?
Here's my code:
module Enumerable
def my_count arg='default value'
if kind_of? String
# code
else # I think count works the same way for hashes and arrays
if arg != 'default value'
count = 0
for index in 0...size
count += 1 if arg == self[index]
end
warn "#{'what goes here'}: warning: block not used" if block_given?
count
else
return size if arg == 'default value' && !block_given?
count = 0
for index in 0...size
count += 1 if yield self[index]
end
count
end
end
end
end
Don't use a default argument. Use *args to collect all the arguments into an array.
def my_count(*args, &block)
if args.length == 1 && !block_given?
# use args[0]
elsif args.length == 1 && block_given?
# use block
elsif args.length == 0 && !block_given?
# no argument/block
else
# raise error
end
end

Resources