-2
class character():

  class personalized:
    def __init__(self, name, age, height, width, hair_color, eye_color):

      # I want to do this
      for attr in personalized:
        personalized.attr = attr


      #instead of this
      personalized.name = name
      personalized.age = age
      personalized.height = height

If I am using classes with a lot of attributes I don't want to have to set it equal to a variable every time because it will take up a lot of space. Is there a way to write it like I did above but actually works. In essence I don't know how to retrieve attributes from the __init__ function.

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • 1
    Attributes don't exist until you add them. There's no way for the `__init__` method to know what attributes you want to use in the class. – Barmar Sep 11 '20 at 22:44
  • You can't access parameter variables dynamically, unless you use `eval()`. – Barmar Sep 11 '20 at 22:45
  • also consider refractoring the class so it doesn't have to own all of those argument, therefore having to set less variables in your class. – Arturo Sep 11 '20 at 22:53
  • Pass a kwargs-style dict to `init()`, instead of individual arguments. That way you can loop over the dict and extract the variable names. – John Gordon Sep 11 '20 at 23:14
  • @Barmar `setattr(self,'parameter',value)` will create an instance variable dynamically. – Mark Tolonen Sep 12 '20 at 00:48
  • But just do it the long way. The code is clear. Or use `dataclass` if using Python 3.7+ if this is a data structure and not a class with other methods. – Mark Tolonen Sep 12 '20 at 00:49
  • @MarkTolonen But how would it know which attributes to create? – Barmar Sep 12 '20 at 00:58
  • @Barmar I didn’t say it was a solution, just a comment about your `eval` comment. – Mark Tolonen Sep 12 '20 at 02:57
  • @MarkTolonen I was talking about accessing the parameter variables dynamically, not the attributes. E.g. `setattr(self, parameter, eval(parameter))` – Barmar Sep 12 '20 at 03:55
  • @Barmar Still don't need `eval`. `vars()` can access the parameter names and values. I made an answer with that solution, although think dataclasses are a better way to go. – Mark Tolonen Sep 12 '20 at 05:03

3 Answers3

1

I would recommend using dataclasses for this. In your case you would just add:

from dataclasses import dataclass

@dataclass
class personalized:
    name: str
    age: int
    height: int
    width: int
    hair_color: str
    eye_color: str

This will auto-construct a init for you with self-assigned attributes

Kieran Wood
  • 1,297
  • 8
  • 15
0

You could use the __set__(..) Function (https://docs.python.org/3/howto/descriptor.html), but I do not suggest this because:

  • From a readability perspective this will harder to maintain over the long term (code is more often read than written)
  • everytime you want to access such an entry you first of all have to check if the descriptor/attribute is availible, thus making your down the road code worse. see: How to know if an object has an attribute in Python
Frank
  • 1
  • 1
  • 2
0

Using vars() and setattr() can do what you want, but I recommend dataclasses as in the other answer if using Python 3.7+.

vars() returns a dictionary of local variables. At the top of __init__ dictionary contains self and any parameters as keys and along with their values.

setattr() will set an attribute value on an object.

class Personalized:
    def __init__(self, name, age, height, width, hair_color, eye_color):
      for key,value in vars().items():
          if key != 'self':
              setattr(self, key, value)

p = Personalized('name',5,10,12,'black','blue')
print(p.name,p.age,p.height,p.width,p.hair_color,p.eye_color)

Output:

name 5 10 12 black blue
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251