Перейти к содержимому

Как вызвать метод класса

  • автор:

Как вызвать метод другого класа в метод мейн?

Как можно вызвать метод AddPupil чтобы добавить ученика в класс? Не вижу метод другого класса если он не статик.
Что можно сделать? Как изменить когда чтобы добавить ученика в список. Еще нужно ли поле List в классе Class, или лист нужно будет создавать в Main , (при вызове метода AddPupil параметром нужно указать лист, в который хочу добавить)

Отслеживать
73.6k 110 110 золотых знаков 38 38 серебряных знаков 55 55 бронзовых знаков
задан 30 окт 2022 в 23:59
19 6 6 бронзовых знаков

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Это че с#? Почему тег не указали? Ну если в двух словах, то нужно создать экземпляр вашего Class, вызвать на нем метод AddPupil и передать в него учеников.

Коллекция конечно же должна быть внутри объекта класс, это же логично, чтоб хранить учеников внутри. Поэтому логика метода AddPupil не правильная у вас. Смысл передавать в метод объекта коллекцию класса и ученика,чтоб просто внутри добавить ученика в эту коллекцию, а потом её сохранить, нету. Это очень спецефичный случай. Зачастую вы хотите добавить в класс либо одного ученика, либо нескольких. Поэтому в main создаёте коллекцию, если вам надо, добавляете туда учеников и потом передаёт её в экземпляр класса, то есть сохраняете её в классе. И последние ваше предложение: указать параметр лист в который я хочу добавить, не совсем понятно. У вас всего один лист в классе

Покажу на примере Java может поможет , у меня там два метода с одинаковым названием AddPupil, они перегружены и срабатывают в зависимости от того какой аргумент в вызове метода, если в с# такого нет, то можно использовать разные названия методов.

 class MyClass // в java не используйте слово Class в названии < private ListPupilsList = new ArrayList<>(); public void AddPupil(Pupils pupil) < PupilsList.add(pupil); >//перегруженная версия метода для добавления колекции public void AddPupil(List pupil) < PupilsList = pupil; /* // Либо соединить две коллекции . Тогда нужно будет //импорт сделать библеотеки Stream //и удалить строку PupilsList = pupil PupilsList = Stream.concat( PupilsList.stream(), pupil.stream()).collect(Collectors.toList()); */ >public void showClass() < System.out.println(PupilsList); >> 

В методе main создаю экземпляр ученика и класса, чтоб добавить ученика в через вызов метода AddPupil экземпляра класса MyClass

 Pupils pupil = new Pupils("Vlad", 24); MyClass MyClass1 = new MyClass(); MyClass1.AddPupil(pupil); MyClass1.showClass(); // JAVA функция для создания листа на лету MyClass1.AddPupil(Arrays.asList( new Pupils("Vlad", 24),new Pupils("Dima", 27),new Pupils("Semen", 26))); //либо для с# //MyClass1.AddPupil(/* ВАШ ЛИСТ УЧЕНИКОВ КОТОРЫЙ ВЫ СОЗДАДИТЕ В MAIN*/) ; MyClass1.showClass(); 

Могут быть мелкие синтаксические ошибки так как набирал на телефоне, нет возможности запустить проверить

Arrays.asList — это для удобства, это функция создаёт лист из перечисленных объектов , а так вы должны передать List который в main создадите. В java если после добавления коллекции будете использовать добавление по одному, лучше так не делать. Насколько я помню он создаёт фиксированный лист, и вы не сможете добавить к этому списку ученика . Так что если столкнетесь с такой проблемой используйте в качестве аргумента метода AddPupil(List pupil) — ArrayList, а не Arrays.asList. Ну то есть в main создаёте полноценную коллекцию и её передаёте. Если использовать будете версию где соединение через stream идёт, то там все равно, кст можно через метод addAll, который есть у листов, соединять, но stream лучше.

Метод объекта/экземпляра класса в Python

Методы — это функции, вызываемые с использованием точечной нотации. Если обратится к методу (функции, определенной в пространстве имен класса) через экземпляр, то получим специальный объект: объект привязанного метода (также называемого методом экземпляра). При вызове он добавляет аргумент self в список аргументов.

Обычно метод вызывается сразу после его привязки:

class MyClass: """Простой пример класса""" i = 12345 def f(self): return 'hello world' x = MyClass() x.f() # 'hello world' 

В примере с классом MyClass метод экземпляра класса x.f() возвращает строку «hello world». Нет необходимости вызывать метод сразу, x.f — это объект метода класса и его можно сохранить и вызвать позже. В примере ниже — бесконечный цикл, который будет продолжать печатать «hello world».

xf = x.f while True: print(xf()) 

Что именно происходит при вызове метода? Заметили, что x.f() был вызван без аргумента? Хотя в определение функции f() был указан один аргумент self . Python всегда вызывает исключение, когда функция, требующая аргумента, вызывается без него, даже если аргумент фактически не используется…

Особенность методов заключается в том, что объект экземпляра передается в качестве первого аргумента self функции. В примере вызов x.f() в точности эквивалентен вызову MyClass.f(x) . В общем случае вызов метода со списком из n аргументов эквивалентен вызову соответствующей функции со списком аргументов, который создается путем вставки объекта экземпляра метода перед первым аргументом.

При ссылке на атрибут экземпляра, не являющийся атрибутом данных, выполняется поиск экземпляра класса. Если имя обозначает допустимый атрибут класса, который является объектом функции, объект метода создается путем упаковки указателей объекта экземпляра и объекта функции, только что найденных вместе в абстрактном объекте: это объект метода. Когда объект метода вызывается со списком аргументов, новый список аргументов создается из экземпляра класса и списка аргументов этого класса, а объект функции вызывается с этим новым списком аргументов.

Первый аргумент метода называется self . Это не более чем соглашение: имя self не имеет абсолютно никакого особого значения для Python. Обратите внимание, что не следуя соглашению, ваш код может быть менее читаемым для других программистов Python и также может быть написана некая программа для просмотра классов, которая будет основываться на этом соглашении.

Любой функциональный объект, являющийся атрибутом класса, определяет метод для экземпляров этого класса. Нет необходимости в том, чтобы определение функции было текстуально заключено в определение класса: присвоение объекта функции локальной переменной в классе также нормально.

# Функция, определенная вне класса def f1(self, x, y): return min(x, x+y) class C: f = f1 def g(self): return 'hello world' h = g 

Обратите внимание, что эта практика обычно только запутывает читателя программы. Теперь f , g и h — это все атрибуты класса C , которые относятся к функциональным объектам, и, следовательно, все они являются методами экземпляров класса C . Метод h точно эквивалентны g .

Методы могут вызывать другие методы, используя атрибуты метода собственного аргумента:

class Bag: def __init__(self): self.data = [] def add(self, x): self.data.append(x) def addtwice(self, x): self.add(x) self.add(x) 

Методы могут ссылаться на глобальные имена так же, как обычные функции. Глобальной областью видимости, связанной с методом, является модуль, содержащий его определение. Класс никогда не используется в качестве глобальной области видимости. Хотя редко встречаются веские причины для использования глобальных данных в методе, существует много законных вариантов использования глобальной области видимости. Функции и модули, импортированные в глобальную область, могут использоваться методами, а также функциями и классами, определенными в нем. Обычно класс, содержащий метод, сам определяется в этой глобальной области видимости.

Поддержка получения произвольных атрибутов методами.

Связанные методы имеют два специальных атрибута, доступных только для чтения: m.__ self__ — это объект, с которым работает метод, и m.__func__ — это функция, реализующая метод. Вызов m(arg-1, arg-2, . arg-n) полностью эквивалентен вызову m.__func__(m.__self__, arg-1, arg-2, . arg-n) .

Как и объекты функций, связанные объекты методов поддерживают получение произвольных атрибутов. Однако, поскольку атрибуты метода фактически хранятся в базовом объекте функции ( meth.__func__ ), то установка атрибутов метода для связанных методов запрещена. Попытка установить атрибут в методе приводит к возникновению исключения AttributeError . Чтобы установить атрибут метода, необходимо явно установить его для базового объекта функции:

>>> class C: . def method(self): . pass . >>> c = C() >>> c.method.whoami = 'my name is method' # can't set on the method # Traceback (most recent call last): # File "", line 1, in # AttributeError: 'method' object has no attribute 'whoami' >>> c.method.__func__.whoami = 'my name is method' >>> c.method.whoami # 'my name is method' 
  • ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
  • Пространство имен и область видимости в классах
  • Определение классов
  • Объект класса и конструктор класса
  • Создание экземпляра класса
  • Метод экземпляра класса
  • Что такое метод класса и зачем нужен
  • Что такое статический метод в классах Python и зачем нужен
  • Атрибуты класса и переменные экземпляра класса
  • Кэширование методов экземпляра декоратором lru_cache
  • Закрытые/приватные методы и переменные класса Python
  • Наследование классов
  • Множественное наследование классов
  • Абстрактные классы
  • Перегрузка методов в классе Python
  • Что такое миксины и как их использовать
  • Класс Python как структура данных, подобная языку C
  • Создание пользовательских типов данных
  • Специальные (магические) методы класса Python
  • Базовая настройка классов Python магическими методами
  • Настройка доступа к атрибутам класса Python
  • Дескриптор класса для чайников
  • Протокол дескриптора класса
  • Практический пример дескриптора
  • Использование метода .__new__() в классах Python
  • Специальный атрибут __slots__ класса Python
  • Специальный метод __init_subclass__ класса Python
  • Определение метаклассов metaclass
  • Эмуляция контейнерных типов в классах Python
  • Другие специальные методы класса
  • Как Python ищет специальные методы в классах
  • Шаблон проектирования Фабрика и его реализация

Как использовать метод из другого класса java

Чтобы использовать метод из другого класса его необходимо вызвать через объект этого класса или через имя класса, если метод статический.

// Класс, где вызываем методы другого класса public class Example  public static void main(String[] args)  // Создаем объект класса Greetings greetings = new Greetings(); // Вызываем метод greetings.printHello(); // => Hello // Вызываем статический метод Greetings.printHexlet(); // => Hexlet > > class Greetings  public void printHello()  System.out.println("Hello"); > public static void printHexlet()  System.out.println("Hexlet"); > > 

Вызов методов базового класса

Надо вызвать метод базового класса из метода, который переопределен в производном классе.

Из конструктора дочернего класса нужно явно вызывать конструктор родительского класса.

Обращение к базовому классу происходит с помощью super()

Нужно явно вызывать конструктор базового класса

class A(object): def __init__(self, x=5): print('A.__init__') self.x = x class B(A): def __init__(self, y=2): print('B.__init__') self.y = y k = B(7) # B.__init__ print('k.y =', k.y) # k.y = 7 #print('k.x =', k.x) # AttributeError: 'B' object has no attribute 'x' 

Видно, что без явного вызова конструктора класса А не вызывается A.__init__ и не создается поле x класса А.

Вызовем конструктор явно.

Конструктор базового класса стоит вызывать раньше, чем иницилизировать поля класса-наследника, потому что поля наследника могут зависеть (быть сделаны из) полей экземпляра базового класса.

class A(object): def __init__(self, x=5): print('A.__init__') self.x = x class B(A): def __init__(self, y=2): print('B.__init__') super().__init__(y/2) self.y = y k = B(7) # B.__init__ # A.__init__ print('k.y =', k.y) # k.y = 7 print('k.x =', k.x) # k.x = 3.5 

super() или прямое обращение к классу?

Метод класса можно вызвать, используя синтаксис вызова через имя класса:

class Base(object): def __init__(self): print('Base.__init__') class A(Base): def __init__(self): Base.__init__(self) print('A.__init__') k = A() # Base.__init__ # A.__init__ 

Все работает. Но при дальнейшем развитии классов могут начаться проблемы:

class Base(object): def __init__(self): print('Base.__init__') class A(Base): def __init__(self): Base.__init__(self) print('A.__init__') class B(Base): def __init__(self): Base.__init__(self) print('B.__init__') class C(A, B): def __init__(self): A.__init__(self) B.__init__(self) print('C.__init__') x = C() # Base.__init__ # A.__init__ # Base.__init__ - второй вызов # B.__init__ # C.__init__ 

Видно, что конструктор Base.__init__ вызывается дважды. Иногда это недопустимо (считаем количество созданных экземпляров класса, увеличивая в конструкторе счетчик на 1; выдаем очередное auto id какому-то нашему объекту, например, номер пропуска или паспорта или номер заказа).

То же самое через super():

  • вызов конструктора Base.__init__ происходит только 1 раз.
  • вызваны конструкторы всех базовых классов.
  • порядок вызова конструкторов для классов А и В не определен.
class Base(object): def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(A, B): def __init__(self): super().__init__() print('C.__init__') x = C() # Base.__init__ # B.__init__ - вызваны конструкторы обоих базовых классов # A.__init__ - порядок вызова # C.__init__ 

Как это работает?

Для реализации наследования питон ищет вызванный атрибут начиная с первого класса до последнего. Этот список создается слиянием (merge sort) списков базовых классов:

  • дети проверяются раньше родителей.
  • если родителей несколько, то проверяем в том порядке, в котором они перечислены.
  • если подходят несколько классов, то выбираем первого родителя.

При вызове super() продолжается поиск, начиная со следующего имени в MRO. Пока каждый переопределенный метод вызывает super() и вызывает его только один раз, будет перебран весь список MRO и каждый метод будет вызван только один раз.

Не забываем вызывать метод суперкласса

А если где-то не вызван метод суперкласса?

class Base(object): def __init__(self): print('Base.__init__') class A(Base): def __init__(self): #super().__init__() - НЕ вызываем super() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(A, B): def __init__(self): super().__init__() print('C.__init__') x = C() # A.__init__ # C.__init__ print(C.__mro__) # (, , , , ) 

Заметим, что хотя в B.__init__ есть вызов super(), то до вызова B.__init__ не доходит.

  • Вызываем у объекта класса С метод __init__.
  • Ищем его в mro и находим С.__init__. Выполняем его.
  • В этом методе вызов super() — ищем метод __init__ далее по списку от найденного.
  • Находим A.__init__. Выполняем его. В нем нет никаких super() — дальнейший поиск по mro прекращается.

Нет метода в своем базовом классе, есть у родителя моего сиблинга

Определим класс, который пытается вызвать метод, которого нет в базовом классе:

class A(object): def spam(self): print('A.spam') super().spam() x = A() x.spam() 

получим, как и ожидалось:

A.spam Traceback (most recent call last): File "examples/oop_super_3.py", line 7, in x.spam() File "examples/oop_super_3.py", line 4, in spam super().spam() AttributeError: 'super' object has no attribute 'spam' 

Определим метод spam в классе В. Класс С, наследник А и В, вызывает метод A.spam(), который вызывает B.spam — класс В не связан с классом А.

class A(object): def spam(self): print('A.spam') super().spam() class B(object): def spam(self): print('B.spam') class C(A, B): pass y = C() y.spam() print(C.__mro__) 
A.spam B.spam (, , , ) 

Для объекта класса С вызвали метод spam(). Ищем его в MRO. Находим A.spam() и вызываем. Далее для super() из A.spam() идем дальше от найденного по списку mro и находим B.spam().

Отметим, что при другом порядке описания родителей class C(B, A) , вызывается метод B.spam() у которого нет super():

B.spam (, , , ) 

Вызываем метод spam для объекта класса С. В С его нет, ищем дальше в В. Находим. Вызваем. Далее super() нет и дальнейший поиск не производится.

Чтобы не было таких сюрпризов при переопределении методов придерживайтесь правил:

  • все методы в иерархии с одинаковым именем имеют одинаковую сигнатуру вызова (количество аргументов и их имена для именованных аргументов).
  • реализуйте метод в самом базовом классе, чтобы цепочка вызовов закончилась хоть каким

Обращение к дедушке

Игнорируем родителя

Если у нас есть 3 одинаковых метода foo(self) в наследуемых классах А, В(А), C(B), и нужно из C.foo() вызвать сразу A.foo() минуя B.foo(), то наши классы неправильно сконструированы (почему нужно игнорировать В? может, нужно было наследовать С от А, а не от В?). Нужен рефакторинг.

Но можно всегда вызвать метод по имени класса:

class A(object): def spam(self): print('A.spam') class B(A): def spam(self): print('B.spam') class C(B): def spam(self): A.spam(self) print('C.spam') y = C() y.spam() print(C.__mro__) 
A.spam C.spam (, , , ) 

Метод определен только у дедушки

Если в В такого метода нет, и из C.foo() нужно вызвать A.foo() (или в базовом классе выше по иерархии), вызываем super().foo() и больше не думаем, у какого пра-пра-пра-дедушки реализован этот метод.

Просто воспользуйтесь super() для поиска по mro.

class A(object): def spam(self): print('A.spam') class B(A): pass class C(B): def spam(self): super().spam() print('C.spam') y = C() y.spam() print(C.__mro__) 
A.spam C.spam (, , , ) 

super().super() не работает

Или мы ищем какого-то родителя в mro, или точно указываем из какого класса нужно вызвать метод.

Литература

  • Документация по python
  • Python’s super() considered super!
  • Python Cookbook, chapter 8.7 Calling a Method on a Parent Class

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *