Получить переопределенные функции подкласса - PullRequest
18 голосов
/ 24 октября 2019

Есть ли способ получить все переопределенные функции подкласса в Python?

Пример:

class A:
    def a1(self):
        pass

    def a2(self):
        pass


class B(A):
    def a2(self):
        pass

    def b1(self):
        pass

Здесь я хотел бы получить список ["a2"] для объектакласса B (или для самого объекта класса), поскольку класс B переопределяет только один метод, а именно a2.

Ответы [ 4 ]

16 голосов
/ 24 октября 2019

Вы можете получить доступ к родительским классам с помощью cls.__bases__, найти все атрибуты родителей с помощью dir и получить доступ ко всем атрибутам самого класса с помощью vars:

def get_overridden_methods(cls):
    # collect all attributes inherited from parent classes
    parent_attrs = set()
    for base in cls.__bases__:
        parent_attrs.update(dir(base))

    # find all methods implemented in the class itself
    methods = {name for name, thing in vars(cls).items() if callable(thing)}

    # return the intersection of both
    return parent_attrs.intersection(methods)
>>> get_overridden_methods(B)
{'a2'}
3 голосов
/ 24 октября 2019

Вы можете использовать кортеж __mro__, который содержит порядок разрешения метода.

Для вашего примера:

>>> B.__mro__
( <class '__main__.B'>, <class '__main__.A'>, <class 'object'>) 

Таким образом, вы можете перебрать этот кортеж и проверить,B метод также находится в одном из других классов.

0 голосов
/ 26 октября 2019

Просто, чтобы уточнить, когда вы определяете какой-либо атрибут, добавляется к __dict__ атрибуту Class:

class A:
    def a1(self):
        pass 

print('a1' in A.__dict__) # True Note: vars(A) == A.__dict__  

и для проверки, является ли атрибут методом, используйте built-in callable witch возвращает True, если объект callable (функция, метод, класс и т. д.):

 print(callable(A.__dict__['a1']))  # True

И теперь, даже если B является подклассом Aно не определил a1, что атрибут не добавляется в B.__dict__:

   class B(A):
      pass

   print('a1' in B.__dict__)  # False 

Так что, просто сравнивая значения из атрибутов __dict__, вы получите, что метод ведьмы переопределен, метод ведьмыкоторые существуют в A.__dict__ и B.__dict__

  override_method = [attr for attr in B.__dict__ if attr in A.__dict__ and callable(A.__dict__[attr])]

Примечание: Я мог бы заменить A.__dict__ на vars(A), чтобы упростить код, но я хотел показать этот специальный атрибут, которыйдобавлен python для нового разработчика Python.

0 голосов
/ 24 октября 2019
class A:

    def a1(self):
        pass

    def a2(self):
        pass


class B(A):

    def a2(self):
        super().a2()  
        pass

    def b1(self):
        pass
obj = B()

obj.a2()   # ***first give the output of parent class then child class***
...