Discuss / Python / 廖大?为什么我的类是callable,而该类的对象却不是呢?

廖大?为什么我的类是callable,而该类的对象却不是呢?

Topic source

久疤_796

#1 Created at ... [Delete] [Delete and Lock User]
>>> def Stu(object):
    def __init__(self,name):
        self.name = name
    def __call__(self):
        return self.name


>>> s = Stu('Lance')
>>> s
>>> s()
Traceback (most recent call last):
  File "<pyshell#53>", line 1, in <module>
    s()
TypeError: 'NoneType' object is not callable
>>> dir(s)
['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> callable(s)
False
>>> dir(Stu)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> callable(Stu)
True
>>>

久疤_796

#2 Created at ... [Delete] [Delete and Lock User]

打扰廖大了。是我太不认真了,我错了,写成了def了,应该是class,还纠结了这么久。。。

久疤_796

#3 Created at ... [Delete] [Delete and Lock User]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'定制类'

__author__ = 'HZF'

import os

'__str__'
class Stu1(object):
    def __init__(self,name):
        self.__name = name

class Stu2(object):
    def __init__(self,name):
        self.__name = name
    def __str__(self):
        return 'Stu2 object (name:%s)'%self.name
    @property
    def name(self):
        return self.__name

'__repr__'
class Stu3(object):
    def __init__(self,name):
        self.__name = name
    def __str__(self):
        return 'Stu3 object (name:%s)'%self.name
    __repr__ = __str__
    @property
    def name(self):
        return self.__name

'__iter__'#如果要一个类能够被用于for...in循环
class Fib(object):
    def __init__(self,limit=100000):
        self.__a = 0
        self.__b = 1
        self.__limit = limit
    def __str__(self):
        return '%s object (limit:%d)'%(self.__class__.__name__,self.__limit)
    __repr__ = __str__
    def __iter__(self):
        return self
    def __next__(self):
        self.__a,self.__b = self.__b,self.__a+self.__b
        if self.__a > self.__limit:
            raise StopIteration()
        return self.__a
'''
Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行
'Fib' object does not support indexing
这时,__getitem__就有用了
'''
'__getitem__'
class Fib2(object):
    def __init__(self,limit=10**100):
        self.__a = 0
        self.__b = 1
        self.__limit = limit
    def __str__(self):
        return '%s object (limit:%d)'%(self.__class__.__name__,self.__limit)
    __repr__ = __str__
    def __iter__(self):
        return self
    def __next__(self):
        self.__a,self.__b = self.__b,self.__a+self.__b
        if self.__a > self.__limit:
            raise StopIteration()
        return self.__a
    def __getitem__(self,n):
        a,b = 1,1
        for i in range(n):
            a,b = b,a+b
        return a
'''
现在就可以通过角标来得到对应的元素了
但是list有个神奇的方法:切片。对于Fib2却报错
原因是__getitem__()传入的参数可能是一个int,也可能是一个切片对象slice,所以要做判断:
'''

class Fib3(object):
    def __init__(self):
        self.__a = 0
        self.__b = 1
    def __str__(self):
        return '%s object (limit:%d)'%(self.__class__.__name__,self.__limit)
    __repr__ = __str__
    def __iter__(self):
        return self
    def __next__(self):
        self.__a,self.__b = self.__b,self.__a+self.__b
        return self.__a
    def __getitem__(self,n):
        fib = self.__class__()
        if isinstance(n,int):
            for i in range(n):
                next(fib)
            return next(fib)
        if isinstance(n,slice):
            L = []
            for i in range(n.stop):
                num = next(fib)
                if i>=n.start:
                    L.append(num)
            return L

'__getattr__'
'''
正常情况下,当我们调用类的方法属性时,如果 不存在,就会报错找不到该方法或属性
要避免这种错误,除了加上该方法或属性,Python还有个机制__getattr__动态返回一个属性、方法
'''
class Stu4(object):
    def __init__(self):
        self.__name = 'HZF'
    @property
    def name(self):
        return self.__name
    def __getattr__(self,attr):
        if attr=='age':
            return 25
        if attr=='info':
            return lambda:[self.name,self.age]
'''
链式调用:利用完全动态的__getattr__
'''
class Chain(object):
    def __init__(self,path='',user='HZF'):
        self.path = path
        self.__user = user
    @property
    def path(self):
        return self.__path
    @path.setter
    def path(self,path):
        if not isinstance(path,str):
            raise ValueError('path must be a string!')
        self.__path = path
    '''
    @property
    def user(self):
        return self.__user
    @user.setter
    def user(self,user):
        self.__user = user
    '''
    def __getattr__(self,path):
        if path=='user':
            path = self.__user
        return Chain('%s/%s'%(self.path,path),self.__user)
    def __str__(self):
        return self.path
    __repr__ = __str__

'__call__'
'''
'''
class Stu5(object):
    def __init__(self,name):
        self.name = name
    def __call__(self):
        #print('My name is %s.'%self.name)
        return 'My name is %s'%self.name
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self,name):
        self.__name = name

if __name__ == '__main__':
    s1 = Stu1('Luce')
    print(s1)
    s2 = Stu2('Miao')
    print(s2)
    #但是再按下s2时得到的信息还是不爽
    s3 = Stu3('Ming')
    print(s3)
    print([x for x in Fib()])
    #print(Fib()[5])
    print(Fib2()[10**3])
    #print(Fib2()[5:10])
    print(Fib3()[0:10])

    s4 = Stu4()
    print(s4.age)
    print(s4.num)#None
    print(s4.info())

    p = Chain('help','Ming')
    print(p.user.hello.make.user)

    s5 = Stu5('Lance')
    print(s5,callable(s5),callable(Stu5))
    print(s5())

手de温度

#4 Created at ... [Delete] [Delete and Lock User]

借楼考考大家 self.b, self.a = self.a + self.b, self.b,这句写成这样呢?结果同不同呢,为什么

久疤_796

#5 Created at ... [Delete] [Delete and Lock User]
>>> a,b = 1,10
>>> a,b
(1, 10)
>>> a,b = b,a+b
>>> a,b
(10, 11)
>>> a,b = 1,10
>>> b,a = a+b,b
>>> a,b
(10, 11)
>>>

这样看来,

self.b, self.a = self.a + self.b, self.b
self.a, self.b = self.b, self.a + self.b

这两句达到的是一样的效果,并没有太大的区别,我猜self.b, self.a + self.b可能是把这两项组成的元组tuple,后赋值给另一元组self.a, self.b,实际上还是一个量赋值给另一个量,就像前面学习的return a,b实际上返回的是一个量。


  • 1

Reply