Despite of this question being answered:
How to import a class with composition from a module?
I still don't understand the functioning of importing composite classes in python.
The following is a kind of long code but very basic. In a file called example.py there are three classes, Employee, Car and Company. Company calls Employee and employee calls Car.
Employee has a static method which does not work, simply returns a variable that does not exists.
example.py:
class Employee():
def __init__(self,name):
self.name = name
def add_employee_atribute(self):
if ' ' in self.name:
self.completename='created with method class: ^' + self.name.title()
def upperit(self):
return self.name.upper()
#staticmethod
def empstatic(myname):
return myname+myname
#staticmethod
def empstatic_wrong():
# this is wrong
return ERROR
def add_car(self,make):
self.car = Car(make)
class Car():
def __init__(self, make):
self.car = make
class Company():
def __init__(self,name,people):
self.name=name
self.employees=[]
for person in people:
self.employees.append(Employee(person))
def get_all_employess(self):
return 'These are all: ' + ', '.join([e.name for e in self.employees])
def get_employee(self,name):
for e in self.employees:
if e.name == name:
return e
Now if I want to use Company in a file I go:
work.py:
from example import Company
C = Company('kodak',['peter','john smith'])
C.employees[1].add_employee_atribute()
C.get_all_employess()
peter = C.get_employee('peter')
peter.add_car('BMW')
This all works.
Python seems to evaluate the imported code (Company) in work.py in a way that realises that Company needs Employee and Employee needs Car. Very clever. So it looks like python looks for the classes when they are called. Nevertheless python does not realise that the variable 'ERROR' does not exist.
So what puzzles me is the fact that python is able to distinguish, look for the composite classes but not for the variables.
Some explanation about this?
Related
I'm a beginner. I'm doing my best. Please go easy on me. My task is to create a class called "person" with one method "hello" and one attribute "name" which represents the name of a person. In the end it should print "My name is X and I am a Y, where X is the sys.argv[1] name and Y is the name of the class. I'm supposed to instantiate an object of the class, run the hello method and print the name of the class. My brain is a bit fried and I'm at a loss. Please help. I feel like I'm moving in circles and getting no where. Here's what I've got so far:
import sys
class person():
def __init__(self, name):
self.name = name
def hello(self):
print(f'My name is {self.name} and I am a {__class__.__name__}.')
print(person1.hello())
person(sys.argv[1])
person1=person(sys.argv[1])
print(str(person.__class__))
So far its not printing anything at all.
This one is working.
class Person():
def __init__(self, name):
self.name = name
def hello(self):
print(f'My name is {self.name} and I am a {__class__.__name__}.')
my_person = Person('John')
my_person.hello()
The Output:
My name is John and I am a person.
Suggestion:
For convention classes are named with first letter Capital to distinguish of the instances.
I'am using more class based programs, however in some cases it's not handy to provide all self.paramets into a class.
In those cases I want to use a regular input into a function in a class. I figured out a way to achieve both inputs, let me show this in following script:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def myfunc(a):
if (type(a) == str):
name = a
else:
name = a.name
print("Hello my name is " + name)
p1 = Person("John", 36)
p1.myfunc()
print("---------------------")
Person.myfunc("Harry")
Output:
Hello my name is John
---------------------
Hello my name is Harry
First, the name is initialized by the classes self.params.
Second, the name is provided in the method within the class as a string.
So a type check is necessary.
However I don't think this is a clean approach, because when I have >30 methods I need to implement these type checks again, including upcoming type-error results.
Does anyone know a better approach?
The simplest solution is to implement a __str__ method for your class. This method will be called whenever something tries to convert an instance of the class to a string.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return self.name
p = Person('Jane', 25)
print('Hello', p)
'Hello Jane'
The approach might be just wrong to begin with, but I'm trying to do the following:
class Material:
pass
class Vacuum(Material):
def __str__(self):
return 'vacuum'
class Aluminum(Material):
def __str__(self):
return 'aluminum'
class Graphite(Material):
def __str__(self):
return 'graphite'
class Beryllium(Material):
def __str__(self):
return 'beryllium'
I have different pieces of code that deals with different materials. Instead of passing a string as argument to that other pieces I would prefer to give it objects. This allows to have tab-completion with ipython and it is also a way to enforce the type.
To avoid changing the already written pieces, those will just do str(argument): if it is a string it recovers the old behavior, if it is one of the objects it will work.
The question is now: I want to support a given list of materials:
allowed_materials = ['vacuum', 'aluminum', 'graphite',]
and that list might be growing. Instead of manually writing the classes, how could I generate them based on the list?
You can define a metaclass that can generate your classes for you.
class mattype(type):
def __new__(mcls, name, bases=(), d=None):
def __str__(self):
return name.lower()
if not d:
d = {}
d['__str__'] = __str__
bases = (*bases, Material)
return super().__new__(mcls, name.title(), bases, d)
allowed_materials = ['vacuum', 'aluminum', 'graphite',]
classes = {name: mattype(name) for name in allowed_materials}
str(classes['vacuum']())
# 'vacuum'
If you do not need different class name for different material you can simply initialise it inside the material class. If not I will delete my answer.
class Material:
def __init__(self,name):
self.name=name
def __str__(self):
return self.name
allowed_materials = ['vacuum', 'aluminum', 'graphite',]
obj_lst=[Material(material) for material in allowed_materials]
for obj in obj_lst:
print(str(obj))
output:
vacuum
aluminum
graphite
I ended up doing the following, also adding objects to the module.
import sys
class Material:
def __str__(self):
return self.__class__.__name__
pass
print(sys.modules[__name__])
_materials = ['Copper', 'Vacuum']
for m in _materials:
setattr(sys.modules[__name__], m, type(m, (Material,), {})())
I'm reading Lutz & Ascher - Learn Python and I found this as a solution to one of the exercises:
class Lunch:
def __init__(self):
self.cust = Customer()
self.empl = Employee()
def order(self, foodName):
# start a Customer order simulation
self.cust.placeOrder(foodName, self.empl)
def result(self):
# ask the Customer what kind of Food it has
self.cust.printFood()
class Customer:
def __init__(self):
# initialize my food to None
self.food = None
def placeOrder(self, foodName, employee):
# place order with an Employee
self.food = employee.takeOrder(foodName)
def printFood(self):
# print the name of my food
print self.food.name
class Employee:
def takeOrder(self, foodName):
# return a Food, with requested name
return Food(foodName)
class Food:
def __init__(self, name):
# store food name
self.name = name
if __name__ == '__main__':
x = Lunch()
x.order('burritos')
x.result()
x.order('pizza')
x.result()`
What I don't understand is how the definition of the method placeOrder inside the customer class works, more specifically, there is no class employee (just Employee) whose method placeOrder could be used.
def placeOrder(self, foodName, employee):
# place order with an Employee
self.food = employee.takeOrder(foodName)
you may need to read a little bit about object oriented programming, and dynamic typing to grasp this. So basically, employee is an argument which will be passed at runtime, its type will be determined after the call to placeOrder. if you call PlaceOrder and put an instance of Employee or any class that has method takeOrder(), it will work. Imho, you should try to code an example from the beginning and test out what you learn, it will help you learn Python faster
`
I have no idea what is wrong! This is a very simple program and I have done a lot head banging! Please someone enlighten me!
This a lab problem from the CSE 111 - Programming Language II course. They teach Java at the university and the code I wrote in Java works fine.
I just have to create a Student class with some fields to hold the basic information about a student with methods to get and set the attributes. Then create an instance of that class and tryout the methods.
But every time I run this program the following error occurs:
TypeError: set_name() takes exactly 1 positional argument (2 given)
Here is the code I wrote.
class Student:
'''Student class'''
name = None
id = 0
address = None
cgpa = None
def get_name():
return name
def set_name(n):
name = n
def get_id():
return id
def set_id(i):
id = i
def get_address():
return address
def set_address(a):
address = a
def get_cgpa():
return cgpa
def set_cgpa(c):
cgpa = c
#An object of Student class
jack = Student()
jack.set_name('jacky')
print(jack.get_name())
You're not accepting a reference to your instance as the first argument to that method, i.e. your set_name() should be written:
def set_name(self, n):
self.name = n
This is somewhat different from other languages where there is a built-in keyword (such as this) that refers to the current object. Python passes that reference explicitly, as an argument to the method.
All your other methods must be modified similarly.
Note that just setting name = n sets a local variable name which goes away when the method ends; it does not set anything on the instance. You have to explicitly set self.name if you want an instance attribute.
Also, and this is a matter of style, but you do not usually write set and get methods in Python. It is normal practice to set and get attributes directly. If you want to do validation of values, use a property instead. So basically, none of your methods are actually necessary in good style.
However, you don't have an __init__() method. Usually you would pass the desired attributes of the instance when instantiating the class and save these on the instance.
class Student:
def __init__(self, name, id, address, cgpa):
self.name = name
self.id = id
self.address = address
self.cgpa = cgpa
herman = Student("Herman Munster", 12345, "1313 Mockingbird Lane", 4.0)
Try this:
import sys
class Student:
'''Student class'''
self.name = None
self.id = 0
self.address = None
self.cgpa = None
def get_name(self):
return self.name
def set_name(self, n):
self.name = n
def get_id(self):
return self.id
def set_id(self, i):
self.id = i
def get_address(self):
return self.address
def set_address(self, a):
self.address = a
def get_cgpa(self):
return self.cgpa
def set_cgpa(self, c):
self.cgpa = c
You need to pass self as the first argument to each member function of the class. Member variables must then be referred to with self, i.e. self.name. Furthermore, you may wish to include an __init__() function; this serves usually to initialize any member variables, and is called at the instantiation of the class.
Take a look at the Python documentation here for some examples on well-formed classes: http://docs.python.org/tutorial/classes.html#random-remarks
In Python, you need to pass in self for each of your member functions. You also need to reference class variables as self.x, if you want them to take an effect.
Here are a couple examples that you need to apply to the rest of your code.
def set_name(self, n):
self.name = n
def get_cgpa(self):
return self.cgpa
There is some explanation for why this is the case in the documentation.
This is because first argument of methods is self - the class instance.
See What is the purpose of self?
and http://docs.python.org/tutorial/classes.html#class-objects