Как вы вызываете другой класс, используя класс?

#python #python-3.x #class

#python #python-3.x #класс

Вопрос:

я изучаю объектно-ориентированное программирование на Python и пытаюсь написать программу, которая вызывает класс B в качестве переменной для класса A. Могу ли я узнать, правильный ли мой подход к обработке этого?

Пример класса A

 Class A():
   _name = str
   _cost = int

   def __init__(self, _name, _cost):
       self.name = _name
       self.cost = _cost
   def name(self):
       return self.name
   def cost(self):
       return self.cost
  

Пример класса B

 Class B():
   _a = A
   def __init__(self,_a):
      self.a = _a
   def __str__(self):
      return 'Phone Model: ', a.name, 'Cost: ', a.cost
phone= B('phone_X', 100)
print(phone.__str__())
  

Заранее благодарю вас!

Комментарии:

1.Что вы здесь делаете: _name = str ? Почему вы создаете эти переменные класса (т. Е. статические)? Вы пришли с такого языка, как Java / C #? Ваш подход неверен. Например, в __str__ a не определено, вы имеете в виду self.a , но почему, опять же, вы делаете _a = A в классе B в качестве переменной класса? Вы никогда его не используете.

2. Вы определяете, B чтобы принимать один аргумент, но затем вы пытаетесь создать его как B('phone_X', 100) , так что это не удастся.

3. кстати, элементы вне метода init являются статическими элементами; они принадлежат классу. Элементы внутри метода init являются элементами объекта (self);

4. Обратите внимание, что dataclasses модуль использует синтаксис, очень похожий на то, что в настоящее время имеет OP для автоматической генерации различных методов (например __init__ ).

5. Сначала я хотел инициализировать переменную с определенным типом, но, похоже, это был неправильный подход, спасибо за разъяснение

Ответ №1:

Это должно сработать. Обратите внимание, что я упростил логику классов A и B.

 class A():

    # name and cost are constructor arguments
    def __init__(self, name, cost):
       self.name = name
       self.cost = cost
  

Мы удалили _name и _cost , потому что мы хотим присвоить значения name и cost , когда мы вызываем новый экземпляр класса A, что делается в __init__ . Итак, когда вы хотите создать экземпляр класса A, вы должны присвоить значения, подобные этому:
product = A("phoneX",5) .
Теперь у вас есть экземпляр класса A под названием «product», который имеет name = "phoneX" и cost = 5 .

 class B():

    # Passing object of A as an argument
    def __init__(self, a):

      self.a = a

    # This function should return a string
    def __str__(self):
        return 'Phone Model: '  self.a.name  ' Cost: '  str(self.a.cost)

# Instantiating object of A and passing it to B
a = A('phone_X', 100)
phone= B(a)
# Just printing the object would suffice
print(phone)
# Phone Model: phone_X Cost: 100
  

Мы удалили _a по тем же причинам, по которым мы удалили переменные _name и _cost в классе A. В __init__ для этого класса вы предполагаете, что переменная ‘a’ будет экземпляром класса A. Таким образом, у нее будет переменная name и cost .

Комментарии:

1. Похоже, что OP намеревался B принять A объект в качестве аргумента.

2. Обновлено соответствующим образом

3. Это было бы неуместно, но для OP было бы полезно, если бы вы объяснили OP, что их код делал правильно / неправильно и почему ваша версия является наилучшей практикой?

4. Я добавил комментарии к своему коду, чтобы сделать именно это. Не стесняйтесь изменять мой ответ @Rook, чтобы сделать то же самое, поскольку я также новичок в SO и не уверен, какие изменения будут полезны для OP

5. Только что отредактировал ваш пост. Я забыл объяснить операторы печати.

Ответ №2:

Те вещи, которые вы в настоящее время пытаетесь сделать в A (объявить существование и тип каждой переменной экземпляра), — это то, что dataclasses модуль поддерживает, начиная с Python 3.7.

 from dataclasses import dataclass

@dataclass
class A():
   name: str
   cost: int
  

В Python нет необходимости определять метод, который ничего не делает, кроме как возвращает значение атрибута экземпляра; просто получите доступ к атрибуту напрямую.

 @dataclass
class B():
    _a: A

    def __str__(self):
        return f'Phone Model: {self._a.name}, Cost: {self._a.cost}'
  

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

 phone = B(A('phone_X', 100))
print(str(phone))
  

Комментарии:

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

2. спасибо за совет, я рассмотрю использование dataclass

3. Либо return 'Phone Model: {}, Cost: {}'.format(self._a.name, self._a.cost) , либо return f'Phone Model: {self._a.name}, Cost: {self._a.cost}') . 2-й вариант более элегантный, имхо, и, учитывая, что вы предлагаете классы данных, тогда f-строки отлично поддерживаются

4. Согласен; большая часть кода, над которым я работаю, все еще находится в процессе перехода с Python 2 на Python 3, поэтому f-строки еще не первое, о чем я думаю для форматирования строк.