1

I have a question regarding the solution to Exercise 9-8 in Python Crash Course (2nd edition). The codes are as follows:

class User():
    """Represent a simple user profile."""

    def __init__(self, first_name, last_name, username, email, location):
        """Initialize the user."""
        self.first_name = first_name.title()
        self.last_name = last_name.title()
        self.username = username
        self.email = email
        self.location = location.title()
        self.login_attempts = 0

    def describe_user(self):
        """Display a summary of the user's information."""
        print(f"\n{self.first_name} {self.last_name}")
        print(f"  Username: {self.username}")
        print(f"  Email: {self.email}")
        print(f"  Location: {self.location}")

    def greet_user(self):
        """Display a personalized greeting to the user."""
        print(f"\nWelcome back, {self.username}!")

class Admin(User):
    """A user with administrative privileges."""

    def __init__(self, first_name, last_name, username, email, location):
        """Initialize the admin."""
        super().__init__(first_name, last_name, username, email, location)
        
        # Initialize an empty set of privileges.
        self.privileges = Privileges()


class Privileges():
    """A class to store an admin's privileges."""

    def __init__(self, privileges=[]):
        self.privileges = privileges

    def show_privileges(self):
        print("\nPrivileges:")
        if self.privileges:
            for privilege in self.privileges:
                print(f"- {privilege}")
        else:
            print("- This user has no privileges.")


eric = Admin('eric', 'matthes', 'e_matthes', 'e_matthes@example.com', 'alaska')
eric.describe_user()

eric.privileges.show_privileges()

print("\nAdding privileges...")
eric_privileges = [
    'can reset passwords',
    'can moderate discussions',
    'can suspend accounts',
    ]
eric.privileges.privileges = eric_privileges
eric.privileges.show_privileges()

My question is about the second last line. I understand the first "priviledges" refers to the instance in the class Admin. So, what about the second "priviledges"?

Many thanks in advance!

  • 1
    Welcome to Stack Overflow! Please read about [How to debug small programs](http://ericlippert.com/2014/03/05/how-to-debug-small-programs/). You can also use [Python-Tutor](http://www.pythontutor.com/visualize.html#mode=edit) which helps to visualize the execution of the code step-by-step. – Tomerikoo Jan 01 '21 at 15:39
  • 1
    `Admin` objects have an attribute called `privileges` which is a `Privileges` object which in turn has a `privileges` attribute which is a list... So, `eric.privileges.privileges` accesses the privileges list – Tomerikoo Jan 01 '21 at 15:41
  • 2
    To be honest, the whole `Privileges` class is redundant and can be removed. Simply save the `privileges` list directly under `Admin` and add `show_privileges` as an `Admin` method or even just an external function... – Tomerikoo Jan 01 '21 at 15:44

3 Answers3

1

To answer your question, it's because Admin contains self.privileges = Privileges(), then the Privileges class contains self.privileges = privileges again.

I don't know why they've set it up like this though. The code is a tad sketchy. The Privileges class alone has multiple odd things:

  • You don't need the () in class Privileges():.
  • privileges=[] is nearly always wrong. Never have a mutable default argument.
  • Why even have the class? All it's doing is housing a method. That method could easily be a method of Admin, or as a standalone function that accepts admin.privileges as an argument. It isn't encapsulating anything, so it's really just making the code more complex than it needs to be.

I'd be cautious taking advice from this source.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
  • 1
    Just that `privileges=[]` alone is a huge red flag. I can't believe any tutorial teaching people Python would put that out there, let alone anything else. – CrazyChucky Jan 01 '21 at 23:54
0

The class Admin has an attribute self.privileges that is an object of the class Privileges. The class Privileges also has an attribute named self.privileges.

class Admin, attribute privileges -> class Privileges, attribute privileges
eric.privileges.privileges = eric_privileges

scmanjarrez
  • 407
  • 4
  • 8
-1
class Privileges():
    """A class to store an admin's privileges."""

    def __init__(self, privileges=[]):
        self.privileges = privileges

not sure why but was thinking about this line of code,

adding this at the end of the file

print('***************')
for property, value in vars(eric).items():
    print(property, ":", value)
print('***************')

print(type(eric.privileges))
print(eric.privileges)
print('id : ',id(eric.privileges))
for property, value in vars(eric.privileges).items():
    print(property, ":", value)
print('***************')
print(type(eric.privileges.privileges))
print(eric.privileges.privileges)
print('id : ',id(eric.privileges.privileges))

gives :

***************
first_name : Eric
last_name : Matthes
username : e_matthes
email : e_matthes@example.com
location : Alaska
login_attempts : 0
privileges : <__main__.Privileges object at 0x7fd795456be0>
***************
<class '__main__.Privileges'>
<__main__.Privileges object at 0x7fd795456be0>
id :  140563899050976
privileges : ['can reset passwords', 'can moderate discussions', 'can suspend accounts']
***************
<class 'list'>
['can reset passwords', 'can moderate discussions', 'can suspend accounts']
id :  140563932329856

guess these two privileges are related but slightly different

As per answer one : as in one: The class Admin has an attribute self.privileges that is an object of the class Privileges. The class Privileges also has an attribute named self.privileges. class Admin, attribute privileges -> class Privileges, attribute privileges eric.privileges.privileges = eric_privileges

pippo1980
  • 2,181
  • 3
  • 14
  • 30
  • In what way does this answer the question? – Tomerikoo Jan 01 '21 at 15:49
  • as in one: The class Admin has an attribute self.privileges that is an object of the class Privileges. The class Privileges also has an attribute named self.privileges. class Admin, attribute privileges -> class Privileges, attribute privileges eric.privileges.privileges = eric_privileges ?? – pippo1980 Jan 01 '21 at 15:51
  • all the above should be [edit]ed into your answer... That's the actual answer. Simply posting the exact same code from the question is not an answer. The whole point of the question is that the OP do not understand that code – Tomerikoo Jan 01 '21 at 15:54
  • I will revert it once you edited your answer... A ban is not an excuse to post low-quality content... – Tomerikoo Jan 01 '21 at 16:05
  • Why don't you put your first comment above in the answer? That's exactly the answer to the question... – Tomerikoo Jan 01 '21 at 21:29
  • Look at the other answers and my comments under the question. It's just a (not necessary if you ask me) 2-level capsulation: the admin has a privileges object which has a list of privileges – Tomerikoo Jan 01 '21 at 23:07
  • I’ll do as soon as I figure out the entire picture. Tried online http://pythontutor.com/visualize.html#mode=edit on the script but wasn’t really helpful. – pippo1980 Jan 01 '21 at 23:11
  • So ‘#Initialize an empty set of privileges’ in the code its kind of misleading ? Or it’s the right way to describe: self.privileges = Privileges() ?? – pippo1980 Jan 01 '21 at 23:19
  • Yes I agree. It can be misleading. It should be something more like *initialize a new privileges object with an empty list of privileges* – Tomerikoo Jan 02 '21 at 10:54
  • set() list object too much too soon to me nevetheless thanks a lot – pippo1980 Jan 02 '21 at 11:13