Ошибка: 'float' object is not callable при вызове функции

Есть код, который выполняет некоторые расчеты, он разделен на два класса и функции внутри них.

import math
    
    
class SimilarCalculations:
    def __init__(self, diameter, length, mass_flow_rate, viscosity, density):
        self.diameter = diameter
        self.length = length
        self.mass_flow_rate = mass_flow_rate
        self.viscosity = viscosity
        self.density = density
    
    def injector_nozzle_area(self):
        return (math.pi * self.diameter ** 2) / 4
    
    def reynolds_number(self):
        return (4 * self.mass_flow_rate) / (math.pi * self.diameter * self.viscosity)
    
    def average_speed(self):
        return self.mass_flow_rate / (self.density * self.injector_nozzle_area())


class LiquidJetInjector(SimilarCalculations):
    def __init__(self, density_comb, sigma_fuel):
        SimilarCalculations.__init__(self, diameter, length, mass_flow_rate, viscosity, density)
        self.reynolds_laminar = 2000
        self.reynolds_turbulent = 10000

        self.density_comb = density_comb
        self.sigma_fuel = sigma_fuel
   
        self.reynolds_number = super().reynolds_number()
        self.injector_nozzle_area = super().injector_nozzle_area()
        self.average_speed = super().average_speed()
    
    def linear_hydraulic_resistance(self):
        if self.reynolds_number < self.reynolds_laminar:
            return 64 / self.reynolds_number
    
        elif self.reynolds_laminar <= self.reynolds_number <= self.reynolds_turbulent:
            return 0.3164 * self.reynolds_number ** (-0.25)
    
        else:
            return 0.031
    
    def injector_losses_inlet(self):
        if self.reynolds_number < self.reynolds_laminar:
            return 2.2 - 0.726 * math.exp(-74.5 * ((self.viscosity * self.length) / self.mass_flow_rate))
        else:
            return 1 + 2.65 * self.linear_hydraulic_resistance()
    
    def injector_flow_coefficient(self):
        return 1 / (math.sqrt(self.injector_losses_inlet() + self.linear_hydraulic_resistance() *
                                  (self.length / self.diameter)))
    
    def pressure_drop_injector(self):
        return self.mass_flow_rate ** 2 / (2 * self.density * self.injector_flow_coefficient() ** 2 *
                                           self.injector_nozzle_area ** 2)
    
    def weber_criterion(self):
        return (self.density_comb * self.average_speed ** 2 * self.diameter) / self.sigma_fuel
    
    def media_diameter_spray_droplets(self):
        return self.diameter * round(math.pow((27 * math.pi) / 4, 1 / 3.)) * self.weber_criterion() ** (-0.333)



diameter = 0.001
length = 0.01
mass_flow_rate = 0.01899
viscosity = 0.00116
density = 1315
density_comb = 0.1
sigma_fuel = 0.5
calc = SimilarCalculations(diameter, length, mass_flow_rate, viscosity, density)
calc_2 = LiquidJetInjector(density_comb, sigma_fuel)
print(calc.injector_nozzle_area())
print(calc_2.pressure_drop_injector())

Если запустить данный код в данной конфигурации, то он выдаст ошибку:

Traceback (most recent call last):
  File "G:\LARIS\src\jet_injector_calc.py", line 79, in <module>
    calc_2 = LiquidJetInjector(density_comb, sigma_fuel)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "G:\LARIS\src\jet_injector_calc.py", line 33, in __init__
    self.average_speed = super().average_speed()
                         ^^^^^^^^^^^^^^^^^^^^^^^
  File "G:\LARIS\src\jet_injector_calc.py", line 19, in average_speed
    return self.mass_flow_rate / (self.density * self.injector_nozzle_area())
                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'float' object is not callable

Но, если в строчке 19 заменить self.injector_nozzle_area() на self.injector_nozzle_area, то код будет корректно работать без ошибок.
Почему так происходит?


Ответы (1 шт):

Автор решения: CrazyElf

Почему выходит ошибка вам написали в комментарии - вы перекрываете унаследованную функцию результатом её вызова.

При этом, судя по всему, вам вообще не нужно наследование, лучше просто инициализируйте класс для вычислений и пользуйтесь им где вам нужно, например как у вас сейчас в конструкторе:

class LiquidJetInjector():
    def __init__(self, density_comb, sigma_fuel):
        self.calc = SimilarCalculations(diameter, length, mass_flow_rate, viscosity, density)
        ...
        self.reynolds_number = self.calc.reynolds_number()
        self.injector_nozzle_area = self.calc.injector_nozzle_area()
        self.average_speed = self.calc.average_speed()

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

Наследование нужно для других вещей - для расширения функционала базового класса. В вашем же случае достаточно того, что называется композицией. Пример я привёл выше - просто инициализируете нужный вам класс в конструкторе, и пользуетесь им.

Кстати, очень странно, что часть переменных вы прямо передали в класс LiquidJetInjector, а часть передали неявно, как глобальные. Не делайте так. Передавайте все переменные, нужные классу, в явном виде в его конструктор.

→ Ссылка