Inheritance Issue

Hello,

I have the following inheritance test program which I created. The base class is
the general class which applies to the subsequent derived classes - all employees
have a first and last name. I then would like to create two derived classes to
separate managers from technicians. Thus, each object created should have a
first name, a last name, and an employee badge number. When I attempted to
run the script, I kept getting the following error:

TypeError: manager.init() takes 2 positional arguments but 4 were given

class employee:

    def __init__(self, fname, lname):
        self.fname = fname
        self.lname = lname

class manager(employee):
    
    def __init__(self, badgeNumber):
        self.id_number = badgeNumber
        super().__init__()
        
class technician(employee):

    def __init__(self, badgeNumber):
        self.id_number = badgeNumber

# Instantiate class (create object)
manager1 = manager("Sam", "Lawrence","DI456")

Can you please advise what is going wrong here?

You are inheriting from employee and calling super().__init__() to call the inherited employee initialization, but you are not providing variables. Even more, once you inherited from employee for manager and technician, you do not allow these new classes to accept fname or lname:

This would fix your issue:

class employee:

    def __init__(self, fname, lname):
        self.fname = fname
        self.lname = lname

class manager(employee):

    def __init__(self, fname, lname, badgeNumber):
        self.id_number = badgeNumber
        super().__init__(fname, lname)

class technician(employee):

    def __init__(self, fname, lname, badgeNumber):
        self.id_number = badgeNumber
        super().__init__(fname, lname)

# Instantiate class (create object)
manager1 = manager("Sam", "Lawrence","DI456")
2 Likes

Hello,

thank you very much for providing a potential solution to my issue.
Yes, this is much better than the solution that I found.

class employee:

    def __init__(self, fname, lname):
        self.fname = fname
        self.lname = lname

class manager(employee):
    
    def __init__(self, badgeNumber, *args1, **args2):
        self.id_number = badgeNumber
        super().__init__(*args1, **args2)
        
class technician(employee):

    def __init__(self, badgeNumber, *args1, **args2):
        self.id_number = badgeNumber
        super().__init__(*args1, **args2)


manager1 = manager("MI456", "Sam", "Lawrence")
tech1 = technician("TI812", "Joe", "Johnson")

Here, I had to rearrange the order of the input parameters for it to work. With your solution,
the input parameters can remain as per the original design.

Thank you a bunch.

Greatly appreciated!

Well, rearranging them is not required to get it to work, but as long as you have it working, that’s all that matters.

If my parameters were entered in this order:

*args1, **args2, badgeNumber

then I would get a syntax error.

Yes, if you want handle any and all arguments and keyword arguments of the base class generically, then you would be correct.

It is (somewhat) reasonable-thinking, that if all the common logic has been retained by the super-class, then so too would the initialisation of common attributes. Sadly, not the way (any) the language works.
The explanation for the original problem, is that values must be expected and provided for all of the instance-attributes - and those initialised by the super-class passed to it (per earlier response). Thus, fname, lname, AND badgeNumber!
(BTW lousy name choices. Why not first_name, last_name, and badge_number - that way the reader does not have to think about trivia and can concentrate on the logic - notice how this is EXACTLY how the problem was described in the original post!)
Later in the conversation, the phrase “each object created…[three attributes]” became complicated by the use of *args and *kwargs. That’s a separate issue and/or an omitted specification.
As you (correctly surmised) iterable-arguments must come AFTERWARDS - otherwise, how would Python know which was which?
(strictly-speaking the asterisk prefix “unpacks” an iterable into as many elements as there may be - will leave you to read-up on both of these points, if the whim appeals)
The better solution (IMHO) may have been shouldered-aside by rushing to the general case. Why not use keyword-arguments, eg self, first_name=None, last_name=None, badge_number=None
NB have added the concept of a default-argument which provides default-values, but in this case (more likely) enables the testing of each field to ensure that the data is reasonably-valid (ie “have a …name”)

Such has the ‘disadvantage’ that a calling-routine must either state the keywords or position the arguments in the defined sequence. Conversely, it has the advantage that keyword-arguments may be stated in any sequence, and Python will sort-it-all-out for you. Thus, a neater solution, and one more-easily read by others…

Even better: name, badge_number.

https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/

Hello,

thank you for your in-depth response. Yes, I am still getting acquainted with python. So, I will definitely
be taking your input into consideration. Please note that the code is not written in stone and is evolving.

Here is my latest code from my original post:

class employee:

    def __init__(self, first_name, last_name, title, badge_Number):
        self.first_name = first_name
        self.last_name = last_name
        self.title = title
        self.id_number = badge_Number

    def printIdentity(self):
        return print('\nName:   %s %s \nTitle:  %s \nID No.: %s' % (self.first_name, self.last_name, self.title, self.id_number))

class manager(employee):

    def __init__(self, first_name, last_name, title, id_number):
        super().__init__(first_name, last_name, title, id_number)

    def runTest(self):
        self.begin_test = False # Initial state is 'Off'

class technician(manager):

    def __init__(self, first_name, last_name, title, id_number):
        super().__init__(first_name, last_name, title, id_number)


# Instantiate classes (create objects)
LabEmp1 = employee("Ryan", "Larson", "Lab Tech", "JE173")
manager1 = manager("Sam", "Lawrence","Manager", "MI456")
tech1 = technician("Joe", "Johnson", "Senior Technician", "TI812")

# Print out employees (Note: Not real people)
manager1.printIdentity()
LabEmp1.printIdentity()
tech1.printIdentity()

tempVar = manager1.runTest().begin_test # Working on this

Note that these are code snippets that I use to test my understanding as I am progressively learning
python.

Definitely appreciate your feedback.

Thank you.

Nice Article :wink:

You’ll find “Falsehoods programmers believe about X” articles on quite a number of topics. I believe “time” was the first one, but the format has been used for many others, too. Here’s a bit of light reading for you.

Be aware, though, that even though these statements are all false, this doesn’t mean you suck as a programmer for ever making these assumptions. In the first place, these are EXTREMELY common misconceptions; if you make them, you’re in good company. Try to do better when you can, and celebrate the victories when you see them. But in the second place, some of them are hard to avoid. For example, not everyone’s names can be adequately represented in Unicode; but if you invite someone to enter a name in a web form, what can you do with a non-Unicode name? At best, you’d have a massive job handling a small number of people’s names in a handwritten form. At worst, you now can’t actually use them at all. But when you DO make these sorts of assumptions, the important thing is to be aware that you are placing restrictions on people - and be aware of what those restrictions are.

This is a parody, but here’s what can happen with names: The Bastard formerly known as Roger • The Register

So, the next time you design a system that works with dates/times, or names, or countries (it seems so simple, “Select your country”, but that easy drop-down list is incredibly politically charged), be sensitive to who you’re offending or excluding, and what you gain by it.

Be aware that @Chris and I spark off one-another, ie will equally cheerfully argue as agree - or even take an apposite point-of-view merely to ensure a more complete consideration.
The article-mentioned is well-worth reading. The value of its content is under-estimated by far too many ‘westerners’ and English[only]-speakers. However, it is more Information Science than Python - albeit one informing the other, one hopes (in real-life).

That said, in a corporate situation (or constrained training environment - whichever applies to the OP) one can afford to make ‘rules’, eg everyone has exactly two names [and only two]. Of course, (basic psychology says) better to refer to such as a “convention” rather than “rule” or “regulation”… For example, many corporates have a first-name.last-name@corporate.com email-address convention.
The risk though, is that we are trying to abstract to a (data-)structure, where such does NOT exist in the real-world. Trying to impose such is likely to lead to problems, and almost certainly user complaint!

Now, back to the scheduled program[me], hah!
Because (in this ‘latest version’) the two sub-classes (and the super-class) use an identical “signature”*, the sub-class init()s can be removed - they will then use the same in the super-class!
Firstly, eschew unnecessary repetition.
Secondly, this is the sort of thinking that seemed to be present in your earlier expectations of how inheritance works
Thus, the sub-class(es) only need an init() if it/they are going to do something else, and probably something unique to that type/class.

This old-coder likes (over-likes?) named-arguments. Sure they look like more typing - although a decent IDE will help with that. More to the point, they remind my (failing?) memory that I need to provide n-number of arguments, and what they all mean (and a good IDE will help with that too). For example, watching this conversation develop, one could be forgiven for becoming confused about whether badge_number comes before or after the names in the argument-list. (to say nothing of this simple-boy becoming distracted by questions about “badge_number” and “id_number”)

* something referred to as virtuous in the “Liskov Substitution Principle”

Irony: a name like “David” is unlikely to make me unique in a room of people. Thus, using “dn” as my ‘name’. Yet, here on the board, the “rule” insists that I must be “d_n”. What was @Chris’ point again???

You’re making good progress - keep it up!

1 Like

Hello,

thank you a bunch. Yes, I see your point (I tested the suggestion). For the ‘technician’ class,
I commented out the two statements and substituted them with the ‘pass’ keyword. Still works like
a charm. However, at this time, I don’t know if I will be adding additional methods to both the ‘manager’ and ‘technician’ classes. There could be unique functions that they could be executing. For example, different test boards, or different tests in the test procedure. So, for now, I am keeping those statements in place as it is an evolving code snippet. Like I stated in earlier posts, the end game is to create windows using tkinter along with PyVisa for controlling test equipment.

In a real-world environment, there would be a tech testing products. A manager could also test products to verify the performance of the test application. Both their names and badge number would be required to proceed with the testing in order for the test to commence.

Again, thank you for your insight.

NO WE DON’T!

Ok, after further pondering this statement, and testing the code, you’re absolutely correct. The signature, as is, in the ‘manager’ and ‘technician’ classes are not required. I can still create objects from these classes via inheritance.

Much obliged!

Yes, I agree with you.
(or do I?)

1 Like

In all seriousness, we do argue, we do debate, but not because we dislike each other :slight_smile:

+1
(antipodean humor can be difficult for others to understand - alternately, why would you want to?)

Coming back to speak at our PUG sometime in 2024?

1 Like

Dunno, maybe! I’m certainly open to the possibility, but I don’t have a topic.