'Why is __new__() asking for 4 arguments when initializing an object from a class derived from an abstract base class that wants one argument?
I am using Python 2.7 (using 3 in my case is not possible). I have a base class with some implemented methods and some abstract methods. I am using abc to implement the abstract base class, and the class inherits from ABCMeta, as recommended in some Python2.7 documentation.
import rospy
from bayesian.bbn import *
from cr_project.srv import ObservePatch, ObservePatchResponse, ConsumeFlower, ConsumeFlowerResponse
from abc import ABCMeta, abstractmethod
import numpy as np
# Base class
class Bee(ABCMeta):
def __init__(self, name):
self.name = name
self.collected_nectar = 0
self.bbn = build_bbn(
self.f_C, self.f_B, self.f_N,
domains = {
'C':[0,1,2]
})
rospy.init(self.name)
# Desirability of a flower based on color
# 0 = red, 1 = blue, 2 = yelloe
@abstractmethod
def f_C(self, C):
pass
# Desirability of a flower based on how many bees it has
@abstractmethod
def f_B(self, B):
pass
# probability of a flower containing nectar
@abstractmethod
def f_N(self, C, B, N):
pass
def calc_patch_probabilities(self, observation):
rows = observation.rows
cols = observation.columns
result = numpy.array([bbn.query(C=f[0], B=f[1]) for f in zip(observation.colors, observation.bees)])
return result.reshape(rows,cols).tolist()
def select_flower(self, prob2d):
row = 0
col = 0
max = 0
for r in range(0, len(prob2d)):
for c in range(0, len(prob2d[0])):
if prob2d[r][c] > max:
max = prob2d[r][c]
row = r
col = c
return row, col
def start(self):
observe_srv = rospy.ServiceProxy('ObservePatch', ObservePatch)
consume_srv = rospy.ServiceProxy('ConsumeFlower', ConsumeFlower)
while not rospy.is_shutdown():
# Observe the flower patch
observe_req = ObservePatch() # no request data needed
observation = observe_srv(observe_req)
# Get probabilities for all flowers and normalize
prob2d = self.calc_patch_probabilities(observation)
# consume flower with highest probability
row, col = self.select_flower(prob2d)
consume_req = ConsumeFlower()
consume_req.row = row
consume_req.col = col
consume_rsp = consume_srv(consume_req)
self.collected_nectar += consume_rsp.nectar_received
rospy.info('%s consumed %d nectar from flower at [%d, %d] and has collected a total of %d nectar', self.name, rsp.nectar_received, row, col, self.collected_nectar)
# wait a random number of seconds (maximum of 3)
rospy.sleep(random.uniform(0,3))
I then have a subclass that inherits from the Bee base class, and implements the missing functions. I also want to have the __init__() constructor set the name that is passed into the base class. This subclass is in a separate file which also has a main function and is executable.
class StupidBee(Bee):
def __init__(self):
super(StupidBee, self).__init__('StupidBee')
def f_C(self, C):
return 1.0/3.0 # Doesn't care about color
def f_B(self, B):
return 1.0 # Doesn't care
def f_N(self, C, B, N):
return 1.0
if __name__ == "__main__":
try:
b = StupidBee()
b.start()
except rospy.ROSInterruptException:
pass
However, when I try to run it, I get an error with StupidBee().
Traceback (most recent call last):
File "./StupidBee.py", line 27, in <module>
b = StupidBee()
TypeError: __new__() takes exactly 4 arguments (1 given)
I am completely at a loss on what I'm doing wrong, to be honest. I have not declared __new__() anywhere, and I have no idea what arguments it needs. What am I missing?
(Note: the code is still a work-in-progress, was not tested yet, and probably has other mistakes and issues)
EDIT: Here's a minimal reproducible example
#!/usr/bin/env python
from abc import ABCMeta, abstractmethod
class Base(ABCMeta):
def __init__(self, name):
self.name = nam
@abstractmethod
def abs_method(self):
pass
def print_name(self):
print self.name
class Derived(Base):
def __init__(self):
super(Derived, self).__init__('Derived')
def abs_method(self):
print "This is a Derived method"
d = Derived()
d.abs_method()
Solution 1:[1]
As a few commenters have figured out, you've inherited from the wrong base class. If you inherit from abc.ABCMeta, then you're making your own metaclass. If you just want to make an abstract base class, you want to either inherit from abc.ABC, or to declare that abc.ABCMeta is your class's metaclass.
In Python 2, you'll want:
from abc import ABC
class Bee(ABC):
...
Or:
from abc import ABCMeta
class Bee:
__metaclass__ = ABCMeta
...
In Python 3, the latter would be:
from abc import ABCMeta
class Bee(metaclass=ABCMeta):
...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Blckknght |
