V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
deepreader
V2EX  ›  Python

Python 3 用元编程和 typehints 实现类函数重载 - Pover

  •  
  •   deepreader · 2018-12-14 15:25:32 +08:00 · 1527 次点击
    这是一个创建于 2166 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Python 是有名的动态类型语言,本身不支持函数重载。

    class Foo:
        def add(self, a):
            pass 
            
        def add(self, a, b):
        	# 会覆盖上面已经定义类函数
            pass
          
    

    然而使用元编程 (meta-programming) 和 python 3.5+ 的 type hints,可以实现类函数重载。

    然后写了一个库:pover - Python OVERload

    pip3 install pover
    

    使用一个 metaclass OverloadMeta实现类函数重载。

    #!/usr/bin/env python3
    import unittest
    import pover
    
    
    class Foo(metaclass=pover.OverloadMeta):
        def add(self, a: int):
            return a + 1
    
        def add(self, a: list):
            return a + [1]
    
        def add(self, a: set):
            a.add(1)
            return a
    
        def minus(self, a: int):
            return a - 1
    
        def minus(self, a: str):
            return a[:-1]
    
    
    class OverloadTest(unittest.TestCase):
        def test_overload(self):
            foo = Foo()
            self.assertEqual(foo.add(1), 2)
            self.assertEqual(foo.add([0]), [0, 1])
            self.assertEqual(foo.add({0}), {0, 1})
            self.assertEqual(foo.minus(1), 0)
            self.assertEqual(foo.minus("hello"), "hell")
    

    具体实现原理在: https://github.com/idf/pover/blob/master/pover/core.py

    GitHub 地址,请多指教: https://github.com/idf/pover

    10 条回复    2018-12-15 11:11:56 +08:00
    Kilerd
        1
    Kilerd  
       2018-12-14 16:26:59 +08:00
    deepreader
        2
    deepreader  
    OP
       2018-12-14 16:33:14 +08:00
    @Kilerd 了解过,`singledispatch` 没法 dispatch 类函数吧。singledispatch decorator renames module functions,这个机制并不使用类函数。
    xpresslink
        3
    xpresslink  
       2018-12-14 16:35:43 +08:00
    from functools import singledispatch

    @singledispatch
    def add(a:object): pass

    @add.register(int)
    def _add(a: int): return a + 1

    @add.register(list)
    def _add(a: list): return a + [1]

    @add.register(set)
    def _add(a: set): a.add(1); return a

    cases=[1, [0], {0}]
    for case in cases: print(add(case))
    xpresslink
        4
    xpresslink  
       2018-12-14 16:39:50 +08:00
    实现上由于 python 是动态语言,传递对象是鸭子类型又可以变长参数,所以用上方法重载的机会不太多。
    java 那个有名的 23 种设计模式,大约有 16 种设计模式在动态语言里面根本就不需要了。
    deepreader
        5
    deepreader  
    OP
       2018-12-14 16:54:04 +08:00 via iPhone
    @xpresslink single dispatch 是不错,但是不适合类函数吧?见#2
    xpresslink
        6
    xpresslink  
       2018-12-14 17:13:12 +08:00
    @deepreader 当然可以用在类函数了。
    ffffish
        7
    ffffish  
       2018-12-14 17:32:25 +08:00
    蛋总牛逼
    deepreader
        8
    deepreader  
    OP
       2018-12-15 01:03:31 +08:00 via iPhone
    @xpresslink show me the code.

    Decorator invocation 是在类函数 invocation 时执行的的,类函数 definition 的时候同函数名已经在 class construction 被覆盖了。
    deepreader
        9
    deepreader  
    OP
       2018-12-15 01:04:24 +08:00 via iPhone
    @ffffish
    xpresslink
        10
    xpresslink  
       2018-12-15 11:11:56 +08:00
    @deepreader 当然要静态方法调用啊,直接 类名.方法()
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3650 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 04:33 · PVG 12:33 · LAX 20:33 · JFK 23:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.