简体   繁体   中英

How can we “manually”/explicity define a class?

The following is what I will call the "implicit" way to define a class:

class Super:
    pass

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

The following is an attempt to "explicitly" define a class like the one above:

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

However, Klass1 and Klass2 are not equivalent, as the following test shows:

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)

The output for the distribution of python I am using is:

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

In particular, __name__ and __qualname__ are different. How can we modify the "explicit" class definition I gave earlier so that Klass2 is essentially a deepy copy of Klass2 and vis versa.

You're not seeing any difference in the classes Klass1 and Klass2 themselves, only in the functions Klass1.get_i and Klass2.get_i . So you're asking the wrong question.

To verify that, try defining Klass2 this way:

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

Or, alternatively, defining Klass this way:

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

You'll see that there is no difference anymore.


If you're interested in the difference between def and lambda , we can strip away all the class stuff and compare:

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

But now it should be obvious. The def statement has a name to store; the lambda expression does not. The fact that you happen to store the lambda in a variable named g after it's created doesn't matter. You could just as easily have assigned it to two variables, or used it without assigning it, or assigned it to an element of an attribute of a temporary unnamed object. So its name is just <lambda> .

If you dig into it further, you'll find that LambdaType and FunctionType are the same type, and that the only attributes of these functions that differ are __name__ and __qualname__ .

As you've said, the only difference between the two classes is the __name__ and __qualname__ of your get_i function. Thus, making the two classes equivalent is as simple as setting those two attributes to the correct values:

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)

Now the comparison shows the following output:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM