I have written this code:
class component(object):
def __init__(self,
name = None,
height = None,
width = None):
self.name = name
self.height = height
self.width = width
class system(object):
def __init__(self,
name = None,
lines = None,
*component):
self.name = name
self.component = component
if lines is None:
self.lines = []
else:
self.lines = lines
def writeTOFile(self,
*component):
self.component = component
line =" "
self.lines.append(line)
line= "#----------------------------------------- SYSTEM ---------------------------------------#"
self.lines.append(line)
Component1 = component ( name = 'C1',
height = 500,
width = 400)
Component2 = component ( name = 'C2',
height = 600,
width = 700)
system1 = system(Component1, Component2)
system1.writeTOFile(Component1, Component2)
and I get the error :
Traceback (most recent call last):
File "C:\Python27\Work\trial2.py", line 46, in <module>
system1.writeTOFile(Component1, Component2)
File "C:\Python27\Work\trial2.py", line 32, in writeTOFile
self.lines.append(line)
AttributeError: 'component' object has no attribute 'append'
And I don't really know how to fix it.
Also is there a way for defining my system1 as system(Component) where component = [Component1, Component2, ...Componentn] ?
Thanks in adavance
You've got things out of order in your __init__:
def __init__(self, *component, **kwargs):
self.name = kwargs.get('name')
self.component = component
self.lines = kwargs.get('lines', [])
Will work. You need lines and name to be after the * item that collects the component.
In Python 2, you can't then have named attributes after a *, so you need to instead use **kwargs and get('name') and get('lines') from the kwargs.
get just returns None if you don't supply a default, so you'll get self.name = None here. If you want to specify a default name, you can do
self.name = kwargs.get('name', 'defaultname')
like I did for lines.
in line 32 you use self.lines.append(line).
But lines is a member of the class system initialized with Component2, which type is the class component that does not have the method append.
The problem is in the fact that when defining system you pass Component1 as a line argument in constructor. Since python does all the operations he can and not checking for the argument types if the operation can be done legally, this passes.
Maybe it would be a nice idea in the system constructor to check if the given argument lines is really of type list, and maybe writing something like:
if lines is None or not isinstance(lines, list):
self.lines = []
else:
self.lines = lines
That way, you would know about the problem before you try appending to the non-list object.
And as for the second part of your question, you can do it exactly like you suggested:
system1 = system([Component1, Component2, MyComponent], [])
(if you, for example, want to make a system with 3 components, and an empty list as an "console" for lines)
Related
So I'm fairly new to python and I wanted to make a program that creates an object of a class from the user input, so I don´t have to make 10 empty profiles. I´ve tried it like this, knowing that it'll be false, but I think it demonstrates my problem.
class Profile():
def __init__(self, weight, height):
self.weight = weight
self.height = height
def create_object():
name = input("What's your name?")
new_weight = input("What's your height?")
new_height = input("What's your weight?")
name = Profile(new_weight, new_height)
return name
If i now want to create the object:
>>> create_object()
What's your name? test
What's your height? 23
What's your weight? 33
<__main__.Profile object at 0x000002564D7CFE80>
>>> test()
Traceback (most recent call last):
File "<pyshell#35>", line 1, in <module>
test()
NameError: name 'test' is not defined
or should I use a dictonary and if yes, how?
In my experience, it is not necessary to specifically name each instance of a class. Instead, you could do as some commenters suggested and add each new object to a dictionary, like so:
object_dict = {}
for i in range(10):
name = input("what's your name")
object_dict[name] = create_object()
The difference to note here is that I moved the name portion of your funtion to outside of the create_object() scope. To my knowledge, there are no "easy" or "clean" ways to create variables in python with a string as the user input (especially not if you are new to python).
If what you are doing doesn't necessarily need the name, and the user details are only for data storage, then it would be more concise to save the name as a property in your class, like so:
class Profile():
def __init__(self, weight, height, name):
self.weight = weight
self.height = height
self.name = name
And then when you generate the profiles, simply add them to a list:
for i in range(10):
object_list.append(create_object())
One last thing, the input method always returns a string. So if you plan to do math with the weight and height values, you will need to change the input from a string to a number, which you can do by surrounding the input() call with int() like
weight = int(input("What's your weight?"))
height = int(input("What's your height?"))
I have a file called Model.py that contains the code
class ModelCalibrator():
def __init__(self):
self.file1 = 'Mortality_Population.txt'
self.file2 = 'Deaths_1x1_adj.txt'
self.MaxAge = 101
self.MinAge = 18
self.basisAges = np.array([18, 50, 100])[np.newaxis]
self.mortalityData = PopulationData()
self.deathRateData = DeathRateData()
(self.age, self.phis) = computeBasisFunctions(ModelCalibrator)
def computeBasisFunctions(mc):
MaxAge = mc.MaxAge
MinAge = mc.MinAge
age = np.arange(MinAge, MaxAge)[np.newaxis]
basisAges = mc.basisAges
#calculations
...
return (age, phis)
In a separate test.py file I am running nosetests using the code
def testMC():
data = ModelCalibrator()
Phi = data.phis()
assert_equal(Phi[0], 1)
This keeps telling me that I have an attributeerror: type object 'ModelCalibrator' has no attributes 'MaxAge'. Can anyone tell me where I am going wrong please?
On this line, you are passing in the class instead of the object. Try replacing ModelCalibrator with self. The class is only a template for the object. self represents the current object with all of the properties set.
(self.age, self.phis) = computeBasisFunctions(self)
Alternatively, if you want these to be accessible without an object, you could set MaxAge and MinAge as class variables by moving them outside of the __init__ function, but inside the class as shown here.
I'm using a not-well-known framework called IPKISS; hopefully, this does not matter.
from ipkiss.all import *
class ElectrodePair(Structure):
"""An electrode component to be used for a PPLN design."""
__name_prefix__ = "ELECTRODE_PAIR"
width = PositiveNumberProperty(required = True)
height = PositiveNumberProperty(required = True)
seperation = PositiveNumberProperty(required = True)
lay1 = Layer(number = 1, name = "boundaries")
def define_elements(self, elems):
left = ShapeRectangle(center = (-self.seperation*0.5,0.), box_size = (self.width, self.height))
right = ShapeRectangle(center = (self.seperation*0.5,0.), box_size = (self.width, self.height))
elems += Boundary(layer = self.lay1, shape = left)
elems += Boundary(layer = self.lay1, shape = right)
return elems
class ElectrodeStructure(ElectrodePair):
"""An array of electrodes."""
__name_prefix__ = "ELECTRODE_STRUCTURE"
amount = PositiveNumberProperty(required = True)
spacing = PositiveNumberProperty(required = True)
def define_elements(self, elems):
electrodePair = ElectrodePair.__init__(self)
elems += ARefX(reference = electrodePair, origin = (0,0), period_1d = self.spacing, n_o_periods_1d = self.amount)
return elems
def main():
FILE_NAME = "ElectrodeArray.gds"
electrodeArray = ElectrodeStructure(amount = 10, height = 100., seperation = 20, spacing = 10., width = 2.)
electrodeArray.write_gdsii(FILE_NAME)
if __name__ == "__main__":
main()
I have no idea why this is erroring. The error is:
File "/usr/local/lib/python2.7/dist-packages/IPKISS-2.4_ce-py2.7.egg/ipcore/properties/initializer.py",
line 327, in __init__ raise IpcoreAttributeException("Required property '%s' is not found in keyword arguments of '%s' initialization." % (p, str(type(self))))
ipcore.exceptions.exc.IpcoreAttributeException: Required property 'amount' is not found in keyword arguments of '<class '__main__.ElectrodeStructure'>' initialization.
It seems as though it's not happy with how I've passed my arguments, I've tried heaps of stuff and cannot get it to work. Advice would be much appreciated.
I suspect the error is due to electrodePair = ElectrodePair.__init__(self).
Thank you for your time.
You have to add __init__ method to your ElectrodeStructure class, that - as #hd1 has pointed out - has to set amount:
class ElectrodeStructure(ElectrodePair):
def __init__(self, amount):
ElectrodePair.__init__(self)
The way you call ElectrodePair.__init__ is wrong, since in the absence of ElectrodeStructure.__init__ in your class the former will be called automatically
EDIT:
Couple of things I've noticed on re-reading - you inherit from a class, and then within a class method you create an object of the parent class. Something is wrong here
class ElectrodeStructure(ElectrodePair):
[...]
def define_elements(self, elems):
electrodePair = ElectrodePair.__init__(self)
[...]
When you create a new ElectrodeStructure in main(), you're passing keword arguments. Becuase you're not defining an __init__ function in ElectrodeStructure, the super's __init__ is being called with those arguments (including amount, so there's no error).
Then in define_elements, you're calling __init__ again, except you aren't passing in any arguments, which is causing the error.
Additionally, this statement:
electrodePair = ElectrodePair.__init__(self)
Is assigning the return value (likely None) of ElectrodePair.__init__(self) to electrodePair. I suspect you want something more like the following:
electrodePair = ElectrodePair(amount=1, etc.)
It looks like you want composition, not inheritance; you could initialize your subclass in a proper __init__ function (as #volcano describes), or just create an ElectrodePair class member, and not inherit at all.
Note: I see that I need to more clearly work out what it is that I want each property/descriptor/class/method to do before I ask how to do it! I don't think my question can be answered at this time. Thanks all for helping me out.
Thanks to icktoofay and BrenBarn, I'm starting to understand discriptors and properties, but now I have a slightly harder question to ask:
I see now how these work:
class Blub(object):
def __get__(self, instance, owner):
print('Blub gets ' + instance._blub)
return instance._blub
def __set__(self, instance, value):
print('Blub becomes ' + value)
instance._blub = value
class Quish(object):
blub = Blub()
def __init__(self, value):
self.blub = value
And how a = Quish('one') works (produces "Blub becomes one") but take a gander at this code:
import os
import glob
class Index(object):
def __init__(self, dir=os.getcwd()):
self.name = dir #index name is directory of indexes
# index is the list of indexes
self.index = glob.glob(os.path.join(self.name, 'BatchStarted*'))
# which is the pointer to the index (index[which] == BatchStarted_12312013_115959.txt)
self.which = 0
# self.file = self.File(self.index[self.which])
def get(self):
return self.index[self.which]
def next(self):
self.which += 1
if self.which < len(self.index):
return self.get()
else:
# loop back to the first
self.which = 0
return None
def back(self):
if self.which > 0:
self.which -= 1
return self.get()
class File(object):
def __init__(self, file):
# if the file exists, we'll use it.
if os.path.isfile(file):
self.name = file
# otherwise, our name is none and we return.
else:
self.name = None
return None
# 'file' attribute is the actual file object
self.file = open(self.name, 'r')
self.line = Lines(self.file)
class Lines(object):
# pass through the actual file object (not filename)
def __init__(self, file):
self.file = file
# line is the list if this file's lines
self.line = self.file.readlines()
self.which = 0
self.extension = Extension(self.line[self.which])
def __get__(self):
return self.line[self.which]
def __set__(self, value):
self.which = value
def next(self):
self.which += 1
return self.__get__()
def back(self):
self.which -= 1
return self.__get__()
class Extension(object):
def __init__(self, lineStr):
# check to make sure a string is passed
if lineStr:
self.lineStr = lineStr
self.line = self.lineStr.split('|')
self.pathStr = self.line[0]
self.path = self.pathStr.split('\\')
self.fileStr = self.path[-1]
self.file = self.fileStr.split('.')
else:
self.lineStr = None
def __get__(self):
self.line = self.lineStr.split('|')
self.pathStr = self.line[0]
self.path = self.pathStr.split('\\')
self.fileStr = self.path[-1]
self.file = self.fileStr.split('.')
return self.file[-1]
def __set__(self, ext):
self.file[-1] = ext
self.fileStr = '.'.join(self.file)
self.path[-1] = fileStr
self.pathStr = '\\'.join(self.path)
self.line[0] = self.pathStr
self.lineStr = '|'.join(self.line)
Firstly, there may be some typos in here because I've been working on it and leaving it half-arsed. That's not my point. My point is that in icktoofay's example, nothing gets passed to Blub(). Is there any way to do what I'm doing here, that is set some "self" attributes and after doing some processing, taking that and passing it to the next class? Would this be better suited for a property?
I would like to have it so that:
>>> i = Index() # i contains list of index files
>>> f = File(i.get()) # f is now one of those files
>>> f.line
'\\\\server\\share\\folder\\file0.txt|Name|Sean|Date|10-20-2000|Type|1'
>>> f.line.extension
'txt'
>>> f.line.extension = 'rtf'
>>> f.line
'\\\\server\\share\\folder\\file0.rtf|Name|Sean|Date|10-20-2000|Type|1'
You can do that, but the issue there is less about properties/descriptors and more about creating classes that give the behavior you want.
So, when you do f.line, that is some object. When you do f.line.extension, that is doing (f.line).extension --- that is, it first evalautes f.line and then gets the extension attribute of whatever f.line is.
The important thing here is that f.line cannot know whether you are later going to try to access its extension. So you can't have f.line do one thing for "plain" f.line and another thing for f.line.extension. The f.line part has to be the same in both, and the extension part can't change that.
The solution for what you seem to want to do is to make f.line return some kind of object that in some way looks or works like a string, but also allows setting attributes and updating itself accordingly. Exactly how you do this depends on how much you need f.lines to behave like a string and how much you need it to do other stuff. Basically you need f.line to be a "gatekeeper" object that handles some operations by acting like a string (e.g., you apparently want it to display as a string), and handles other objects in custom ways (e.g., you apparently want to be able to set an extension attribute on it and have that update its contents).
Here's a simplistic example:
class Line(object):
def __init__(self, txt):
self.base, self.extension = txt.split('.')
def __str__(self):
return self.base + "." + self.extension
Now you can do:
>>> line = Line('file.txt')
>>> print line
file.txt
>>> line.extension
'txt'
>>> line.extension = 'foo'
>>> print line
file.foo
However, notice that I did print line, not just line. By writing a __str__ method, I defined the behavior that happens when you do print line. But if you evaluate it "raw" without printing it, you'll see it's not really a string:
>>> line
<__main__.Line object at 0x000000000233D278>
You could override this behavior as well (by defining __repr__), but do you want to? That depends on how you want to use line. The point is that you need to decide what you want your line to do in what situations, and then craft a class that does that.
I am having some problem accessing class instances. I am calling the class from a procedure, name of instance is defined in some variable. I want the instance name to be created of that value and then want to access it, but when i access it is giving error. Can some one please help to resolve this issue.
class myclass:
def __init__(self,object):
self.name = object
def mydef():
global a1
b = "a1"
b = myclass(b)
mydef()
print a1.name
Second Problem:
In my actual script, I have to create a large number of such instances from this function (around 100). So defining their name as global would be painful, is there a way i could access those instances outside function without having to declare them as global.
Modification:
class myclass:
def __init__(self,object,typename):
self.name = object
self.typeid = typename
def mydef():
file_han = open(file,"r")
while True:
line = file_han.readline()
if not line:
break
start = line.find('"')
end = line.find('"',start+1)
string_f = line[start+1:end]
myclass(string_f,'a11')
mydef(file)
print def.name
print def.typeid
File Contents are :
a11 "def"
a11 "ghi"
a11 "eff"
Here's how I'd do it. I don't know why you're messing around with globals, if you'd care to explain, I'll update my answer.
class Myclass(object):
def __init__(self, name):
self.name = name
def mydef():
return Myclass("a1")
a1 = mydef()
print a1.name
Gather your instances in a list:
instances = []
for x in range(1000):
instances.append(Myclass("Instance {0}".format(x)))
print instance[42].name
Note the changes:
Class names should be capitalized
Use object as the base class of your classes (since python 2.2, but no longer necessary in 3.x)
Don't shadow the built-in object with your parameter name
Just use the string "a1" directly as a parameter instead of assigning it to a variable
Return something from the function instead of passing the result by global variable
RE: Comment
You haven't said anything about the format of these files, so I'll just give an example where the file to be read contains one class name per line, and nothing else:
def mydef(filename):
ret = []
with open(filename) as f:
for line in f:
# Call `strip` on line to remove newline and surrounding whitespace
ret.append(Myclass(line.strip()))
return ret
So if you have several files and wish to add all your instances from all your files to a large list, do it like this:
instances = []
for filename in ["myfile1", "myfile2", "myfile3"]:
instances.extend(mydef(filename))
RE: OP Edit
def mydef(filename):
ret = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret.append(Myclass(string_f))
return ret
i = mydef("name_of_file")
RE: Comment
Oh, you want to access them by name. Then return a dict instead:
def mydef(filename):
ret = {}
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret[string_f] = Myclass(string_f)
return ret
i = mydef("name_of_file")
print i["ghi"].name # should print "ghi"
RE: Comment
If I understand you correctly, you want to have it both ways -- index by both line number and name. Well then why don't you return both a list and a dictionary?
def mydef(filename):
d = {}
L = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
instance = Myclass(string_f)
d[string_f] = instance
L.append(instance)
return L, d
L, d = mydef("name_of_file")
print d["ghi"].name
print L[3]
print L.index(d["ghi"])
You could use class as repository for your instances, for example
class Named(object):
def __init__(self,name):
self.name = name
def __new__(cls,name):
instance = super(type,cls).__new__(cls,name)
setattr(cls,name,instance)
return instance
def __repr__(self):
return 'Named[%s]'%self.name
Named('hello')
Named('x123')
Named('this is not valid attribute name, but also working')
print(Named.hello,Named.x123,getattr(Named,'this is not valid attribute name, but also working'))