How can i avoid repetitive calling of instance variables in Subclasses? - python-3.x

i was wondering if there is a way in Python to get rid of repetitive calling of instance variables , when creating subclasses.
for example:
class Name:
def __init__(self,first,last):
self.first = first
self.last = last
def __str__(self):
return f"Users first name is : {self.first}, Users last name is: {self.last}"
def __repr__(self):
return f"first:{self.first}, last:{self.last}"
class Cash(Name):
def __init__(self,first,last,cash):
super().__init__(first,last)
self.cash = cash
def full(self):
return f"{self.first},{self.last},{self.cash}"
c1 = Cash("Exa","Cool",200)
print(c1.full())
Is it possible to call all instance variables (self.first,self.last...) from "Name", without having to mention them in the constructor of "Cash"
something like:
class Cash(Name):
def __init__("all from Name" + new one ("cash" in this example)):
super().__init__("all from Name")
self.cash = cash

In your case, you can change the Cash class to look like this:
class Cash(Name):
def __init__(self,*inputs):
super(Cash,self).__init__(*inputs[:-1])
self.cash = inputs[-1]
def full(self):
return f"{self.first},{self.last},{self.cash}"
but for a more general solution that covers all situations take a look at this similar question.

Related

How Can I Dynamically Create Python Class Instances Using a List?

I am trying to understand how to dynamically create instances of a python class.
The simple example below shows how to create a class instance
class Person:
def __init__(self, name):
self.name = name
emmy = Person("Emmy")
niels = Person("Niels")
print(emmy.name)
print(niels.name)
If I want to iterate through a list to create class instances, how can I dynamically execute a command the same as
emmy = Person("Emmy")
I have tried to dynamically do it with something like eval or exec method so that I can iterate through a list and be able to call the class instance name using item name from list.
class Person:
def __init__(self, name):
self.name = name
people = ["Emmy","Niels"]
for item in people:
eval('item = Person(item)')
print(emmy.name)
print(niels.name)
Thanks in advance for any suggestions.
I found a solution creating a string variable to use as a command for the exec function.
class Person:
def __init__(self, name):
self.name = name
people = ["Emmy","Niels"]
for item in people:
a = str(item) + ' = Person("' + str(item) + '")'
exec(a)
print(Emmy.name)
print(Niels.name)

Python understanding classes and functions

New to python and have been working on improving my skills overall, however, I struggle with understanding classes and functions.
Why can or can't I do the following code below
class Person():
name = 'Tom'
age = 31
has_job = False
Person.name = 'Tom'
Person.age = 31
Person.has_job = False
print(Person.name, Person.age, Person.has_job)
compared to this
class Person():
def __init__(self, name, age, has_job):
self.name = name
self.age = age
self.has_job = has_job
p1 = Person('Tom', 31, False)
Is this just bad practice or is it something else entirely?
I don't think that writing a class like your first example would be very usefull, because the attributes remain the same for each instance.
That means that every Person will be called by default 'Tom', will have the age: 41 and "has_job" will be set to false.
In the second example you've got a specific constructor that will initialise those variables and that's going to be more usefull. There's only one problem: you forgot to put ":" after def __init__(self, name, age, has_job) .
Also be aware of the indentation.
Your code should look like this:
class Person():
def __init__(self, name, age, has_job):
self.name = name
self.age = age
self.has_job = has_job
p1 = Person('Tom', 31, False)
print(p1.name);
Python is white space sensitive. Unless you want to change the default values in you class you do not need to redefine them.
class Person():
name = 'Tom'
age = 31
has_job = False
'''
change these will change the class values
Person.name = 'Tom'
Person.age = 31
Person.has_job = False
'''
print(Person.name, Person.age, Person.has_job)
In the first section of your code you are trying to define class attributes. These are attributes that do not change between instances of your class. On the other hand if you define variables in the def init(self) method these are parameters you must pass when creating the class and will be unique to each instance of the class you create. These are called instance attributes.
class Person():
# these are class attributes.
name = 'Tom'
age = 31
has_job = False
class Person2():
def __init__(self, name, age, has_job)
# these are instance attributes
self.name = name
self.age = age
self.has_job = has_job
In your first code snippet you did not indent the classes attributes appropriately when you created the class. Check my example above to see how that would be done.
So in your case since each person will be a new instance of your Person class, you do not want to have name, age and has_job as class attributes since those are unique to every person you create. If you had those variables as class attributes then each person you create using your Person() class will have the same name, age, and has_job values.
If you created a class with class attributes and then changed the class attributes of the class instance every time it would not be pythonic. Rather you should create instances of the class with instance attributes.
I HIGHLY recommend watching Corey Shafer OOP tutorials on youtube as they cover all this extensively: https://www.youtube.com/watch?v=ZDa-Z5JzLYM&list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU&index=40

How to use tkinter entry .get() fuction in another class

I'm struggling to get a variable entry getter from another class, i know i have to pass the instance of the class im getting the variable from, but how would i use the actual variable in the class i would like to use it in?
Here is the class:
class NewEmployee:
def __init__(self, master):
self.master = master
self.master.title("Jans Corp")
self.master.configure(background="lightgrey")
self.master.geometry("300x500")
self.FirstNameEntry = tk.Entry(self.master)
self.SurnameEntry = tk.Entry(self.master)
self.AgeEntry = tk.Entry(self.master)
self.PostcodeEntry = tk.Entry(self.master)
Here is where i'd like to use self.FirstNameEntry.get()
class Database(NewEmployee):
def __init__(self, master):
conn = sqlite3.connect(':memory:')
c = conn.cursor()
def addEmployees(self):
with conn:
c.execute("INSERT INTO Employees VALUES (:first, :last, :age)",
{'first':emp.first, 'last':emp.last, 'age':emp.age, }) <-----
Here you can see i have added the instance of the class im want to get the info from but do not know how to call "FirstNameEntry.get()" in the database class.
Would i have to use NewEmployee.FirstNameEntry() or would it be something else?
Here you can see i have added the instance of the class im want to get the info from...
That is not how classes work. Inheritance is a "is a" relationship. Your code is saying that your Database class "is a" NewEmployee, which is clearly not true. Databases are not employees.
The way to do this is to pass an instance of Employee to your addEmployee method. Roughly speaking, it looks like this:
emp = NewEmployee()
db = Database()
db.addEmployee(emp)
That means that you need to modify addEmployee to accept the employee to be added, and to call the get method of the widgets:
class Database():
...
def addEmployee(self, emp):
with conn:
c.execute(..., {'first':emp.FirstNameEntry.get(),...})
Note that it's rather unusual to have something like an Employee class that has widgets in it. Usually it just has data, and you would have a separate class to represent the GUI (ie: you have one GUI but many employees)
For example, your GUI class would be:
class EmployeeForm():
def __init__(self):
...
self.firstNameEntry = tk.Entry(...)
...
You would create one instance of this at the start of your program:
class TheApplication():
def __init__(self):
...
self.employeeForm = EmployeeForm()
...
You might then have an Employee class that looks something like this:
class Employee():
def __init__(self, first, last, etc):
self.first = first
self.last = last
self.etc = etc
Then, you might add a getEmployee method in your GUI class like this:
class EmployeeForm():
...
def getEmployee(self):
first = self.firstEntry.get()
last = self.lastEntry.get()
etc = self.etcEntry.get()
return Employee(first, last, etc)
Then, somewhere in your code -- maybe the "save" button on the form or application -- you would do something like this:
employee = self.employeeForm.getEmployee()
db.addEmployee(employee)
That's not another class ... that's a subclass. You would call it the same way you defined it: with self. Also, remember that with all subclasses, you have to call the parent __init__ from the subclass.
class Database(NewEmployee):
def __init__(self, master):
super().__init__(master) #call parent __init__
conn = sqlite3.connect(':memory:')
c = conn.cursor()
def addEmployees(self):
with conn:
c.execute("INSERT INTO Employees VALUES (:first, :last, :age)",
{'first':self.FirstNameEntry.get(), 'last':self.SurnameEntry.get(), 'age':self.AgeEntry.get(), })

how to access or use name in class ? Python

Python Masters.
I am so curious about class name space.
for example, there some class definition.
import Another_class
class Some_class:
def __init__(self, city):
self.city = city
if self.city == "newyork":
newyork_info = Another_class(some_param)
def state(self):
if self.city == "newyork":
newyork_wether = newyork_info.get_wether()
newyork_population = newyork_info.get_population()
so, i tend to use "newyork_info" in another functions.
NameError: name 'newyork_info' is not defined
but i could not use the name in init function.
how could i solve it? Is there are good way? :)
You must assign newyork_info to the class.
self.newyork_info = Another_class(some_param)

Comparing string to list of objects with repr

If I have a class called Person, and this class contains the name, age, etc. of each person, if I fill a list with the Person class I want to check if a name is in the list without creating a new list of just the names. If I use repr and return repr(self.name), I can print the list and have it return a list of the names of each person in the list. If I then check if "steve" is in the list it returns False. I am guessing this is because it is comparing "steve" to each class, not the class repr. Is there a way to do this without creating a new list?
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return repr(self.name)
people = [Person('steve', 25), Person('dan', 30),Person('heather', 19)]
print(people)
print('steve' in people)
Use any():
any(p.name == 'steve' for p in people)
#True
...and a fail test:
any(p.name == 'bob' for p in people)
#False
However, to be able to use in, you need to define __eq__, not __repr__:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, s):
return s == self.name
and now it works as intended:
'steve' in people
#True
'bob' in people
#False
The easiest way probably is to just do this manually:
steve_in_people = any('steve' == repr(person) for person in people)
You could also use a bloom filter to quickly determine if 'steve' isn't in your list, but there's no way to know for sure without checking the list. You could also use something like a B-Tree to perform this check very quickly (worst case would be something like O(m) where m is the length of the string you're looking for).
If you don't want fancy data structures and would prefer to be pythonic... well then, use a set, which will give you very high-performance in checks (virtually constant-time):
names = {repr(person) for person in people}
steve_in_people = 'steve' in names
#JoeIddon makes a good point about modifying the class to easily support this behavior. I'll suggest one further improvement:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return self.name
def __eq__(self, s):
return s == self.name
# This will allow you to quickly find this object in a set using its name
def __hash__(self):
return hash(self.name)
Now you can just create a set of Person objects and search into it using a name string:
person_set = set(all_person_objects)
steve_in_people = 'steve' in person_set

Resources