development

Python 3 및 정적 타이핑

big-blog 2020. 12. 25. 22:46
반응형

Python 3 및 정적 타이핑


저는 제가 원하는만큼 Python 3의 개발에 많은 관심을 기울이지 않았고 단지 몇 가지 흥미로운 새로운 구문 변경 사항을 발견했습니다. 구체적으로 ,이 SO 응답 함수 파라미터 주석 :

def digits(x:'nonnegative number') -> "yields number's digits":
    # ...

이것에 대해 아무것도 모르기 때문에 파이썬에서 정적 타이핑을 구현하는 데 사용될 수 있다고 생각했습니다!

일부 검색 후, 같은 언급과 파이썬 (전체 옵션) 정적 타이핑에 관한 많은 토론이있을 것 같았다 PEP (3107) , 및 "파이썬 옵션 정적 타이핑 추가" (와 2 부 )

.. 그러나 이것이 얼마나 발전했는지는 확실하지 않습니다. 매개 변수 주석을 사용하는 정적 유형의 구현이 있습니까? 매개 변수화 된 유형의 아이디어가 Python 3에 포함 되었습니까?


내 코드를 읽어 주셔서 감사합니다!

실제로 Python에서 일반 주석 집행자를 만드는 것은 어렵지 않습니다. 내 의견은 다음과 같습니다.

'''Very simple enforcer of type annotations.

This toy super-decorator can decorate all functions in a given module that have 
annotations so that the type of input and output is enforced; an AssertionError is
raised on mismatch.

This module also has a test function func() which should fail and logging facility 
log which defaults to print. 

Since this is a test module, I cut corners by only checking *keyword* arguments.

'''

import sys

log = print


def func(x:'int' = 0) -> 'str':
    '''An example function that fails type checking.'''
    return x


# For simplicity, I only do keyword args.
def check_type(*args):
    param, value, assert_type = args
    log('Checking {0} = {1} of {2}.'.format(*args))
    if not isinstance(value, assert_type):
        raise AssertionError(
            'Check failed - parameter {0} = {1} not {2}.'
            .format(*args))
    return value

def decorate_func(func):    
    def newf(*args, **kwargs):
        for k, v in kwargs.items():
            check_type(k, v, ann[k])
        return check_type('<return_value>', func(*args, **kwargs), ann['return'])

    ann = {k: eval(v) for k, v in func.__annotations__.items()}
    newf.__doc__ = func.__doc__
    newf.__type_checked = True
    return newf

def decorate_module(module = '__main__'):
    '''Enforces type from annotation for all functions in module.'''
    d = sys.modules[module].__dict__
    for k, f in d.items():
        if getattr(f, '__annotations__', {}) and not getattr(f, '__type_checked', False):
            log('Decorated {0!r}.'.format(f.__name__))
            d[k] = decorate_func(f)


if __name__ == '__main__':
    decorate_module()

    # This will raise AssertionError.
    func(x = 5)

이 단순함을 감안할 때 이것이 주류가 아니라는 것이 처음에는 이상합니다. 그러나 나는 그것이 보이는 것만 큼 유용하지 않은 이유가 있다고 생각 합니다 . 일반적으로 유형 검사는 정수와 사전을 추가하면 명백한 실수를 할 가능성이 있기 때문에 도움이됩니다 (합리적인 것을 의미하는 경우 암시 적보다는 명시적인 것이 더 낫습니다 ).

But in real life you often mix quantities of the same computer type as seen by compiler but clearly different human type, for example the following snippet contains an obvious mistake:

height = 1.75 # Bob's height in meters.
length = len(sys.modules) # Number of modules imported by program.
area = height * length # What's that supposed to mean???

Any human should immediately see a mistake in the above line provided it knows the 'human type' of variables height and length even though it looks to computer as perfectly legal multiplication of int and float.

There's more that can be said about possible solutions to this problem, but enforcing 'computer types' is apparently a half-solution, so, at least in my opinion, it's worse than no solution at all. It's the same reason why Systems Hungarian is a terrible idea while Apps Hungarian is a great one. There's more at the very informative post of Joel Spolsky.

Now if somebody was to implement some kind of Pythonic third-party library that would automatically assign to real-world data its human type and then took care to transform that type like width * height -> area and enforce that check with function annotations, I think that would be a type checking people could really use!


As mentioned in that PEP, static type checking is one of the possible applications that function annotations can be used for, but they're leaving it up to third-party libraries to decide how to do it. That is, there isn't going to be an official implementation in core python.

As far as third-party implementations are concerned, there are some snippets (such as http://code.activestate.com/recipes/572161/), which seem to do the job pretty well.

EDIT:

As a note, I want to mention that checking behavior is preferable to checking type, therefore I think static typechecking is not so great an idea. My answer above is aimed at answering the question, not because I would do typechecking myself in such a way.


This is not an answer to question directly, but I found out a Python fork that adds static typing: mypy-lang.org, of course one can't rely on it as it's still small endeavor, but interesting.


"Static typing" in Python can only be implemented so that the type checking is done in run-time, which means it slows down the application. Therefore you don't want that as a generality. Instead you want some of your methods to check it's inputs. This can be easily done with plain asserts, or with decorators if you (mistakenly) think you need it a lot.

There is also an alternative to static type checking, and that is to use an aspect oriented component architecture like The Zope Component Architecture. Instead of checking the type, you adapt it. So instead of:

assert isinstance(theobject, myclass)

you do this:

theobject = IMyClass(theobject)

If theobject already implements IMyClass nothing happens. If it doesn't, an adapter that wraps whatever theobject is to IMyClass will be looked up, and used instead of theobject. If no adapter is found, you get an error.

This combined the dynamicism of Python with the desire to have a specific type in a specific way.


Sure, static typing seems a bit "unpythonic" and I don't use it all the time. But there are cases (e.g. nested classes, as in domain specific language parsing) where it can really speed up your development.

Then I prefer using beartype explained in this post*. It comes with a git repo, tests and an explanation what it can and what it can't do ... and I like the name ;)

* Please don't pay attention to Cecil's rant about why Python doesn't come with batteries included in this case.

ReferenceURL : https://stackoverflow.com/questions/1275646/python-3-and-static-typing

반응형