AlexW AlexW - 7 months ago 12
Python Question

Adding to a class dynamically

I've created a new class and I'm trying to add to that class dynamically,
I've created a list, that I want to put multiple objects in, then I will iterate over that list in Django (is this the correct way of doing things?)

but I'm getting the below error

TypeError: __init__() takes exactly 9 arguments (1 given)


I know what the error means, I'm just wonder how I go about creating a new instance of my objects and adding to it on the fly easily?

### create User Object
class User:
def __init__(self, Policy, Level, StartDate, EndDate, StartTime, EndTime, Name, Mobile):
self.Policy = Policy
self.Level = Level
self.StartDate = StartDate
self.EndDate = EndDate
self.StartTime = StartTime
self.EndTime = EndTime
self.Name = Name
self.Mobile = Mobile
def __init__(self):
pass


### Get all the Polices ###
lstOnCall = []
for objPolicy in objPolicyData['escalation_policies']:
strPolicyName = objPolicy['name']
if strPolicyName.lower().find('test') == -1:
for objOnCall in objPolicy['on_call']:
objUser = User()
objUser.Policy = strPolicyName
objUser.Level = objOnCall['level']
objUser.StartDate = getDate(objOnCall['start'])
objUser.EndDate = getDate(objOnCall['end'])
objUser.StartTime = getTime(objOnCall['start'])
objUser.EndTime = getTime(objOnCall['end'])
objUser = objOnCall['user']
objUser.Name = objUser['name']
objUser.Mobile = getUserMobile(objUser['id'])
lstOnCall.append(objUser)
print lstOnCall


UPDATE:
adding the below works, i just need to know how to print the items now?

def __init__(self):
pass


the below

for item in lstOnCall:
print item()


returns

print item()
AttributeError: User instance has no __call__ method

Answer

You can write a dynamic constructor (def __init__) for your class so:

class User(object):
    __attrs = ['Policy', 'Level', 'StartDate', 'EndDate', 'StartTime',
               'EndTime', 'Name', 'Mobile']

    def __init__(self, **kwargs):
        for attr in self.__attrs:
            setattr(self, attr, kwargs.get(attr, None))

    def __repr__(self):
        return ', '.join(
            ['%s: %r' % (attr, getattr(self, attr)) for attr in self.__attrs])
  • The variable __attrs stores the variables names. I used underscore variable, so that it's inaccessible from extend.
user = User()
print(user.__attrs)
Traceback (most recent call last):
    print(user.__attrs)
AttributeError: 'User' object has no attribute '__attrs'

Yes, there are other method to access it, but no one will do that ;)

  • The function __repr__ return the string by calling the command print or str, if the function __str__ doesn't exist.

Now test it

>>> u1 = User(Name='user1')
>>> u2 = User(Name='user2', Policy=1, Level=3)
>>> print(u1)
Policy: None, Level: None, StartDate: None, EndDate: None, StartTime: None, EndTime: None, Name: 'user1', Mobile: None
>>> print(u2)
Policy: 1, Level: 3, StartDate: None, EndDate: None, StartTime: None, EndTime: None, Name: 'user2', Mobile: None

If you use my codes, you can print the items in your case so:

for item in lstOnCall:         
    print item

Other problem of your code
There aren't the definition Function overloading in Python. You can define multiple function with the same name in python. But it doesn't make any sense. Only the last definition remains in your class/module. The previous definitions will be overwritten. What you are doing with

class User:
   def __init__(self, a, b, c):
      ...
   def __init__(self):
      pass

is False. The function def __init__(self, a, b, c) will be overwritten. Only the function def __init__(self) exists in your class

Comments