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.