How to get the parameters' type and return type of a function?
Asked Answered
H

7

15

I'm trying to implement strong type genetic programming in python.

Is there something like these sample?

def funcA(a,b):
  return a + b
return_type(funcA)

output: <class 'Integer'>

and

def funcA(a,b):
  return a + b
parameter_type(funcA)

output: [<class 'Integer'>,<class 'Integer'>]

update:

I'm trying to generate python's expression and avoiding something cannot be evaluated like this:

funcA(20, funcA(True, "text"))
Hilbert answered 4/3, 2013 at 11:3 Comment(2)
Please update your question with the exact problem you are trying to solve, for which you think this is the solution, because in a loosely typed language like Python, this kind of paradigm doesn't make sense. You could do this if you passed around your own objects, but again I wonder the wisdom of such a requirement.Drunken
I think you meant generic, not genetic typing?Timmytimocracy
G
8

Python 3 introduces function annotations. By themselves they don't do anything, but you can write your own enforcement:

def strict(fun):
    # inspect annotations and check types on call

@strict
def funcA(a: int, b: int) -> int:
    return a + b 
Gounod answered 4/3, 2013 at 11:8 Comment(11)
Again, it's worth noting that type checking is generally a bad idea. It makes your functions less useful, and in general, doesn't really help you. In some, very specific, situations it can be useful, but shouldn't be done as a matter of course - if you want that, write Java instead.Nimble
but It's a good idea for my problem :D It's great to see python can be strong typed, strict typed and dynamic.Hilbert
Unfortunately, no check is performed at compilation type, and nothing can be done to it due to nature of the language. I would not say it looks like a classical "strong typed". Of course, you may perform any type checks you would like. But only at execution time.Detail
@Latty You say type checking is generally a bad idea, but in python isn't duck/polymorphic/lazy typing really popular? Or am I wrong? (Also am I wrong in thinking that duck, polymorphic, and lazy are all synomyms of each other when it comes to typing?)Naze
@JosieThompson Duck typing means relying on the capabilities of an object (does it have a quack() method?) to determine it's identity (if it does, it's a duck). Type checking is where you check the actual type an object was made from (Is it a Duck object?).Nimble
@GarethLatty In most cases (at least in my case), I choose the implementation language for a project, based on context, objectives and sometimes on the framework I need to use; not because I want to have specific return values. Specifying the return type makes it 100 times easier for others to read and understand some code functionality. It is not very practical to have to read through the whole documentation of a function/method, just to see how it returns what it returns. If the documentation is bad, you have to read the actual method body. I generally believe that python is an abomination.Martinson
@P.Soutzikevich I've seen plenty of failing code in strictly typed languages because generally a type doesn't tell you everything you need to know. You need good documentation either way. Not saying that types can't be useful, but duck typed languages have a place and can be extremely good for some uses.Nimble
@GarethLatty Yes, writing good documentation is my no.1 rule. I believe many of my colleagues hate it when I nag about documentation (which is all the time). Yet, bad documentation exists and will always exist, because it is in the nature of the majority of programmers, to simply not care about anything other than making the code work. I have accepted that :p My ultimate point is, that strict typing helps answer some questions quickly, in cases that documentation is insufficient.Martinson
@P.Soutzikevich Except often the typing becomes a crutch people use to excuse poor documentation - it's anecdotal, but I've come across way more Python projects with great documentation, and tons of Java projects with barebones auto-generated Javadocs. There is a culture of documentation in Python, which is in part due to it's nature. Dismissing the language because it doesn't offer that particular tool is a short-sighted view, in my opinion - and Python is the best choice for some things. I'd also be careful about throwing stones from glass houses, because Java's type system isn't perfect.Nimble
@GarethLatty Your latter comment is subjective and opinion-based. If you re-read my initial comment, you'll see that "I choose a prog. language based on the context of a project [..]" and not based on non-functional features such as strong-typing. As a matter of fact, I don't like python for a thousand reasons and yet for my MSc thesis I wrote the whole system for the project in python (hint, hint). Maybe I have offended you by calling your go-to language an abomination; but that was never my intention as it's just my personal opinion. P.S: I never mentioned Java?!? Cool metaphor thoMartinson
@P.Soutzikevich I picked Java because you had activity on the tag, but my point was that no type system is perfect. I'm not sure why you are trying to turn this into a personal argument, I just didn't think "I generally believe that python is an abomination" was a constructive comment that should go without response, but I don't want to get into some kind of language flame war. You appear to have some big issue with the language, and that's your choice, but I'm not sure why you decided to bring that in to an unrelated comment thread - it isn't productive at all.Nimble
G
19

In Python, a dynamically typed language, the type information of a function's parameters is required at runtime. In 3.3 and later, you can get the type of a function as follows:

from inspect import signature
def foo(a, *, b:int, **kwargs):
...     pass

sig = signature(foo)

str(sig)
'(a, *, b:int, **kwargs)'

str(sig.parameters['b'])
'b:int'

sig.parameters['b'].annotation
<class 'int'>

see https://docs.python.org/3/library/inspect.html#introspecting-callables-with-the-signature-object

Gringo answered 4/5, 2018 at 18:35 Comment(0)
F
14

you can check that with annotations:

>>> def func(a: str) -> int:
       # code
>>> func.__annotations__["return"]
<class 'int'>

and the same with parameters:

>>> func.__annotations__["a"]
<class 'str'>
Fortepiano answered 3/5, 2021 at 12:33 Comment(2)
Note that under certain conditions (which I haven't been able to identify), the values in the __annotations__ dict are strings, not classes.Elfish
Note that built-in functions and methods don't have this attribute, and attempting to access it will result in: AttributeError: 'builtin_function_or_method' object has no attribute '__annotations__'. Although, other objects, such as int.__add__ of type wrapper_descriptor, are also missing this attribute.Palliate
G
8

Python 3 introduces function annotations. By themselves they don't do anything, but you can write your own enforcement:

def strict(fun):
    # inspect annotations and check types on call

@strict
def funcA(a: int, b: int) -> int:
    return a + b 
Gounod answered 4/3, 2013 at 11:8 Comment(11)
Again, it's worth noting that type checking is generally a bad idea. It makes your functions less useful, and in general, doesn't really help you. In some, very specific, situations it can be useful, but shouldn't be done as a matter of course - if you want that, write Java instead.Nimble
but It's a good idea for my problem :D It's great to see python can be strong typed, strict typed and dynamic.Hilbert
Unfortunately, no check is performed at compilation type, and nothing can be done to it due to nature of the language. I would not say it looks like a classical "strong typed". Of course, you may perform any type checks you would like. But only at execution time.Detail
@Latty You say type checking is generally a bad idea, but in python isn't duck/polymorphic/lazy typing really popular? Or am I wrong? (Also am I wrong in thinking that duck, polymorphic, and lazy are all synomyms of each other when it comes to typing?)Naze
@JosieThompson Duck typing means relying on the capabilities of an object (does it have a quack() method?) to determine it's identity (if it does, it's a duck). Type checking is where you check the actual type an object was made from (Is it a Duck object?).Nimble
@GarethLatty In most cases (at least in my case), I choose the implementation language for a project, based on context, objectives and sometimes on the framework I need to use; not because I want to have specific return values. Specifying the return type makes it 100 times easier for others to read and understand some code functionality. It is not very practical to have to read through the whole documentation of a function/method, just to see how it returns what it returns. If the documentation is bad, you have to read the actual method body. I generally believe that python is an abomination.Martinson
@P.Soutzikevich I've seen plenty of failing code in strictly typed languages because generally a type doesn't tell you everything you need to know. You need good documentation either way. Not saying that types can't be useful, but duck typed languages have a place and can be extremely good for some uses.Nimble
@GarethLatty Yes, writing good documentation is my no.1 rule. I believe many of my colleagues hate it when I nag about documentation (which is all the time). Yet, bad documentation exists and will always exist, because it is in the nature of the majority of programmers, to simply not care about anything other than making the code work. I have accepted that :p My ultimate point is, that strict typing helps answer some questions quickly, in cases that documentation is insufficient.Martinson
@P.Soutzikevich Except often the typing becomes a crutch people use to excuse poor documentation - it's anecdotal, but I've come across way more Python projects with great documentation, and tons of Java projects with barebones auto-generated Javadocs. There is a culture of documentation in Python, which is in part due to it's nature. Dismissing the language because it doesn't offer that particular tool is a short-sighted view, in my opinion - and Python is the best choice for some things. I'd also be careful about throwing stones from glass houses, because Java's type system isn't perfect.Nimble
@GarethLatty Your latter comment is subjective and opinion-based. If you re-read my initial comment, you'll see that "I choose a prog. language based on the context of a project [..]" and not based on non-functional features such as strong-typing. As a matter of fact, I don't like python for a thousand reasons and yet for my MSc thesis I wrote the whole system for the project in python (hint, hint). Maybe I have offended you by calling your go-to language an abomination; but that was never my intention as it's just my personal opinion. P.S: I never mentioned Java?!? Cool metaphor thoMartinson
@P.Soutzikevich I picked Java because you had activity on the tag, but my point was that no type system is perfect. I'm not sure why you are trying to turn this into a personal argument, I just didn't think "I generally believe that python is an abomination" was a constructive comment that should go without response, but I don't want to get into some kind of language flame war. You appear to have some big issue with the language, and that's your choice, but I'm not sure why you decided to bring that in to an unrelated comment thread - it isn't productive at all.Nimble
D
4

In Python return type is not known until the call is performed and return statement is executed. It even can be different in different situations, so a brief answer is "not possible".

If you need to know the return type for certain function, you still may wrap it into some type checking code that also may expose the return type. However, that would be rather unpythonic:

def declare_return_type(t):
    def decorator(f):
        def wrapper(*a, **kw):
            res = f(*a, **kw)
            assert isinstance(res, t)
            return res
        wrapper.return_type = t
        return wrapper
    return decorator

@declare_return_type(int)
def f(a, b):
    return a + b

print f.return_type

print f(1, 2) # ok
f('a', 'b') # Assertion error

UPD: You may do the same to parameter types and check them as well.

Detail answered 4/3, 2013 at 11:14 Comment(0)
Q
0

no chance. since python uses duck typing, you could pass parameters of different types, e.g. int and int, str and str, etc. to funcA. there is no chance to tell what return type and parameter type can be without seeing actual parameters

Quiroz answered 4/3, 2013 at 11:6 Comment(0)
E
0

the best way is to use docstrings to store such information of the function and

In [49]: def funcA(a,b):
   ....:     ''' returns an int '''
   ....:     return int(a+b)
   ....:

In [50]: funcA.__doc__
Out[50]: ' returns an int '
Emee answered 4/3, 2013 at 11:6 Comment(4)
+1 for docstring, although to be fair you should have return int(a+b).Drunken
It's worth noting that forcing stuff to be of certain types is a bad idea in Python, as it makes your functions less useful.Nimble
@GarethLatty Chiming in 10 years later to say: what is the usefulness in allowing a function to accept something that will cause an error later (i.e. potentially after heavy computing, or writing incomplete results to a file, or generally using up the users time), rather than erroring early? Python has many use cases, and that blanket statement is only true for some.Cataphoresis
@KyleCarow A decade later I'd probably be a little less absolute about it, but in general I would still say checking for specific types should be a last resort, generally if possible it is best to check for the specific things you need, e.g: with an Abstract Base Class defining the interface you want, so you don't force people to use specific types when they have something that will work in-hand. In some cases it may still be necessary though (e.g: to treat strings and other iterables differently).Nimble
N
0

It is impossible to know from just the function as given that it should only be valid for integers. If you call it with integer parameters:

funcA(1, 2)

You get 3, an Integer, but what about this:

funcA("Test", "Test")

You get "TestTest", a string! This technically works, but whether or not it should be used that way is information that just doesn't exist in the code you provide.

In more modern Python, annotations provide the potentially to explicitly state this kind of information, or potentially you could try to infer it from existing usage or from the code of the function, but which of those options (if any) make sense for your use case will depend heavily on the specifics of what you want to do.

Nimble answered 4/3, 2013 at 11:8 Comment(2)
It really isn't impossible: you can use MonkeyType to infer a function's parameter types and return type.Credulity
@AndersonGreen This answer is 8 years old, so yes, there are now options here, and it may now be more viable to approach something like this, but it is worth noting—as the docs you linked point out—while you can infer those things, but that is only an inference and is likely to miss potentially valid options, or include invalid ones.Nimble

© 2022 - 2024 — McMap. All rights reserved.