我们如何“手动”/明确地定义一个类?

时间:2018-03-29 18:37:52

标签: python python-3.x class

以下是我将称之为“隐式”的方法来定义一个类:

class Super:
    pass

class Klass1(Super):
    a = 1
    i = 4
    def get_i(self):
        return self.i

以下是尝试“明确”定义类似上面的类:

get_i = lambda self: self.i    
dct = dict(a=1, i=4, get_i=get_i)    
Klass2 = type('Klass2', (Super,), dct)

但是,Klass1Klass2不相同,如以下测试所示:

import inspect
import types  
LambdaType = type(lambda:0)    
dollar_param_lines = ['isinstance($, types.LambdaType)',
                      'isinstance($, LambdaType)',
                      '$.__name__',
                      '$.__qualname__',
                      'type($)',
                      'inspect.isfunction($)',
                      'inspect.ismethod($)',
                      ]    
for p_line in dollar_param_lines:
    for kls_name in ('Klass1', 'Klass2'):
        # get_i = getattr(kls, 'get_i')
        unparam_line = p_line.replace('$', kls_name + '.get_i')
        result = eval(unparam_line)
        result = str(result)
        print(unparam_line.ljust(45), result)

我正在使用的python发行版的输出是:

isinstance(Klass1.get_i, types.LambdaType)    True
isinstance(Klass2.get_i, types.LambdaType)    True
isinstance(Klass1.get_i, LambdaType)          True
isinstance(Klass2.get_i, LambdaType)          True
Klass1.get_i.__name__                         get_i
Klass2.get_i.__name__                         <lambda>
Klass1.get_i.__qualname__                     Klass1.get_i
Klass2.get_i.__qualname__                     <lambda>
type(Klass1.get_i)                            <class 'function'>
type(Klass2.get_i)                            <class 'function'>
inspect.isfunction(Klass1.get_i)              True
inspect.isfunction(Klass2.get_i)              True
inspect.ismethod(Klass1.get_i)                False
inspect.ismethod(Klass2.get_i)                False

特别是,__name____qualname__不同。我们如何修改我之前给出的“显式”类定义,以便Klass2基本上是Klass2的深层副本,反之亦然。

2 个答案:

答案 0 :(得分:2)

您在类Klass1Klass2中看不到任何差异,仅在函数Klass1.get_iKlass2.get_i中。所以你问的是错误的问题。

要验证这一点,请尝试以这种方式定义Klass2

def get_i(self):
    return self.i
dct = dict(a=1, i=4, get_i=get_i)    
Klass2 = type('Klass2', (Super,), dct)

或者,或者以这种方式定义Klass

class Klass1(Super):
    a = 1
    i = 4
    get_i = lambda self: self.i    

你会发现没有任何区别了。

如果您对deflambda之间的区别感兴趣,我们可以删除所有课程内容并进行比较:

def f(): return 0
g = lambda: 0

但现在应该是显而易见的。 def语句具有要存储的名称; lambda表达式没有。事实上,你碰巧将lambda存储在一个名为g的变量中并不重要。您可以轻松地将其分配给两个变量,或者在不指定它的情况下使用它,或者将其分配给临时未命名对象的属性元素。所以它的名字只是<lambda>

如果您进一步深入研究,您会发现LambdaTypeFunctionType属于同一类型,并且这些函数的唯一属性不同是__name__和{{ 1}}。

答案 1 :(得分:1)

正如您所说,这两个类之间的唯一区别是您的__name__函数的__qualname__get_i。因此,使这两个类等效就像将这两个属性设置为正确的值一样简单:

get_i = lambda self: self.i    
get_i.__name__ = 'get_i'
get_i.__qualname__ = 'Klass2.get_i'
dct = dict(a=1, i=4, get_i=get_i)    
Klass2 = type('Klass2', (Super,), dct)

现在比较显示以下输出:

isinstance(Klass1.get_i, types.LambdaType)    True
isinstance(Klass2.get_i, types.LambdaType)    True
isinstance(Klass1.get_i, LambdaType)          True
isinstance(Klass2.get_i, LambdaType)          True
Klass1.get_i.__name__                         get_i
Klass2.get_i.__name__                         get_i
Klass1.get_i.__qualname__                     Klass1.get_i
Klass2.get_i.__qualname__                     Klass2.get_i
type(Klass1.get_i)                            <class 'function'>
type(Klass2.get_i)                            <class 'function'>
inspect.isfunction(Klass1.get_i)              True
inspect.isfunction(Klass2.get_i)              True
inspect.ismethod(Klass1.get_i)                False
inspect.ismethod(Klass2.get_i)                False