Suppose we have a function that receives a callable as parameter:
def foo(bar: Callable[[Any], Any]) -> None:
pass
According the annotation the callable we must pass as argument should receive only one argument and return anything, just like:
def third_party_callable(x: Any) -> None:
pass
But we have our own callable that receives 2 arguments so we decide to use functools.partial to match the foo signature:
def my_custom_callable(y: Any, x: Any) -> None:
pass
my_callable = partial(my_custom_callable, 'my_custom_y')
# And then ...
foo(my_callable)
This will result in a linter warning stating that: Expected type '(Any) -> None', got 'partial[None]' instead
Question 1: Is there some way to do this and not getting the linter warning?
Question 2: Should the returned type of partial be Callable[[...], ...]?
Question 3: If what I want is not a desired behavior could someone explain why?
Related
What is the correct way to add type hints to the following function?
from typing import Callable
def format_callback(f: Callable) -> Callable:
"""Function to wrap a function to use as a click callback.
Taken from https://stackoverflow.com/a/42110044/8056572
"""
return lambda _, __, x: f(x)
Now mypy is complaining with Missing type parameters for generic type "Callable"
The code needs to be compatible with both Python 3.9 and 3.10. I can use typing_extensions if needed.
Edit:
The following passes mypy but has too many Any's for my taste. Is there a better way?
from typing import Any
from typing import Callable
import click
def format_callback(f: Callable[[Any], Any]) -> Callable[[click.Context, dict[str, Any], Any], Any]:
"""Function to wrap a function to use as a click callback.
Taken from https://stackoverflow.com/a/42110044/8056572
"""
return lambda _, __, x: f(x)
Without looking at click, the immediate fix you can do is to provide type variables that match f(x):
from typing import Any, Callable, TypeVar
import click
ArgT = TypeVar("ArgT")
ReturnT = TypeVar("ReturnT")
def format_callback(
f: Callable[[ArgT], ReturnT]
) -> Callable[[click.Context, dict[str, Any], ArgT], ReturnT]:
return lambda _, __, x: f(x)
This will guard you against bad typing in the internal body of format_callback.
A brief scan of click seems to indicate that you want to pass the return value of format_callback to one of the following class constructors or their subclass constructors:
click.core.Parameter.__init__::callback:
callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]]
click.core.Command.__init__::callback
callback: t.Optional[t.Callable[..., t.Any]]
Now, based on the other answer that you linked to, which passes the keyword argument callback to #click.argument and #click.option, it seems like you'd actually want to use click.core.Parameter.__init__, because the decorators' fallback classes are ArgumentClass = click.core.Argument and OptionClass = click.core.Option, respectively, which are both subclasses of click.Core.Parameter. This means that the second argument to the return Callable type cannot be dict[str, Any], according to the type annotation for click.core.Parameter.__init__::callback. Then, you really should have this instead:
def format_callback(
f: Callable[[ArgT], ReturnT]
) -> Callable[[click.Context, click.Parameter, ArgT], ReturnT]:
return lambda _, __, x: f(x)
Since you're discarding click.Context and click.Parameter as _, __ in your lambda, providing these are only for documentation purposes, of course. They could easily be object, object instead.
case class User(id: Int)
def Transform(u: User): String = u.id.toString()
def Process[A](f: A => String): String = "hello"
val u = User(123)
println(Process(u => Transform(u))) // Scenerio#1 works fine
println(Process(Transform(u))) // error
println(Process[User](Transform(u))) // error
I'm a little confused as to why I need the => in Scenerio#1
I have a function Process that takes a function. The function requires:
a parameter of type A
return value of String.
Now I have a function named Transform that takes a parameter of type A (a User) and returns a string.
Why can't I pass in:
Process(Transform(u))
I am passing it a function that meets the requirements am I not? (I guess not but I don't understand!)
I guess I still don't understand what the following notation really means:
Process(u => Transform(u))
As you already noticed, Transform is of type User => String, therefore, you can just pass it as a parameter to Process:
val process1: String = Process(u => Transform(u))
val process2: String = Process(Transform)
val process3: String = Process[User](Transform)
All of the above are exactly the same, and outputs hello.
def Process[A](f: A => String) method in your code is expecting a function definition as argument whose input parameter type should A and return type should be String.
Case 1:
println(Process(u => Transform(u)))
You are passing function definition so it is working fine as per expectation.
Case 2:
println(Process(Transform(u))) // error
println(ProcessUser) // error
You are not passing function definition here as expected by Process function instead you are passing the function call Transform(u) which will return the value and pass as argument to Process function.
You can refer high order function in scala using this link (https://docs.scala-lang.org/tour/higher-order-functions.html).
I have a method that with the implicit parameter. i get a error when i convert it to function in 2 case :
1:
def action(implicit i:Int) = i + " in action"
val f = action _
then i get a StackOverflowError.
2:
def action(implicit i:Int) = i + " in action"
val f = action(_)
then i get a error: missing parameter type
I must write like this :
val f = (i:Int) => action(i)
that's ok. And if the parameter of 'action' is not the implicit , all case are right. So how to explain , and what i miss ?
If you specify a parameter to a function to be implicit, you are inviting the compiler to supply the value of that parameter for you. So how does the compiler find those values? It looks for values of the same type (Int in your case) that have been declared as implicit values in a variety of scopes.
(For simplicity, I'll just use a local scope in this example, but you might want to read up on this topic. Programming in Scala, 3rd Ed is a good first step.)
Note that the names of the implicit values are ignored and have no bearing on proceedings, the compiler only looks at the types of implicit values. If multiple implicit values with the required type are found in the same scope, then the compiler will complain about ambiguous implicit values.
For example, the following provides a function with an implicit parameter and a default value for that parameter within the current scope:
def greetPerson(name: String)(implicit greeting: String) = s"$greeting $name!"
implicit val defaultGreeting = "Hello" // Implicit value to be used for greeting argument.
val y = greetPerson("Bob") // Equivalent to greetPerson("Bob")(defaultGreeting).
val z = greetPerson("Fred")("Hi")
Note that y is just a String value of "Hello Bob!", and z is a string with the value "Hi Fred!"; neither of them are functions.
Also note that greetPerson is a curried function. This is because implicit parameters cannot be mixed with regular, non-implicit parameters in the same parameter list.
In general, it's bad practice to use common types (Int, Boolean, String, etc.) as values for implicit parameters. In a big program, there might be a lot of different implicit values in your scope, and you might pick up an unexpected value. For that reason, it's standard practice to wrap such values in a case class instead.
If you're trying to create a value that supplies some of the arguments of another function (that is, a partially applied function), then that would look something like this:
def greetPerson(greeting: String, name: String) = s"$greeting $name!"
val sayHello = greetPerson("Hello", _: String)
val y = sayHello("Bob") // "Hello Bob!"
val sayHi = greetPerson("Hi", _: String)
val z = sayHi("Fred") // "Hi Fred!"
In both cases, we're creating partially applied functions (sayHi and sayHello) that call greetPerson with the greeting parameter specified, but which allow us to specify the name parameter. Both sayHello and sayHi are still only values, but their values are partially applied functions rather than constants.
Depending upon your circumstances, I think the latter case may suit you better...
I would also read up on how the underscore character (_) is used in Scala. In a partially applied function declaration, it corresponds to the arguments that will be provided later. But it has a lot of other uses too. I think there's no alternative to reading up on Scala and learning how and when to use them.
In Scala, why would this overload be allowed?
class log {
def LogInfo(m: String, properties: Map[String, String]): Unit = {
println(m)
}
def LogInfo(m: String, properties: Map[String, String], c: UUID = null): Unit = {
println(m + c.toString())
}
}
In the second definition of the LogInfo function, I have set the extra parameter to a default value of null. When I make the following call, it will call the first overload.
val l: log = new log()
val props: Map[String, String] = Map("a" -> "1")
l.LogInfo("message", props)
Why would it not throw an exception? With a default value, I would have thought both definitions could look the same.
An exception wouldn't be thrown here because the compiler chooses the first overload as the applicable one. This has to do with the way overload resolution works with default arguments. As per the specification, a strong hint to the fact such methods are discarded would be the following line:
Otherwise, let CC be the set of applicable alternatives which don't employ any default argument in the application to e1,…,em.
This has to do with the way the Scala compiler emits JVM byte code for these two methods. If we compile them and look behind the curtains, we'll see (omitting the actual byte code for brevity):
public class testing.ReadingFile$log$1 {
public void LogInfo(java.lang.String,
scala.collection.immutable.Map<java.lang.String, java.lang.String>);
Code:
public void LogInfo(java.lang.String,
scala.collection.immutable.Map<java.lang.String, java.lang.String>,
java.util.UUID);
Code:
public java.util.UUID LogInfo$default$3();
Code:
0: aconst_null
1: areturn
}
You see that the generated code actually emitted two methods, one taking two arguments and one taking three. Additionaly, the compiler added an additional method called LogInfo$default$3 (the name actually has a meaning, where $3 means "the default parameter for the third argument), which returns the default value for the c variable of the second overload. If the method with the default argument was to be invoked, LogInfo$default$3 would be used to introduce a fresh variable with the given value.
Both methods are applicable, but overloading resolution specifically tosses out the application that requires default args:
applicable alternatives which don't employ any default argument
http://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#overloading-resolution
As to "why", imagine the overload has many default parameters, such that most applications of it don't look like invocations of the first method.
My requirement is to return a function from another function in scala which takes variable argument i.e while executing the returned function , i can pass multiple argument at runtime.
My code looks like :
object VarArgTest {
def getFunction(): (Map[String, String],Map[String, Any]*) => Any={
(arg:Map[String,String], arg2:Map[String,Any]*) => "random"//this gives compilation error
}
}
In code , i want to return a function which take , Map[String,String] as one argument ,while the other Map[String,Any] should be optional to it.
But i get compilation error in return statement as follow:
type mismatch; found : (Map[String,String], Map[String,Any]) required: (Map[String,String], Map[String,Any]*) ⇒ Any
Can anyone help , what have i missed here?
Note: My requirement is that returned function can take either one argument (Map[String,String]) or it can take two arguments max (Map[String,String], Map[String,Any])
Thanks
It's impossible to use varargs in anonymous function.
You can get your piece of code working by making the returned function nested instead of anonymous like this:
object VarArgTest {
def getFunction(): (Map[String, String],Map[String, Any]*) => Any = {
def nestedFunction(arg:Map[String,String], arg2:Map[String,Any]*) = "random"
nestedFunction
}
}
However since you don't need multiple instances of Map[String, Any] but either none or one, you would be better off using Option[Map[String, Any]], providing None when it is not needed.