Python Forum
Why doesn't calling a parent constructor work with arbitrary keyword arguments?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why doesn't calling a parent constructor work with arbitrary keyword arguments?
#1
I have a module named user_admin_privileges.py with 3 classes in it: Privileges, User, and Admin.

In my program I import the class Admin from the module, create an instance called admin passing 2 positional arguments in parameters fname and lname and one arbitrary keyword argument. But for some reason I get an error saying that there's a type error in parent constructor, __init__() function, and that it takes 3 positional arguments but 4 were given.

TypeError: __init__() takes 3 positional arguments but 4 were given

user_admin_privileges.py:
class Privileges: def __init__(self): self.privileges = ["can add a post", "can delete a post", "can ban a user"] def show_privileges(self): print("The privileges are:") for privilege in self.privileges: print(f"\t- {privilege}") class User: def __init__(self, fname, lname, **data): self.data = data self.data["first name"] = fname self.data["last name"] = lname self.data["login_attempts"] = 0 def describe_user(self): print("The user's data:") for key, val in self.data.items(): print(f"{key}: {val}") print() def greet_user(self): print(f"Hello dear " + self.data["first name"] + "!") print() def increment_login_attempts(self): self.data["login_attempts"] += 1 def reset_login_attempts(self): self.data["login_attempts"] = 0 class Admin(User): def __init__(self, fname, lname, **data): self.data = data self.data["first name"] = fname self.data["last name"] = lname self.privileges = Privileges() super().__init__(fname, lname, data)
And the program itself:
from user_admin_privileges import Admin admin = Admin("Derrick", "Brown", location="Florida, USA") admin.privileges.show_privileges()
What did I do wrong? How to fix this issue?
Reply
#2
I think in Admin.__init__() it should be
super().__init__(fname, lname, **data)
However, the strange thing is that your Admin.__init__() function seems to duplicate the work made by User.__init__()
Reply
#3
(Jun-24-2023, 11:07 AM)Gribouillis Wrote: I think in Admin.__init__() it should be
super().__init__(fname, lname, **data)
However, the strange thing is that your Admin.__init__() function seems to duplicate the work made by User.__init__()

I changed it to **data as you promised, and now it works. Thank you!

And, yes, I messed up with a constructor and it does duplicate the parent constructor. I changed that.

Now it looks like this (I hope it's correct now):


class Admin(User): def __init__(self, fname, lname, **data): self.privileges = Privileges() super().__init__(fname, lname, **data)
Thank you very much!
Reply
#4
UPD: Proposed, not promised, I misspelled xD
Reply
#5
It would be strange to write a class that accepts "arbitrary keyword" arguments for the __init__(). But you aren't doing that. You are replacing the __dict__ object that normally holds all the class attributes with an external dictionary. That is even stranger. Why are you doing this?

Normally a class is aware of what attributes instances of the class are likely to have. Methods of the class can perform operations on the attributes with some confidence that the attributes exist. Your User can only be confident that it can access attributes that it added to the data dictionary. For example, I create two users that have a location, but I make a typo when entering one of the users. Flo Rida has a location attribute, but there is no location attribute for Junior, and that raises an exception when we ask User Junior for their location.
class User: def __init__(self, fname, lname, **data): self.data = data self.data["first name"] = fname self.data["last name"] = lname self.data["login_attempts"] = 0 def __getitem__(self, index): """Adds [] indexing to class.""" return self.data[index] def __str__(self): return "\n".join(f"{key} : {value}" for key, value in self.data.items()) flo_rida = User("Flo", "Rida", location="Florida") junior_rida = User("Junior", "Rida", loc="Florida") print(flo_rida, "\n") print(junior_rida, "\n") print(flo_rida["location"]) print(junior_rida["location"])
Output:
location : Florida first name : Flo last name : Rida login_attempts : 0 loc : Florida first name : Junior last name : Rida login_attempts : 0 Florida
Error:
Traceback (most recent call last): File ..., line 19, in <module> print(junior_rida["location"])
Classes should offer more than dictionaries. They should guarantee a commonality amongst their instances and provide an API for using instances of the class. I would write your code like this:
class Privileges: def __init__(self, *args): self.privileges = list(*args) def __str__(self): return str(self.privileges) class User: def __init__(self, fname, lname, location=None, priv=None): self.first_name = fname self.last_name = lname self.login_attempts = 0 self.location = location self.privileges = Privileges(priv or []) def __str__(self): return "\n".join(( self.__class__.__name__, f"First Name: {self.first_name}", f"Last Name: {self.last_name}", f"Location: {self.location}", f"Priviledges: {self.privileges}" )) def increment_login_attempts(self): self.login_attempts += 1 def reset_login_attempts(self): self.login_attempts = 0 class Admin(User): def __init__(self, *args, priv=None, **kwargs): priv = priv or ("can add a post", "can delete a post", "can ban a user") super().__init__(*args, priv=priv, **kwargs) admin = Admin("Derrick", "Brown", location="Florida, USA") print(admin, "\n") user = User("Flo", "Rida", priv=["can add a post"]) print(user)
Output:
Admin First Name: Derrick Last Name: Brown Location: Florida, USA Priviledges: ['can add a post', 'can delete a post', 'can ban a user'] User First Name: Flo Last Name: Rida Location: None Priviledges: ['can add a post']
I would also consider making User and Administrator dataclasses..
from dataclasses import dataclass class Privileges: def __init__(self, *args): self.privileges = list(*args) def __str__(self): return str(self.privileges) @dataclass class User: first_name: str last_name: str location: str = None privileges: Privileges = Privileges() login_attempts: int = 0 def increment_login_attempts(self): self.login_attempts += 1 def reset_login_attempts(self): self.login_attempts = 0 @dataclass class Admin(User): def __init__(self, *args, privileges=None, **kwargs): privileges = privileges or ("can add a post", "can delete a post", "can ban a user") super().__init__(*args, privileges=privileges, **kwargs) admin = Admin("Derrick", "Brown", location="Florida, USA") print(admin, "\n") user = User("Flo", "Rida", privileges=["can add a post"]) print(user)
Output:
Admin(first_name='Derrick', last_name='Brown', location='Florida, USA', privileges=('can add a post', 'can delete a post', 'can ban a user'), login_attempts=0) User(first_name='Flo', last_name='Rida', location=None, privileges=['can add a post'], login_attempts=0)
And if, for some reason, you really want to have a class that assigns some arbitrary attributes in the __init__(), you can do that like this:
class Privileges: def __init__(self, *args): self.privileges = list(*args) def __str__(self): return str(self.privileges) class User: def __init__(self, fname, lname, location=None, priv=None, extras=None): self.first_name = fname self.last_name = lname self.login_attempts = 0 self.location = location self.privileges = Privileges(priv or []) if extras: for key, value in extras.items(): setattr(self, key, value) def __str__(self): fields = [self.__class__.__name__] + [f"{key:15}: {value}" for key, value in self.__dict__.items()] return "\n".join(fields) def increment_login_attempts(self): self.login_attempts += 1 def reset_login_attempts(self): self.login_attempts = 0 class Admin(User): def __init__(self, *args, priv=None, **kwargs): priv = priv or ("can add a post", "can delete a post", "can ban a user") super().__init__(*args, priv=priv, **kwargs) user = User("Flo", "Rida", priv=["can add a post"], extras={"occupation":"Rapper"}) print(user)
Output:
User first_name : Flo last_name : Rida login_attempts : 0 location : None privileges : ['can add a post'] occupation : Rapper
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  PIP doesn't work YKR 1 1,489 Mar-28-2025, 02:10 PM
Last Post: snippsat
  I'm trying to install python 3.11.11 on windows 10 - it doesn't work Petonique 2 5,021 Feb-04-2025, 05:42 PM
Last Post: snippsat
  creating arbitrary local variable names Skaperen 9 2,947 Sep-07-2024, 12:12 AM
Last Post: Skaperen
  Extending list doesn't work as expected mmhmjanssen 2 2,484 May-09-2024, 05:39 PM
Last Post: Pedroski55
  Why doesn't list require global keyword? johnywhy 9 6,172 Jan-15-2024, 11:47 PM
Last Post: sgrey
  Find a specific keyword after another keyword and change the output sgtmcc 5 3,204 Oct-05-2023, 07:41 PM
Last Post: deanhystad
  calling external function with arguments Wimpy_Wellington 6 3,884 Jul-05-2023, 06:33 PM
Last Post: deanhystad
  Why doesn't this code work? What is wrong with path? Melcu54 7 5,126 Jan-29-2023, 06:24 PM
Last Post: Melcu54
  color code doesn't work harryvl 1 2,485 Dec-29-2022, 08:59 PM
Last Post: deanhystad
  client.get_all_tickers() Doesn't work gerald 2 3,343 Jun-16-2022, 07:59 AM
Last Post: gerald

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020
This forum uses Lukasz Tkacz MyBB addons.
Forum use Krzysztof "Supryk" Supryczynski addons.