11

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"))
  • 1
    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. – Burhan Khalid Mar 04 '13 at 11:05

7 Answers7

17

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

Brian C.
  • 6,455
  • 3
  • 32
  • 42
11

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'>
Mio
  • 121
  • 1
  • 3
  • Note that under certain conditions (which I haven't been able to identify), the values in the `__annotations__` dict are strings, not classes. – darda Aug 04 '23 at 20:36
  • 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. – Vessel Aug 24 '23 at 00:59
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 
Pavel Anossov
  • 60,842
  • 14
  • 151
  • 124
  • 2
    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. – Gareth Latty Mar 04 '13 at 11:12
  • 2
    but It's a good idea for my problem :D It's great to see python can be strong typed, strict typed and dynamic. –  Mar 04 '13 at 11:45
  • 3
    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. – Ellioh Mar 04 '13 at 11:53
  • @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?) – Josie Thompson Mar 19 '16 at 06:29
  • 1
    @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?). – Gareth Latty Mar 19 '16 at 06:33
  • @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. – Soutzikevich Mar 12 '19 at 12:42
  • @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. – Gareth Latty Mar 12 '19 at 12:58
  • @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. – Soutzikevich Mar 12 '19 at 13:02
  • @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. – Gareth Latty Mar 13 '19 at 18:28
  • 5
    @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 tho** – Soutzikevich Mar 18 '19 at 13:16
  • @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. – Gareth Latty Mar 18 '19 at 14:59
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.

Ellioh
  • 5,162
  • 2
  • 20
  • 33
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

gefei
  • 18,922
  • 9
  • 50
  • 67
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 '
avasal
  • 14,350
  • 4
  • 31
  • 47
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.

Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
  • It really isn't impossible: you can use [MonkeyType](https://monkeytype.readthedocs.io/en/stable/) to infer a function's parameter types and return type. – Anderson Green Aug 07 '21 at 19:48
  • @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. – Gareth Latty Aug 08 '21 at 21:38