Initializing Python class object with external data - python

Suppose a "person" class contains name, age and phone number.
When creating a person object, I would like to set phone number by looking up an external phone book rather than explicitly passing a phone number.
Option 1: Store phone book as a class variable
class person():
phonebook = {}
def __init__(self, name, age):
self.name = name
self.age = age
self.phone = self.phonebook[self.name]
person.phonebook = {'dan':1234}
dan = person('dan', 30)
Option 2: Create a class object without phone number then have a separate function to load it.
class person():
def __init__(self, name, age):
self.name = name
self.age = age
def loadphone(self, phone):
self.phone = phone
phonebook = {'dan':1234}
dan = person('dan',30)
dan.loadphone(phonebook['dan'])
Both solutions do not seem optimal. Option 1, every person carries a phone book (unnecessarily). Option 2 requires 2-step initialization.
Is there a better way to create a person object without 1) explicitly passing a phone number or phone book during initialization, 2) storing phone book as a class variable, and 3) requiring a multi-step initialization?

As discussed in this post, defining a variable outside of any methods in the class, while still being defined in a class makes it a static variable, such as the one you have:
class person():
phonebook = {}
This means that there is a single phonebook which all instances of the class refer to
person.phonebook{'dave':1234, 'joey':5678}
dave = person('dave', 30)
joey = person('joey', 23)
There is still only the one universal phonebook that all instances refer to. The one thing to change in that code is that you should not define it as self.phonebook['dave'] so it should look like
class person():
phonebook = {}
def __init__(name, age):
self.name = name
self.age = age
self.number = phonebook[name]

Are you wanting to optionally define a phone number for a Person? You could do something like below:
class Person():
def __init__(self, name, age, phone=None):
self.name = name
self.age = age
self.phone = phone
dan = Person('dan',30, phone=1234)
stan = Person('stan', 60)

Firstly, as for me, it's too wide question and very depend on task. In one case you can access to PhoneBook, in another - it's bad idea (e.g. PhoneBook load data from server and creating 1000 of Person will produce 1000 requests).
Secondary, their is next approach:
class BasicPerson():
def __init__(self, name, age):
self.name = name
self.age = age
def ToString(self):
return('some code')
class PersonWithPhone():
def __init__(self, basicPerson, phone):
self.basicPerson = basicPerson
self.phone = phone
def ToString(self):
return('another code ' + self.basicPerson.ToString())
person = PersonWithPhone(BasicPerson('', ''), '11111')
It's just example and may seems useless, but in many situations you can extract some core actions (ToString, for example) and than wrote small decorators that expand each other.

Related

Getting a class attribute in a method

I have this class and method:
class Person(object):
def __init__(self, name):
self.name = personname
self.surname = personsurname
def changenameorsurname(self, x, y):
self.x = y
return
AdamSmith = Person ("Adam", "Smith")
I want to use method changenameorsurname to change AdamSmith's name or surname, but if I use this code I'm getting a NameError"
AdamSmith.changenameorsurname(personname, Dave)
Result:
NameError: name personname is not defined.
Is there elegant way to reference personname in code like this? Or do I have to make two separate methods like this?
def changename(self, y):
self.name = y
return
AdamSmith.changename(Dave)
There are a couple of problems. Your init method needs to be fixed so you can properly construct a Person object. You can have your changenameorsurname() method take one argument that is a name and a second argument that determines whether that name is the first name or the surname. Here, I have set the default to first name.
class Person:
def __init__(self, first_name, surname):
self.first_name = first_name
self.surname = surname
def changenameorsurname(self, name, first = True):
if first:
self.first_name = name
else:
self.surname = name
def __str__(self):
return f'{self.first_name} {self.surname}'
some_guy = Person ("Adam", "Smith")
print(some_guy) #Adam Smith
some_guy.changenameorsurname("Michael")
print(some_guy) #Michael Smith
some_guy.changenameorsurname("Jones", first=False)
print(some_guy) #Michael Jones

Treating a model as an instance of imported class in Django

I have a class for manipulating certain data.
In that class I calculate and validate the data.
Then, is there a way to apply this calculation and validation to an instance of Django model?
Ideally, I would like to store an instance of the imported class in the database.
I came up with two methods.
1.Make another class to connect model and imported class.
2.Write validation and calculations directly in models.py.
Which is better?
Is there another good way?
If 2 is good, how to do that?
Here is a very simple example.
# in models.py
class Person(models.Modes):
name = models.CharField()
gender = models.CharField()
age = models.IntegerField()
valid = models.NullBooleanField(blank=True)
# in other files
class AboutPerson:# I want to apply this class to above model instance.
def __init__(self, name, gender, age):
self.name =name
self.gender = gender
self.age = age
self.valed = None
def validate_age(self):
self.valid = self.age >= 20
def other_validate(self, age):
self.valid = self.age >= age
In this example, I want to apply change of self.valid to model automatically.
Now, I adopt 2. This is also a simple example.
class FromModel:
'''
obj:object obtained from database
This class passes the value received from the database to the class imported from the module.
Attribute:
'''
def __init__(self, obj):
self.obj = obj
self.instance = AboutPerson(name=obj.name, gender=obj.gender, age=obj.age)
def update(self):#use this method after some validation has done.
self.obj.valid = self.instance.valid
self.obj.save()
I wish you could understand my poor explanation...
Thank you for helping me.
As Alan Hoover said, if you aren't planning on needing to validate the form data from user input then I don't think you should use a form.
My suggestion is to keep the validation of the model in the model. There is a built in method for validation: Model.clean(). So using your example:
models.py
class Person(models.Model):
name = models.CharField(max_length=64)
gender = models.CharField(max_length=16)
age = models.PositiveIntegerField()
def clean(self):
if self.age < 21:
raise ValidationError('No beer for you!')
if self.name == 'Charles':
self.name = 'Charley'
views.py
def my_function():
# ...
my_person_obj.clean()
my_person_obj.save()
Let me know if I misunderstood your question.

Creating objects in Python way

I'm learning Python and recently started with the OOP part.
I know there are different ways to create objects but I do not know what way I should aim at.
Create objects with arguments or without arguments?
Then I do understand the best way to change the attributes is with method calls.
Code:
class Human(object):
def __init__(self):
self.name = ''
self.age = 0
def set_name(self, name):
self.name = name
def set_age(self, age):
self.age = age
class Humans(object):
def __init__(self, name, age):
self.name = name
self.age = age
def set_names(self, name):
self.name = name
def set_ages(self, age):
self.age = age
# Create object without arguments
boy = Human()
boy.set_name('Peter')
boy.set_age(30)
# Or create object with arguments
girl = Humans('Sandra', 40)
An object should be in an usable state after creation. That said, a human with no name and no age is not useful. So the second implemention is preferred. Another thing is, that you don't need setters in python, which reduces the class to
class Humans(object):
def __init__(self, name, age):
self.name = name
self.age = age

passing a class instance as a parameter to a method in python

class Person:
age = None
gender = None
weight = None
def ___init__(self, age, gender):
self.age = age
self.gender= gender
class RunMain:
person = Person()
collect = CollectData()
collect.getAge(person)
collect.getGender(person)
print person.age
print person.gender
class CollectData():
def getAge(self, person):
person.age = 22
def getGender(self, person):
person.gender = 'Male'
I just did this in a hurry and I didn't use a compiler so there could be errors but my question is does Python allow you to send a class instance to a function? Once we have the class instance, can i set the variables in that instance?
I could do this in C# and I've been programming in C# for a long time. I just don't know how this works in Python and I couldn't find anything in any of the books that I've been through.
Sure, I rewrote your code a little so you can run it:
class Person:
age = None
gender = None
weight = None
def ___init__(self, age, gender):
self.age = age
self.gender= gender
class CollectData():
def getAge(self, person):
person.age = 22
def getGender(self, person):
person.gender = 'Male'
class RunMain:
person = Person()
collect = CollectData()
collect.getAge(person)
collect.getGender(person)
print person.age
print person.gender
RunMain()
You can run it here: https://repl.it/BBww
I think are asking whether the class instance passed in gets mutated. And yes it does just like in c#. Why would you expect otherwise?
Strange idiom, though to use getAge() and getGender() to mutate those values.

How to handle instance's external, mutual and attributes?

class ppl:
gender = "male"
def __init__(self, name, age, username):
self.name = name
self.age = age
self.username = username
username = "abcs"
laci = ppl("John", 25, username)
for attr, value in laci.__dict__.iteritems():
print value
How do i make the program to print the gender as well?
Rather than make gender a class attribute, just make it a hard-coded instance attribute:
def __init__(self, name, age, username):
self.name = name
self.age = age
self.username = username
self.gender = "male"
This make more sense than a hard-coded class attribute. Either all instances of ppl are males, in which case there is no need to explicitly store the information (in fact, the class should probably be called Male, not ppl), or the instances could be male or female, in which case gender isn't an attribute of the class as a whole.
It is a class attribute so use the class:
print(ppl.gender)
Or print it using the instance:
print(laci.gender)
To combine both class and instances dicts:
for attr, value in laci.__dict__.viewitems() | ppl.__dict__.iteritems():
if not all((attr.startswith("__"),attr.endswith("__"))):
print(value)

Categories