how to fix the _getitem__ method - python
def pnamedtuple(type_name, field_names, mutable=False):
pass
class type_name:
def __init__(self, x, y):
self.x = x
self.y = y
self._fields = ['x','y']
self._mutable = False
def get_x(self):
return self.x
def get_y(self):
return self.y
def __getitem__(self,i):
if i > 1 or i <0:
raise IndexError
if i == 0 or i == 'x':
return self.get_x():
if i == 1 or i == 'y':
return self.get_y():
the getitem method to overload the [] (indexing operator) for this class: an index of 0 returns the value of the first field name in the field_names list; an index of 1 returns the value of the second field name in the field_names list, etc. Also, the index can be a string with the named field. So, for p = Point(1,2) writing p.get_x(), or p[0]), or p['x'] returns a result of 1. Raise an IndexError with an appropriate message if the index is out of bounds int or a string that does not name a field.
I am not sure how to fix the getitme function. below is the bsc.txt
c-->t1 = Triple1(1,2,3)
c-->t2 = Triple2(1,2,3)
c-->t3 = Triple3(1,2,3)
# Test __getitem__ functions
e-->t1[0]-->1
e-->t1[1]-->2
e-->t1[2]-->3
e-->t1['a']-->1
e-->t1['b']-->2
e-->t1['c']-->3
^-->t1[4]-->IndexError
^-->t1['d']-->IndexError
^-->t1[3.2]-->IndexError
can someone tell how to fix my _getitem _ function to get the output in bsc.txt? many thanks.
You've spelled __getitem__ incorrectly. Magic methods require two __ underscores before and after them.
So you haven't overloaded the original __getitem__ method, you've simply created a new method named _getitem_.
Python 3 does not allow strings and integers to be compared with > or <; it's best to stick with == if you don't yet know the type of i. You could use isinstance, but here you can easily convert the only two valid integer values to strings (or vice versa), then work only on strings.
def __getitem__(self, i):
if i == 0:
i = "x"
elif i == 1:
i = "y"
if i == "x":
return self.get_x()
elif i == "y":
return self.get_y()
else:
raise IndexError("Invalid key: {}".format(i))
your function is interesting, but there are some issues with it:
In python 3 you can't compare string with numbers, so you first should check with == against know values and or types. For example
def __getitem__(self,i):
if i in {0,"x"}:
return self.x
elif i in {1,"y"}:
return self.y
else:
raise IndexError(repr(i))
But defined like that (in your code or in the example above) for an instance t1 this t1[X] for all string X others than "x" or "y" will always fail as you don't adjust it for any other value. And that is because
pnamedtuple looks like you want for it to be a factory like collections.namedtuple, but it fail to be general enough because you don't use any the arguments of your function at all. And no, type_name is not used either, whatever value it have is throw away when you make the class declaration.
how to fix it?
You need other ways to store the value of the fields and its respective name, for example a dictionary lets call it self._data
To remember how you called yours field, use the argument of your function, for instance self._fields = field_names
To accept a unknown number of arguments use * like __init__(self, *values) then verify that you have the same numbers of values and fields and build your data structure of point 1 (the dictionary)
Once that those are ready then __getitem__ become something like:
def __getitem__(self, key):
if key in self._data:
return self._data[key]
elif isintance(key,int) and 0 <= key < len(self._fields):
return self._data[ self._fields[key] ]
else:
raise IndexError( repr(key) )
or you can simple inherit from a appropriate namedtuple and the only thing you need to do is overwrite its __getitem__ like
def __getitem__(self,key):
if key in self._fields:
return getattr(self,key)
return super().__getitem__(key)
Related
Detecting Duplicates in Class Instance's Variable Values
class Translator(object): def __init__(self, tracking_col='tracking_id', coding_col='coding', qualifying_code_col='qualifying_code', translation_col='translation'): self._results = [] self.tracking_col = tracking_col self.data_col = coding_col self.definition_col = qualifying_code_col self.translation_col = translation_col self.__validate_parameters(self.__dict__) def __validate_parameters(self, variable_values): class_values = {} for key, value in variable_values.items(): if type(value) is str: class_values.setdefault(value, set()).add(key) for key, values in class_values.items(): # If there is more than one value, there is a duplicate if len(values) > 1: raise Exception('Duplicate column names exist in parameters. \'{}\' are set to \'{}\'. ' 'Do not use duplicate column names.'.format(values, key)) This class cannot have the duplicate values for any of the 'col' variables. If duplicate values exist, logic further in the class may not crash but will create unpredictable results. Upon instantiation my function __validate_parameters will detect duplicate values and raise an Exception. The problem is I am dumping all the values out to a dictionary, iterating to create another dictionary, and finally manually raising an exception (which from what I've been told is the wrong thing to do in any situation). It's also rather verbose. Is there a shorter and more concise way to validate for duplicates while propogating an error up without the complexity above?
There is nothing wrong with manually raising an exception. Collecting your cols in some collection will make validation easier: class Translator(object): def __init__(self, tracking_col=..., coding_col=..., qualifying_code_col=..., translation_col=...): self._results = [] self.cols = [tracking_col, coding_col, qualifying_code_col, translation_col] self.validate_cols(self) def validate_cols(self): if len(self.cols) > len(set(self.cols)): raise ... #property def tracking_col(self): return cols[0] # ...
You could make the constructor take a dictionary instead of individual variables, e.g. class Translator(object): def __init__(self, cols={}): defaults = { "tracking_col" : "tracking_id", "coding_col" : "coding", "qualifying_code_col" : "qualifying_code", "translation_col" : "translation" } for d in defaults: if d not in cols: cols[d] = defaults[d] self.__validate_parameters(cols) def __validate_parameters(self, d): import Counter c = Counter.Counter(d.values()) if any(cnt > 1 for cnt in c.values()): raise Exception("Duplicate values found: '%s'" % str(c)) (Code not tested)
While evaluating length of a list that is defined as a class
For example, I got a class named stack, class stack: #Will be used for probable files! def __init__(self): self.data = [] def add(self, element): self.data.append(element) def number_of_elements(self): return len(self.data) def stackType(self): if self.number_of_elements == 0: return 0 elif self.number_of_elements == 1: return 1 else: return -1 I then do this: foo = stack() print foo.stackType() I get -1 however I was expecting a return of 1 Why is it so and how can I handle with it?
That's because you did not call the call the method self.number_of_elements; you merely tested to see if it equalled 0 or 1. Modify your code to actually call the method using this syntax: self.number_of_elements() [notice the use of () to call the method]: def stackType(self) : if self.number_of_elements() == 0 : return 0 elif self.number_of_elements() == 1 : return 1 else : return -1 You could also have written it like this: def stack_type(self): n = self.number_of_elements() return -1 if n > 1 else n which would be an improvement because number_of_elements() will be called once only. In your code the method could be called twice. I renamed the function to be consistent with the Python method naming conventions set out in PEP8.
Because self.number_of_elements is not the same as self.number_of_elements()! The former is a reference to the function, the latter is a call to the function actually calculating the length of your stack.
self.number_of_elements is a function, so its value is neither zero nor 1
Any way to bypass namedtuple 255 arguments limitation?
I'm using a namedtuple to hold sets of strings and their corresponding values. I'm not using a dictionary, because I want the strings accessible as attributes. Here's my code: from collections import namedtuple # Shortened for readability :-) strings = namedtuple("strings", ['a0', 'a1', 'a2', ..., 'a400']) my_strings = strings(value0, value1, value2, ..., value400) Ideally, once my_strings is initialized, I should be able to do this: print(my_strings.a1) and get value1 printed back. However, I get the following error instead: strings(value0, value1, value2, ...value400) ^SyntaxError: more than 255 arguments It seems python functions (including namedtuple's init()), do not accept more than 255 arguments when called. Is there any way to bypass this issue and have named tuples with more than 255 items? Why is there a 255 arguments limit anyway?
This is a limit to CPython function definitions; in versions before Python 3.7, you cannot specify more than 255 explicit arguments to a callable. This applies to any function definition, not just named tuples. Note that this limit has been lifted in Python 3.7 and newer, where the new limit is sys.maxint. See What is a maximum number of arguments in a Python function? It is the generated code for the class that is hitting this limit. You cannot define a function with more than 255 arguments; the __new__ class method of the resulting class is thus not achievable in the CPython implementation. You'll have to ask yourself, however, if you really should be using a different structure instead. It looks like you have a list-like piece of data to me; 400 numbered names is a sure sign of your data bleeding into your names. You can work around this by creating your own subclass, manually: from operator import itemgetter from collections import OrderedDict class strings(tuple): __slots__ = () _fields = tuple('a{}'.format(i) for i in range(400)) def __new__(cls, *args, **kwargs): req = len(cls._fields) if len(args) + len(kwargs) > req: raise TypeError( '__new__() takes {} positional arguments but {} were given'.format( req, len(args) + len(kwargs))) if kwargs.keys() > set(cls._fields): raise TypeError( '__new__() got an unexpected keyword argument {!r}'.format( (kwargs.keys() - set(cls._fields)).pop())) missing = req - len(args) if kwargs.keys() & set(cls._fields[:-missing]): raise TypeError( '__new__() got multiple values for argument {!r}'.format( (kwargs.keys() & set(cls._fields[:-missing])).pop())) try: for field in cls._fields[-missing:]: args += (kwargs[field],) missing -= 1 except KeyError: pass if len(args) < req: raise TypeError('__new__() missing {} positional argument{}: {}'.format( missing, 's' if missing > 1 else '', ' and '.join(filter(None, [', '.join(map(repr, cls._fields[-missing:-1])), repr(cls._fields[-1])])))) return tuple.__new__(cls, args) #classmethod def _make(cls, iterable, new=tuple.__new__, len=len): 'Make a new strings object from a sequence or iterable' result = new(cls, iterable) if len(result) != len(cls._fields): raise TypeError('Expected %d arguments, got %d' % (len(cls._fields), len(result))) return result def __repr__(self): 'Return a nicely formatted representation string' format = '{}({})'.format(self.__class__.__name__, ', '.join('{}=%r'.format(n) for n in self._fields)) return format % self def _asdict(self): 'Return a new OrderedDict which maps field names to their values' return OrderedDict(zip(self._fields, self)) __dict__ = property(_asdict) def _replace(self, **kwds): 'Return a new strings object replacing specified fields with new values' result = self._make(map(kwds.pop, self._fields, self)) if kwds: raise ValueError('Got unexpected field names: %r' % list(kwds)) return result def __getnewargs__(self): 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) def __getstate__(self): 'Exclude the OrderedDict from pickling' return None for i, name in enumerate(strings._fields): setattr(strings, name, property(itemgetter(i), doc='Alias for field number {}'.format(i))) This version of the named tuple avoids the long argument lists altogether, but otherwise behaves exactly like the original. The somewhat verbose __new__ method is not strictly needed but does closely emulate the original behaviour when arguments are incomplete. Note the construction of the _fields attribute; replace this with your own to name your tuple fields. Pass in a generator expression to set your arguments: s = strings(i for i in range(400)) or if you have a list of values: s = strings(iter(list_of_values)) Either technique bypasses the limits on function signatures and function call argument counts. Demo: >>> s = strings(i for i in range(400)) >>> s strings(a0=0, a1=1, a2=2, a3=3, a4=4, a5=5, a6=6, a7=7, a8=8, a9=9, a10=10, a11=11, a12=12, a13=13, a14=14, a15=15, a16=16, a17=17, a18=18, a19=19, a20=20, a21=21, a22=22, a23=23, a24=24, a25=25, a26=26, a27=27, a28=28, a29=29, a30=30, a31=31, a32=32, a33=33, a34=34, a35=35, a36=36, a37=37, a38=38, a39=39, a40=40, a41=41, a42=42, a43=43, a44=44, a45=45, a46=46, a47=47, a48=48, a49=49, a50=50, a51=51, a52=52, a53=53, a54=54, a55=55, a56=56, a57=57, a58=58, a59=59, a60=60, a61=61, a62=62, a63=63, a64=64, a65=65, a66=66, a67=67, a68=68, a69=69, a70=70, a71=71, a72=72, a73=73, a74=74, a75=75, a76=76, a77=77, a78=78, a79=79, a80=80, a81=81, a82=82, a83=83, a84=84, a85=85, a86=86, a87=87, a88=88, a89=89, a90=90, a91=91, a92=92, a93=93, a94=94, a95=95, a96=96, a97=97, a98=98, a99=99, a100=100, a101=101, a102=102, a103=103, a104=104, a105=105, a106=106, a107=107, a108=108, a109=109, a110=110, a111=111, a112=112, a113=113, a114=114, a115=115, a116=116, a117=117, a118=118, a119=119, a120=120, a121=121, a122=122, a123=123, a124=124, a125=125, a126=126, a127=127, a128=128, a129=129, a130=130, a131=131, a132=132, a133=133, a134=134, a135=135, a136=136, a137=137, a138=138, a139=139, a140=140, a141=141, a142=142, a143=143, a144=144, a145=145, a146=146, a147=147, a148=148, a149=149, a150=150, a151=151, a152=152, a153=153, a154=154, a155=155, a156=156, a157=157, a158=158, a159=159, a160=160, a161=161, a162=162, a163=163, a164=164, a165=165, a166=166, a167=167, a168=168, a169=169, a170=170, a171=171, a172=172, a173=173, a174=174, a175=175, a176=176, a177=177, a178=178, a179=179, a180=180, a181=181, a182=182, a183=183, a184=184, a185=185, a186=186, a187=187, a188=188, a189=189, a190=190, a191=191, a192=192, a193=193, a194=194, a195=195, a196=196, a197=197, a198=198, a199=199, a200=200, a201=201, a202=202, a203=203, a204=204, a205=205, a206=206, a207=207, a208=208, a209=209, a210=210, a211=211, a212=212, a213=213, a214=214, a215=215, a216=216, a217=217, a218=218, a219=219, a220=220, a221=221, a222=222, a223=223, a224=224, a225=225, a226=226, a227=227, a228=228, a229=229, a230=230, a231=231, a232=232, a233=233, a234=234, a235=235, a236=236, a237=237, a238=238, a239=239, a240=240, a241=241, a242=242, a243=243, a244=244, a245=245, a246=246, a247=247, a248=248, a249=249, a250=250, a251=251, a252=252, a253=253, a254=254, a255=255, a256=256, a257=257, a258=258, a259=259, a260=260, a261=261, a262=262, a263=263, a264=264, a265=265, a266=266, a267=267, a268=268, a269=269, a270=270, a271=271, a272=272, a273=273, a274=274, a275=275, a276=276, a277=277, a278=278, a279=279, a280=280, a281=281, a282=282, a283=283, a284=284, a285=285, a286=286, a287=287, a288=288, a289=289, a290=290, a291=291, a292=292, a293=293, a294=294, a295=295, a296=296, a297=297, a298=298, a299=299, a300=300, a301=301, a302=302, a303=303, a304=304, a305=305, a306=306, a307=307, a308=308, a309=309, a310=310, a311=311, a312=312, a313=313, a314=314, a315=315, a316=316, a317=317, a318=318, a319=319, a320=320, a321=321, a322=322, a323=323, a324=324, a325=325, a326=326, a327=327, a328=328, a329=329, a330=330, a331=331, a332=332, a333=333, a334=334, a335=335, a336=336, a337=337, a338=338, a339=339, a340=340, a341=341, a342=342, a343=343, a344=344, a345=345, a346=346, a347=347, a348=348, a349=349, a350=350, a351=351, a352=352, a353=353, a354=354, a355=355, a356=356, a357=357, a358=358, a359=359, a360=360, a361=361, a362=362, a363=363, a364=364, a365=365, a366=366, a367=367, a368=368, a369=369, a370=370, a371=371, a372=372, a373=373, a374=374, a375=375, a376=376, a377=377, a378=378, a379=379, a380=380, a381=381, a382=382, a383=383, a384=384, a385=385, a386=386, a387=387, a388=388, a389=389, a390=390, a391=391, a392=392, a393=393, a394=394, a395=395, a396=396, a397=397, a398=398, a399=399) >>> s.a391 391
namedtuple out of the box doesn't support what you are trying to do. So the following might achieve the goal, which might change from 400 to 450 arguments, or lesser and saner. def customtuple(*keys): class string: _keys = keys _dict = {} def __init__(self, *args): args = list(args) if len(args) != len(self._keys): raise Exception("No go forward") for key in range(len(args)): self._dict[self._keys[key]] = args[key] def __setattr__(self, *args): raise BaseException("Not allowed") def __getattr__(self, arg): try: return self._dict[arg] except: raise BaseException("Name not defined") def __repr__(self): return ("string(%s)" %(", ".join(["%s=%r" %(self._keys[key], self._dict[self._keys[key]]) for key in range(len(self._dict))]))) return string >>> strings = customtuple(*['a'+str(x) for x in range(1, 401)]) >>> s = strings(*['a'+str(x) for x in range(2, 402)]) >>> s.a1 'a2' >>> s.a1 = 1 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/hus787/p.py", line 15, in __setattr__ def __setattr__(self, *args): BaseException: Not allowed For more light on the subject.
Here is my version of a replacement for namedtuple that supports more than 255 arguments. The idea was not to be functionally equivalent but rather to improve on some aspects (in my opinion). This is for Python 3.4+ only: class SequenceAttrReader(object): """ Class to function similar to collections.namedtuple but allowing more than 255 keys. Initialize with attribute string (space separated), then load in data via a sequence, then access the list keys as properties i.e. csv_line = SequenceAttrReader('a b c') csv_line = csv_line.load([1, 2, 3]) print(csv_line.b) >> 2 """ _attr_string = None _attr_list = [] _data_list = [] def __init__(self, attr_string): if not attr_string: raise AttributeError('SequenceAttrReader not properly initialized, please use a non-empty string') self._attr_string = attr_string self._attr_list = attr_string.split(' ') def __getattr__(self, name): if not self._attr_string or not self._attr_list or not self._data_list: raise AttributeError('SequenceAttrReader not properly initialized or loaded') try: index = self._attr_list.index(name) except ValueError: raise AttributeError("'{name}'' not in attribute string".format(name=name)) from None try: value = self._data_list[index] except IndexError: raise AttributeError("No attribute named '{name}'' in".format(name=name)) from None return value def __str__(self): return str(self._data_list) def __repr__(self): return 'SequenceAttrReader("{attr_string}")'.format(attr_string=self._attr_string) def load_data(self, data_list): if not self._attr_list: raise AttributeError('SequenceAttrReader not properly initialized') if not data_list: raise AttributeError('SequenceAttrReader needs to load a non-empty sequence') self._data_list = data_list This is probably not the most efficient way if you are doing a lot of individual lookups, converting it internally to a dict may be better. I'll work on an optimized version once I have more time or at least see what the performance difference is.
Elegant way to avoid .put() on unchanged entities
A reoccurring pattern in my Python programming on GAE is getting some entity from the data store, then possibly changing that entity based on various conditions. In the end I need to .put() the entity back to the data store to ensure that any changes that might have been made to it get saved. However often there were no changes actually made and the final .put() is just a waste of money. How to easily make sure that I only put an entity if it has really changed? The code might look something like def handle_get_request(): entity = Entity.get_by_key_name("foobar") if phase_of_moon() == "full": entity.werewolf = True if random.choice([True, False]): entity.lucky = True if some_complicated_condition: entity.answer = 42 entity.put() I could maintain a "changed" flag which I set if any condition changed the entity, but that seems very brittle. If I forget to set it somewhere, then changes would be lost. What I ended up using def handle_get_request(): entity = Entity.get_by_key_name("foobar") original_xml = entity.to_xml() if phase_of_moon() == "full": entity.werewolf = True if random.choice([True, False]): entity.lucky = True if some_complicated_condition: entity.answer = 42 if entity.to_xml() != original_xml: entity.put() I would not call this "elegant". Elegant would be if the object just saved itself automatically in the end, but I felt this was simple and readable enough to do for now.
Why not check if the result equals (==) the original and so decide whether to save it. This depends on a correctly implemented __eq__, but by default a field-by-field comparison based on the __dict__ should do it. def __eq__(self, other) : return self.__dict__ == other.__dict__ (Be sure that the other rich comparison and hash operators work correctly if you do this. See here.)
One possible solution is using a wrapper that tracks any attribute change: class Wrapper(object): def __init__(self, x): self._x = x self._changed = False def __setattr__(self, name, value): if name[:1] == "_": object.__setattr__(self, name, value) else: if getattr(self._x, name) != value: setattr(self._x, name, value) self._changed = True def __getattribute__(self, name): if name[:1] == "_": return object.__getattribute__(self, name) return getattr(self._x, name) class Contact: def __init__(self, name, address): self.name = name self.address = address c = Contact("Me", "Here") w = Wrapper(c) print w.name # --> Me w.name = w.name print w.name, w._changed # --> Me False w.name = "6502" print w.name, w._changed # --> 6502 True
This answer is a part of an question i posted about a Python checksum of a dict With the answers of this question I developed a method to generate checksum from a db.Model. This is an example: >>> class Actor(db.Model): ... name = db.StringProperty() ... age = db.IntegerProperty() ... >>> u = Actor(name="John Doe", age=26) >>> util.checksum_from_model(u, Actor) '-42156217' >>> u.age = 47 >>> checksum_from_model(u, Actor) '-63393076' I defined these methods: def checksum_from_model(ref, model, exclude_keys=[], exclude_properties=[]): """Returns the checksum of a db.Model. Attributes: ref: The reference og the db.Model model: The model type instance of db.Model. exclude_keys: To exclude a list of properties name like 'updated' exclude_properties: To exclude list of properties type like 'db.DateTimeProperty' Returns: A checksum in signed integer. """ l = [] for key, prop in model.properties().iteritems(): if not (key in exclude_keys) and \ not any([True for x in exclude_properties if isinstance(prop, x)]): l.append(getattr(ref, key)) return checksum_from_list(l) def checksum_from_list(l): """Returns a checksum from a list of data into an int.""" return reduce(lambda x,y : x^y, [hash(repr(x)) for x in l]) Note: For the base36 implementation: http://en.wikipedia.org/wiki/Base_36#Python_implementation Edit: I removed the return in base36, now these functions run without dependences. (An advice from #Skirmantas)
Didn't work with GAE but in same situation I'd use something like: entity = Entity.get_by_key_name("foobar") prev_entity_state = deepcopy(entity.__dict__) if phase_of_moon() == "full": entity.werewolf = True if random.choice([True, False]): entity.lucky = True if some_complicated_condition: entity.answer = 42 if entity.__dict__ == prev_entity_state: entity.put()
Subclass/Child class
I had this class and subclass : class Range: def __init__(self, start, end): self.setStart(start) self.setEnd(end) def getStart(self): return self.start def setStart(self, s): self.start = s def getEnd(self): return self.end def setEnd(self, e): self.end = e def getLength(self): return len(range(self.start, self.end)) def overlaps(self, r): if (r.getStart() < self.getEnd() and r.getEnd() >= self.getEnd()) or \ (self.getStart() < r.getEnd() and self.getEnd() >= r.getEnd()) or \ (self.getStart() >= r.getStart() and self.getEnd() <= r.getEnd()) or \ (r.getStart() >= self.getStart() and r.getEnd() <= self.getEnd()): return True else: return False class DNAFeature(Range): def __init__(self, start, end): self.setStart(start) self.setEnd(end) self.strand = none self.sequencename = none def getSeqName(self, s): return self.SeqName def setSeqName(self, s): self.sequencename = s def getStrand(self): if self.SeqName == 'plus': return 1 elif self.SeqName == 'minus': return -1 else: return 0 def setStrand(self, s): self.strand = s And here is what I have to do: Create a new class – GeneModel ‐ that contains a group of DNAFeature objects representing exons and is a child class of DNAFeature. It should implement the following methods: getFeats() – returns a list of DNAFeature objects, sorted by start position addFeat(feat) – accepts a DNAFeature feat and adds it to its internal group of DNAFeature objects setTranslStart(i) – accepts a non‐negative int, sets the start position of the initiating ATG codon getTranslStart() – returns an int, the start position of the initiating ATG codon setTranslStop(i) – accepts a positive int, sets the end position for the stop codon getTranslStop() – returns an int, the end position for the stop codon setDisplayId(s) – sets the name of the gene model; s is a string getDisplayId() – return the name of the gene model, returns a string, e.g., AT1G10555.1 GeneModel should raise appropriate ValueError and TypeError exceptions when users pass incorrect types and values to constructors and “set” methods. I have tried to write whatever comes to my mind, and read the books as well as searching the way to put codes together, but I am so new to programming and hardly can understand how to write the codes correctly. To be honest, this is the first time I ever do a programming class. So if I make any funny mistake in my codes, please forgive me. I haven't finish my codes yet and still reading the books to see where I am doing wrong and right with my codes. However, I really need your help to guide me to the right path. Thank you guys very much. Below is my codes: class GeneModel(DNAFeature): def __init__(self, translstart, translend, displayid): self.setTranslStart(translstart) self.setTranslStop(translend) setDisplayId(displayid) def getFeats(): result = [] sort.self.getStart() return result def addFeat(feat): self.addFeat = feat return self.getStart+self.getEnd def setTranslStart(i): self.translstart = self.setStart self.translstart = non-negative int def getTranslStart(): return self.translstart def setTranslStop(i): self.translend = self.setEnd self.translend = "+" int def getTranslStop(): return self.translend def setDisplayId(s): self.displayid = re.compile('r'\AT1G[0-9]{5,5}\.[0-9]{,1}, IGNORECASE') def getDisplayId(): return self.displayid
I don't understand what the name of the gene model is. I think it's subject specific, but I think this will work for you: class GenoModel(DNAFeature): def __init__(self, start, end): self.setStart(start) self.setEnd(end) self.strand = None self.sequencename = None self.exons = [] self.translStart = None self.translStop = None self.displayId = None def getFeats(self): self.exons.sort(cmp=self.start) return self.exons def addFeat(self, f): if type(f) == DNAFeature: self.exons.append(f) else: raise TypeError("Cannot add feature as it is not of type DNAFeature") def setTranslStart(self, i): if type(i) != int: raise TypeError("Cannot set translStart as it is not of type int") elif i < 0: raise ValueError("Cannot set tanslStart to a negative int") else: self.translStart = i def getTranslStart(self): return self.translStart def setTranslStop(self, i): if type(i) != int: raise TypeError("Cannot set translStop as it is not of type int") elif i <= 0: raise ValueError("Cannot set tanslStop to anything less than 1") else: self.translStop = i def getTranslStop(self): return self.translStop def setDisplayId(self, s): if type(s) != str: raise TypeError("Cannot set desiplayId as it is not of type string") else: self.displayId = s def getDisplayId(self): return self.displayId Hope this helps.
First, a little bit of cleanup. I'm not completely convinced that your original class, DNAFeature, is actually correct. DNAFeature seems to be inheriting from some other class, named Range, that we're missing here so if you have that code please offer it as well. In that original class, you need to define the variable SeqName (also, its preferable to keep variables lower-cased) since otherwise self.SeqName will be meaningless. Additionally, unless they're inherited from the Range class, you should also define the methods "setStart" and "setEnd". You're getter should not any additional variables, so feel free to change it to "def getSeqName(self)" instead of adding "s". I'm not sure what else your code is really supposed to do, so I'll hold any further comment. Additionally, though you stated otherwise in your comment, I have to believe from the naming conventions (and what little I remember from bio) that you actually want GeneModel to be a container for a set of DNAFeature instances. That's different from GeneModel subclassing DNAFeature. If I'm right, then you can try: class GeneModel(object): def __init__(dnafeatures): self.dnafeatures = dnafeatures def get_features(self): return self.dnafeatures def add_feature(self, feature): self.dnafeatures.append(feature) Here dnafeatures would just be a list of dnafeature instances. This would then allow you to write methods to access these features and do whatever fun stuff you need to do. My advice would be to make sure your DNAFeature class is correct and that your model of how you want your problem solved (in terms of what your classes do) and try asking again when its a little clearer. Hope this helps!