V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
Cheez
V2EX  ›  问与答

Python 如何重载?

  •  
  •   Cheez ·
    PRO
    · Jul 21, 2018 · 3458 views
    This topic created in 2841 days ago, the information mentioned may be changed or developed.

    我想要这样的效果:

    ans.vote --> 返回数目 ans.vote() --> 赞同答案

    可是具体操作时却这样: TypeError: 'NoneType' object is not callable

    Supplement 1  ·  Jul 21, 2018
    class Ans(object): 
    
        def __init__(self ):
            pass
    
        def vote(self):
            print('赞同他')
    
        @property
        def vote(self):
            print('获取赞同'+str(self._vote))
             
    
    Ans().vote
    >> '获取赞同9'
    Ans().vote(2)
    >>TypeError: 'NoneType' object is not callable
    

    我又试了一下:

    class aaa(object): 
        def __init__(self):
            pass
    
        def __get__(self, instance, owner):
            print('get')
    
        def __call__(self, *arg):
            print('call')
    
    
    class ccc(object):
        """docstring for ccc"""
        a = aaa() 
    
        def __init__(self):
            pass
     
    aaa()()
    >> get
    ccc().a
    >> get
    ccc().a()
    >> TypeError: 'NoneType' object is not callable
    
    Supplement 2  ·  Jul 21, 2018
    def intcan(call):
        def allcan_func(f):
    
            class allcan_class(int):
                def __call__(self, instance, *args, **kwargs):
    
                    return call(instance)
    
                def __get__(self, instance, owner):
                    return allcan_class(f(instance))
            return allcan_class()
        return allcan_func
    

    最后用这个装饰器实现了ans.vote,ans.vote()的功能

    但是有个问题,调用ans.vote的时候会自动调用ans.vote值的相关代码,不知道怎么解决

    Supplement 3  ·  Jul 22, 2018
    因为问题始终无法解决,最后换成了这种写法:
    ```
    def vote(self):
    print('赞同他')
    self.vote.__dict__['count'] = self._vote
    return self

    ```
    调用的时候:
    ```
    print('方法')
    print(Article('37208344').vote())
    print('属性')
    print(Article('37208344').vote.count)
    ```
    25 replies    2018-07-22 13:14:35 +08:00
    hlwjia
        1
    hlwjia  
    PRO
       Jul 21, 2018
    你的 ans 是 None ?
    mimzy
        2
    mimzy  
       Jul 21, 2018
    Python 没有重载(可能不严格,请指正),因为有可变参数和默认参数。

    你的 ans 或者实例中的某些东西是 None
    Cheez
        3
    Cheez  
    OP
    PRO
       Jul 21, 2018
    不是 None,具体见附言.
    Trim21
        5
    Trim21  
       Jul 21, 2018   ❤️ 1
    class vote(int):
    def __call__(self, *args, **kwargs):
    print('vote')

    pass


    class a(object):
    vote = vote(1)


    ans = a()
    print(ans.vote)
    ans.vote()
    u2386
        6
    u2386  
       Jul 21, 2018   ❤️ 2
    附言里加了 property 的 vote 覆盖了上一个 vote 方法,并且只有 print,没有 return,所以调用这个方法返回是个 None。
    Cheez
        7
    Cheez  
    OP
    PRO
       Jul 21, 2018
    最后这样好了

    ```

    def intcan(call):
    def allcan_func(f):

    class vote(int):
    def __call__(self, *args, **kwargs):

    return call()

    def __get__(self, instance, owner):
    return vote(f())
    return vote()
    return allcan_func
    ```

    就是很不优雅(笑哭
    @u2386 #6
    @Trim21
    ipwx
        8
    ipwx  
       Jul 21, 2018
    强烈反对楼主的做法。
    Cheez
        9
    Cheez  
    OP
    PRO
       Jul 21, 2018 via Android
    @ipwx 怎么了
    yezhiye
        10
    yezhiye  
       Jul 21, 2018 via Android
    这样做挺奇怪的,因为可以定义函数 func def func()...然后 a = func,这样就可以通过 a()执行 func。如果名字一样的话就覆盖了。
    Cheez
        11
    Cheez  
    OP
    PRO
       Jul 21, 2018
    @yezhiye #10

    zhihu.vote()
    zhihu.vote

    两个一个赞同,一个获取赞同,这不是很爽嘛
    Cheez
        12
    Cheez  
    OP
    PRO
       Jul 21, 2018
    def intcan(call):
    def allcan_func(f):

    class allcan_class(int):
    def __call__(self, instance, *args, **kwargs):

    return call(instance)

    def __get__(self, instance, owner):
    return allcan_class(f(instance))
    return allcan_class()
    return allcan_func
    最后用这个装饰器实现了 ans.vote,ans.vote()的功能

    但是有个问题,调用 ans.vote 的时候会自动调用 ans.vote 值的相关代码,不知道怎么解决
    @Trim21 #5
    @yezhiye
    @ipwx #8
    @u2386 #4
    Trim21
        13
    Trim21  
       Jul 21, 2018
    @Cheez #12 这里没必要重载__get__吧...
    Cheez
        14
    Cheez  
    OP
    PRO
       Jul 21, 2018
    @Trim21 #13

    def vote_call(self):
    print('赞同他')

    @varCan(vote_call)
    def vote(self):
    print('获取赞同'+str(self._vote))
    return self._vote

    get 的时候也是要调用一个函数计算得到值的
    Trim21
        15
    Trim21  
       Jul 21, 2018
    @Cheez #14 为什么不直接用两个类呢...
    这种写法没感觉相比用两个类有什么优势...
    方便自定义__call__?
    Cheez
        16
    Cheez  
    OP
    PRO
       Jul 21, 2018
    @Trim21 #15
    调用的时候比较方便一点 TAT
    mingyun
        17
    mingyun  
       Jul 21, 2018
    函数里定义类 python 有点怪
    gnijuohz
        18
    gnijuohz  
       Jul 21, 2018 via iPhone
    不太明白为什么非要都用 vote 这词

    从语法上讲名词( property )用 votes 这个复数形式更恰当
    然后进行投票用 vote
    wangyongbo
        19
    wangyongbo  
       Jul 21, 2018   ❤️ 1
    这两天升级 django , 从 1.8 升级到 支持 python2.7 的最后一个版本 1.11.
    发现
    "Using user.is_authenticated() and user.is_anonymous() as a method "
    "is deprecated. Remove the parentheses to use it as an attribute.",
    之前的使用方法:user.is_authenticated()
    现在的使用方法:user.is_authenticated

    我看了一下 django 的实现方法

    ```
    class User():

    @property
    def is_authenticated(self):
    return CallableFalse

    ```
    首先用 property 把它变成了一个属性,但是返回的不是一个 bool, 是一个有__call__ 的对象

    CallableFalse = CallableBool(False)


    ```
    class CallableBool:
    """
    An boolean-like object that is also callable for backwards compatibility.
    """
    do_not_call_in_templates = True

    def __init__(self, value):
    self.value = value

    def __bool__(self):
    return self.value

    def __call__(self):
    warnings.warn(
    "Using user.is_authenticated() and user.is_anonymous() as a method "
    "is deprecated. Remove the parentheses to use it as an attribute.",
    RemovedInDjango20Warning, stacklevel=2
    )
    return self.value

    def __nonzero__(self): # Python 2 compatibility
    return self.value

    def __repr__(self):
    return 'CallableBool(%r)' % self.value

    def __eq__(self, other):
    return self.value == other

    def __ne__(self, other):
    return self.value != other

    def __or__(self, other):
    return bool(self.value or other)

    def __hash__(self):
    return hash(self.value)

    ```


    你觉得这种实现方式 怎么样?

    出了 这种需要兼容的代码, 再也没有见过 类似的代码了。
    ipwx
        21
    ipwx  
       Jul 22, 2018 via iPhone
    @Cheez 如果我想拿 vote 这个函数对象怎么办?
    Cheez
        22
    Cheez  
    OP
    PRO
       Jul 22, 2018 via Android
    @ipwx 拿来好像也没什么用...
    Cheez
        23
    Cheez  
    OP
    PRO
       Jul 22, 2018
    因为问题始终无法解决,最后换成了这种写法:
    ```
    def vote(self):
    print('赞同他')
    self.vote.__dict__['count'] = self._vote
    return self

    ```
    调用的时候:
    ```
    print('方法')
    print(Article('37208344').vote())
    print('属性')
    print(Article('37208344').vote.count)
    ```
    @ipwx #21
    @wangyongbo #19
    @Trim21 #15
    laike9m
        24
    laike9m  
       Jul 22, 2018 via Android
    这接口设计也是醉了,弄个叫 vote_count 的 property 不好么
    Trim21
        25
    Trim21  
       Jul 22, 2018 via Android
    @Cheez …那为什么不写两个 class 呢…满足你最一开始的要求,还比现在这样好
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2650 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 52ms · UTC 13:06 · PVG 21:06 · LAX 06:06 · JFK 09:06
    ♥ Do have faith in what you're doing.