简体   繁体   中英

Python: How do I pass a value for an attribute for an instance of a class that is being created within an instance of a different class?

I confused myself typing this title, so please let me know if it requires some clarification. I'm working my way through Python Crash Course, by Eric Matthes and one of the exercises brought up a question that I haven't been able to find an answer for. Also, apparently, I can't figure out how to properly format the following code, sorry. The code for the exercise in question follows:

class User():
    """Store info about a user profile"""

    def __init__(self, first_name, last_name, email, username):
        """Init common profile info"""
        self.first_name = first_name
        self.last_name = last_name
        self.email = email
        self.username = username
        self.login_attempts = 0

    def describe_user(self):
        """Print users info"""
        print("User info summary: \n\t" + 
            self.first_name.title() + " " +
            self.last_name.title() + "\n\t" +
            self.username + "\n\t" +
            self.email
            )

    def greet_user(self):
        """Print a short greeting"""
        print("Welcome, " + self.first_name.title() + "!")

    def increment_login_attempts(self):
        """Increments the number of login attempts by 1"""
        self.login_attempts += 1

    def reset_login_attempts(self):
        """Rest value of login_attempts to 0"""
        self.login_attempts = 0

class Privileges():
    """Represents a list of privileges"""

    def __init__(self, privileges=[]):
        """Initialize attributes for Privileges"""
        self.privileges = privileges

    def show_privileges(self):
        """Print the list of privileges for this admin"""
        for item in self.privileges:
            print(item.title())

class Admin(User):
    """Model an administrative user"""

    def __init__(self, first_name, last_name, username, email):
        """Initialize attributes of Admin"""
        super().__init__(first_name, last_name, username, email)
        self.privileges = Privileges(['can add user', 'can block user'])

bbob = Admin('billy', 'bob', 'bbob', 'blah')
bbob.privileges.show_privileges()

OK so, I'd like to be able to provide the list of privileges to the instance of class Privileges that's being created inside of Admin , at the time I'm creating the instance of Admin . Does this all make sense? Every time I type it out I get confused. It seems to me, that in a potential real-world application, it would be unreasonable to provide that list in the class definition, as it is in Admin 's __init__ method. It should be able to be passed to the class as an argument or something, right?

Thanks, all, for your time reading this. Please let me know if this didn't make any sense at all.

It is convenient and makes sense to be able to configure contained objects. It might not win you purity points, and it entangles the classes, but it's convenient, and at least some entanglement is natural and not necessarily to be avoided. Just add another parameter:

class Admin(User):

     def __init__(self, first_name, last_name, username, email,
                  privileges):
         """Initialize attributes of Admin"""
         super().__init__(first_name, last_name, username, email)
         self.privileges = Privileges(privileges)

 bbob = Admin('billy', 'bob', 'bbob', 'blah',
              ['can add user', 'can block user'])

Or, perhaps better, if Admins have some default privileges, is just to let the developer optionally add them:

class Admin(User):

     def __init__(self, first_name, last_name, username, email,
                  extra_privileges=None):
         """Initialize attributes of Admin"""
         super().__init__(first_name, last_name, username, email)
         privileges = ['can add user', 'can block user']
         privileges += extra_privileges or []
         self.privileges = Privileges(privileges)

 bbob = Admin('billy', 'bob', 'bbob', 'blah')
 ssara = Admin('sara', 'smith', 'ssara', 'blatz', ['can read emails'])

One final note: Parameter lists should not contain mutable structures like lists if you can at all avoid that. Subtle but important side-effects can make them do things you really don't expect. This is basically Python gotcha #1 . Instead, if you have a null default, use None :

 def __init__(self, privileges=None):
     """Initialize attributes for Privileges"""
     self.privileges = privileges or []

This way, if __init__ is called with no privileges, self.privileges gets the empty list as before. Or if they provide a list, that is taken. But without the nasty side effects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM