Skip to content

Add .__base__ #4368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Add .__base__ #4368

wants to merge 1 commit into from

Conversation

nanfang2000
Copy link

Add CPython compatible attribute .base for retrieving base Class

Add CPython compatible attribute .__base__ for retrieving base Class
@dpgeorge
Copy link
Member

Thanks for the contribution.

Independent of whether or not this would be a good thing to add, I think the correct implementation would be to put it in py/objtype.c:type_attr(), similar to how __name__ is handled.

Also, it seems that __base__ (singular) is not documented in the Python docs, but __bases__ (plural) is: https://docs.python.org/3/library/stdtypes.html#class.__bases__ . Arguable the plural version is more useful to have because it will give all base classes in the case of multiple inheritance.

@nanfang2000
Copy link
Author

That's OK. Hope you can implement it both base and bases. I have no confidence to modify the py/objtype.c:type_attr()

@pmp-p
Copy link
Contributor

pmp-p commented Dec 21, 2018

about usefullness __base__ is a readonly attribute and its implementation has almost no cost.
meanwhile __bases__ is for modifying mro of a class and i really doubt it's usefull for everyday micropython. I think if one wants mutabilty reassigning .__class__ of instance would be more than enough but it does not work and i think it's a bug not a corner case.

test code

class null(object):
    pass

    @classmethod
    def __bases__(cls):
        stack = [cls]
        while True:
            try:
                stack.append(stack[-1].__base__)
            except:
                break
            if stack[-1] is cls:
                break
        stack.pop(0)
        stack.pop()
        return tuple(stack)


class A(null):
    a = 'a'
    b = '?'

class B(null):
    a = '?'
    b = 'b'


def stat():
    global a,b,x
    print()
    print('a', a )
    print('a.a', a.a )
    print('a.b', a.b )
    print()
    print('b', b )
    print('b.a', b.a )
    print('b.b', b.b )

    print()
    print('x',x)
    print('x.a',x.a)
    print('x.b',x.b)

a = A()
b = B()
x = A()

stat()

print("="*60)
try:
    print( x.__class__.__base__ )
except : print('no.__base__')
try:
    if not isinstance( x.__class__.__bases__ , tuple):
        raise Exception('no.__bases__')
    print( x.__class__.__bases__ )
except :
    print('no.__bases__','fixing')
    print( x.__class__.__bases__() )

x.__class__ = B

stat()

cpython

x <__main__.A object at 0x7fa7a4371c50>
x.a a
x.b ?
============================================================
<class '__main__.null'>
(<class '__main__.null'>,)

x <__main__.B object at 0x7fa7a4371c50>
x.a ?
x.b b

micropython

x <A object at 7f7aa1b0d5a0>
x.a a
x.b ?
============================================================
<class 'null'>
no.__bases__

[...]
x <A object at 7f7aa1b0d5a0>  # <========= should be B
x.a a
x.b ?

@pmp-p
Copy link
Contributor

pmp-p commented Dec 21, 2018

__base__ allows a naive read only __bases__() if really needed

    @classmethod
    def __bases__(cls):
        stack = [cls]
        while True:
            try:
                stack.append(stack[-1].__base__)
            except:
                break
            if stack[-1] is cls:
                break
        stack.pop(0)
        stack.pop()
        return tuple(stack)

related #4993 #5106

@pfalcon
Copy link
Contributor

pfalcon commented Dec 21, 2018

Independent of whether or not this would be a good thing to add

Well, in the context of #4309, may be useful, but indeed, should be a real documented thing (i.e. __bases__), and per the best practices, should have its own config option (default off) and tests.

@nanfang2000
Copy link
Author

agree with Paul, we can implement 'base' first than 'bases'since multi-inherit is not fully supported in MPY.
if really need 'bases' then we can use a native version Paul shows above.

@dpgeorge
Copy link
Member

Closing in favour of #5139 (adds __bases__).

@dpgeorge dpgeorge closed this Oct 16, 2019
@dpgeorge
Copy link
Member

8f9e2e3 added __bases__

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants