Re: [Tutor] classes and the deepcopy function
Okay Just when I think I am getting it you throw this in. So why does a become local to each variable but b seem global? Michael bob gailer wrote: > Michael wrote: >> Hi Michael >> >> Thanks for the quick reply, I think I get it. So becuase I did not >> declare them withing the init method using self they are shared by >> every object that is created, even completely brand new ones? >> >> Is it normal practice to declare your variables in a class? I notice >> that you don't have to, you can create them as you go, but i thought >> declaring and initialising them in the class would make it easier to >> understand and see what the class is for and should contain. > And now for the rest of the story: > > class Foo: > a = 0 > b = [] > > f = Foo() > f.a = 3 > f.b.append(1) > > g = Foo() > g.a = 4 > g.b.append(2) > > print f.a, g.a # 3 4 > print f.b, g.b # [1, 2] [1, 2] > > [snip] > ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Program review
Jeff Younker wrote: > The procesar function is complicated. It tries to do several things > that that are better done elsewhere. It needs to be broken up into > several functions and methods. This also clarifies and isolates the > exception handling. > >> def procesar(mensaje): >>try : > The enclosing try block isn't needed. More on this later. >> >>try : >>fIncl = open(mensaje.direcciones) >>except Exception, e : >>logging.error('Error!!! No pude abrir "%s" : %s', >>mensaje.direcciones, >>e.strerror) >>raise > > This is one function. It has the argument filename. >> >>try : >>fExcl = open(mensaje.excluidas) >>except Exception, e : >>logging.error('No pude abrir "%s" : %s', >>mensaje.excluidas, >>e.strerror) >>fIncl.close() >>raise > > This is the same function with a different argument. > >> >>except : pass >>else : > > The outer exception block here does nothing. If an exception > is raised then the following code won't be executed anyway. > >>mails = enumerate( >>set(addr.strip() for addr in fIncl) >>- set(excl.strip() for excl in fExcl)) >>fIncl.close() >>fExcl.close() > Maybe it is my poor understanding of exception handling. My intention here is to open the first file, if error then report in logging and finish normally, else open the 2nd file, if error then report in logging close the 1st file and finish normally. If no error then process. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] classes and the deepcopy function
Michael wrote: > Okay > > Just when I think I am getting it you throw this in. You're welcome. > So why does a become local to each variable but b seem global? > A better way to ask that is "why does a become an instance property but b remain a class property?" f.a = 3 This is an assignment statement. It creates a property of the instance. The class property a is ignored. f.b.append(1) This is not an assignment. It references a property of the instance that does not exist, so Python goes up the inheritance hierarchy and finds the class property. HTH ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Program review
Ricardo Aráoz wrote: > Jeff Younker wrote: >> The enclosing try block isn't needed. More on this later. > Maybe it is my poor understanding of exception handling. My intention > here is to open the first file, if error then report in logging and > finish normally, else open the 2nd file, if error then report in logging > close the 1st file and finish normally. If no error then process. The code is correct for what you want to do. It does seem a bit awkward but it's hard to get much better and preserve the logging. You could use 'return' instead of 'raise' and eliminate the outer try block. You could put the duplicate code in a function (with raise): def my_open(f): try : fIncl = open(f) except Exception, e : logging.error('Error!!! No pude abrir "%s" : %s', f, e.strerror) raise but you would still need try/except in the calling function: try : fIncl = my_open(mensaje.direcciones) except: return try : fExcl = my_open(mensaje.excluidas) except: fIncl.close() return It is safe to omit the close() in this situation - the file will be closed by the OS when the program terminates - so you could use a single try block: try : fIncl = my_open(mensaje.direcciones) fExcl = my_open(mensaje.excluidas) except: return That is the only version I can come up with that seems significantly simpler than what you wrote. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Program review
Kent Johnson wrote: > Ricardo Aráoz wrote: >> Jeff Younker wrote: > >>> The enclosing try block isn't needed. More on this later. > >> Maybe it is my poor understanding of exception handling. My intention >> here is to open the first file, if error then report in logging and >> finish normally, else open the 2nd file, if error then report in logging >> close the 1st file and finish normally. If no error then process. > > The code is correct for what you want to do. It does seem a bit awkward > but it's hard to get much better and preserve the logging. > Yes, I guessed so. > You could use 'return' instead of 'raise' and eliminate the outer try block. > > You could put the duplicate code in a function (with raise): > def my_open(f): > try : > fIncl = open(f) > except Exception, e : > logging.error('Error!!! No pude abrir "%s" : %s', > f, > e.strerror) > raise > > but you would still need try/except in the calling function: > > try : > fIncl = my_open(mensaje.direcciones) > except: > return > try : > fExcl = my_open(mensaje.excluidas) > except: > fIncl.close() > return > AND the code would have an added depth that gives me no real benefit, which is why I chose to do it that way. So long as meaning is not obscured by complicated or lengthy code I'd rather keep it shallow. > It is safe to omit the close() in this situation - the file will be > closed by the OS when the program terminates - so you could use a single > try block: > try : > fIncl = my_open(mensaje.direcciones) > fExcl = my_open(mensaje.excluidas) > except: > return True, I usually prefer to explicitly close the file anyway. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Program review
Ok, new version. In procesar() I tried getting rid of the outer try block and having 'return' instead of 'raise' in the inner try blocks but I didn't like the result. I'd rather have one more indent level but have only one exit point from the function. Redesigned class Mensaje so that it now includes a MIME message, I think it simplifies the code and less attributes are going around, now Correo.__init__() is simpler. I was tempted to put 'messg = self.mensage.messg' as the first line of Correo.enviar() so as to shorten things like self.mensaje.messg.replace_header('To', addr) to messg.replace_header('To', addr) but I didn't like it, I'd rather stress the fact that 'messg' belongs to Correo's attribute 'mensaje'. Here's the code (untested): #!/usr/bin/env python import time import smtplib import email import ConfigParser import logging class Mensaje(object) : def __init__(self) : cfg = ConfigParser.ConfigParser() try : cfg.readfp(open('config.cfg')) except Exception, e : logging.error('No pude leer "config.cfg" : %s', e.strerror) self.direcciones = cfg.get('Archivos', 'Direcciones') self.excluidas = cfg.get('Archivos', 'Excluir') self.cuantos = cfg.getint('Correo', 'MailsPorVez') self.intervalo = cfg.getint('Correo', 'IntervaloEnSegundos') try : htmlFile = open(cfg.get('Archivos', 'Mensaje')) self.html = htmlFile.read() htmlFile.close() except Exception, e : logging.error('No pude leer "%s" : %s', cfg.get('Archivos', 'Mensaje'), e.strerror) self.messg = email.MIMEMultipart.MIMEMultipart() self.messg['From'] = cfg.get('Encabezados', 'De') self.messg['To'] = '' self.messg['Subject'] = cfg.get('Encabezados', 'Encabezado') self.messg['Reply-To'] = cfg.get('Encabezados', 'ResponderA') self.messg.preamble = 'This is a multi-part message in MIME format' self.messg.attach(email.MIMEText.MIMEText(mensaje.html, 'html')) self.Servidor = cfg.get('Correo', 'Servidor') self.Usuario = cfg.get('Correo', 'Usuario') self.Contra = cfg.get('Correo', 'Contrasenia') class Correo(object) : def __init__(self, mensaje) : self.mensaje = mensaje self.conexion = smtplib.SMTP() def connect(self) : try : self.Conexion.connect(self.mensaje.servidor) self.Conexion.set_debuglevel(False) self.Conexion.ehlo() self.Conexion.starttls() self.Conexion.ehlo() self.Conexion.login(self.mensaje.usuario, self.mensaje.contra) return True except : logging.error('No me pude conectar al Servidor') return False def disconnect(self) : self.Conexion.close() def enviar(self, addr) : self.mensaje.messg.replace_header('To', addr) try : self.Conexion.sendmail(self.mensaje.messg['From'], self.mensaje.messg['To'], self.mensaje.messg.as_string()) logging.info('Enviado a : %s', self.mensaje.messg['To']) except SMTPRecipientsRefused : logging.error('El destinatario fue rechazado por el servidor') except SMTPHeloError : logging.error('El servidor no respondio apropiadamente') except SMTPSenderRefused : logging.error('El From: fue rechazado por el servidor') except SMTPDataError : logging.error('El servidor respondio con un error desconocido') def procesar(mensaje): try : try : fIncl = open(mensaje.direcciones) except Exception, e : logging.error('Error!!! No pude abrir "%s" : %s', mensaje.direcciones, e.strerror) raise try : fExcl = open(mensaje.excluidas) except Exception, e : logging.error('No pude abrir "%s" : %s', mensaje.excluidas, e.strerror) fIncl.close() raise except : pass else : mails = enumerate( set(addr.strip() for addr in fIncl) - set(excl.strip() for excl in fExcl)) fIncl.close() fExcl.close() miCorreo = Correo(mensaje) miCorreo.connect() empiezo = time.clock() for nro, addr in mails : if nro%mensaje.cuantos == 0 and nro > 0 : miCorreo.disconnect() time.sleep(mensaje.intervalo - (time.clock() - empiezo)) if not miCorreo.connect() : logging.info('Terminando') return empiezo = time.clock() miCorreo.enviar(addr) miCorreo.disconnect() if __nam
Re: [Tutor] Program review
Jeff Johnson wrote: > I would like to "butt" in here and mention that this is some of the most > useful information I have seen! I am a programmer of 25 years that is > new to Python. This type of back and forth dialog on actual production > code is extremely useful to learning the language. I have done this > with Ed Leafe with Dabo and it has helped a lot. > > Keep it up! > > Jeff > Guys, I really learned with this exercise (and my code was improved). I got to think how good it would be to have one or two ongoing small projects where we contribute code and the code is criticized and enhanced by our community. We could agree on a subject, someone could volunteer to give it a try (if the subject is big enough then many could volunteer with different parts of the whole) then post the code so that it can be viewed and reviewed by the rest. We could learn a lot and we might end up with some useful pieces of code. What do you think? Ricardo ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
[Tutor] locating python scripts
hey i just have a small question, doesn't have much to do with programing but it has to do with python. anyways Im running a apple computer version 10.4 and have been keeping my scripts in the user folder i was wondering where and how i can change the files that python looks in when looking for programs i would like to make it so that i can have separate folders in the user folder for different projects any help would be great thanks ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Program review
Ok, now the "tested" version (has been corrected) : #!/usr/bin/env python import time import smtplib import email import ConfigParser import logging class Mensaje(object) : def __init__(self) : cfg = ConfigParser.ConfigParser() try : cfg.readfp(open('config.cfg')) except Exception, e : logging.error('No pude leer "config.cfg" : %s', e.strerror) self.direcciones = cfg.get('Archivos', 'Direcciones') self.excluidas = cfg.get('Archivos', 'Excluir') self.cuantos = cfg.getint('Correo', 'MailsPorVez') self.intervalo = cfg.getint('Correo', 'IntervaloEnSegundos') try : htmlFile = open(cfg.get('Archivos', 'Mensaje')) htmlMessage = htmlFile.read() htmlFile.close() except Exception, e : logging.error('No pude leer "%s" : %s', cfg.get('Archivos', 'Mensaje'), e.strerror) self.messg = email.MIMEMultipart.MIMEMultipart() self.messg['From'] = cfg.get('Encabezados', 'De') self.messg['To'] = '' self.messg['Subject'] = cfg.get('Encabezados', 'Encabezado') self.messg['Reply-To'] = cfg.get('Encabezados', 'ResponderA') self.messg.preamble = 'This is a multi-part message in MIME format' self.messg.attach(email.MIMEText.MIMEText(htmlMessage, 'html')) self.servidor = cfg.get('Correo', 'Servidor') self.usuario = cfg.get('Correo', 'Usuario') self.contra = cfg.get('Correo', 'Contrasenia') class Correo(object) : def __init__(self, mensaje) : self.mensaje = mensaje self.conexion = smtplib.SMTP() def connect(self) : try : self.conexion.connect(self.mensaje.servidor) self.conexion.set_debuglevel(False) self.conexion.ehlo() self.conexion.starttls() self.conexion.ehlo() self.conexion.login(self.mensaje.usuario, self.mensaje.contra) return True except : logging.error('No me pude conectar al Servidor') return False def disconnect(self) : self.conexion.close() def enviar(self, addr) : self.mensaje.messg.replace_header('To', addr) try : self.conexion.sendmail(self.mensaje.messg['From'], self.mensaje.messg['To'], self.mensaje.messg.as_string()) logging.info('Enviado a : %s', self.mensaje.messg['To']) except smtplib.SMTPRecipientsRefused : logging.error('El destinatario fue rechazado por el servidor') except smtplib.SMTPHeloError : logging.error('El servidor no respondio apropiadamente') except smtplib.SMTPSenderRefused : logging.error('El From: fue rechazado por el servidor') except smtplib.SMTPDataError : logging.error('El servidor respondio con un error desconocido') def procesar(mensaje): try : try : fIncl = open(mensaje.direcciones) except Exception, e : logging.error('Error!!! No pude abrir "%s" : %s', mensaje.direcciones, e.strerror) raise try : fExcl = open(mensaje.excluidas) except Exception, e : logging.error('No pude abrir "%s" : %s', mensaje.excluidas, e.strerror) fIncl.close() raise except : pass else : mails = enumerate( set(addr.strip() for addr in fIncl) - set(excl.strip() for excl in fExcl)) fIncl.close() fExcl.close() miCorreo = Correo(mensaje) if miCorreo.connect() : empiezo = time.clock() for nro, addr in mails : if nro%mensaje.cuantos == 0 and nro > 0 : miCorreo.disconnect() time.sleep(mensaje.intervalo - (time.clock() - empiezo)) if not miCorreo.connect() : logging.info('Terminando') return empiezo = time.clock() miCorreo.enviar(addr) miCorreo.disconnect() if __name__ == '__main__' : logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename=time.strftime('informe-%Y-%m-%d-%H-%M-%S.log'), filemode='w') procesar(Mensaje()) ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] locating python scripts
max baseman gmail.com> writes: > > hey i just have a small question, doesn't have much to do with > programing but it has to do with python. > anyways Im running a apple computer version 10.4 and have been > keeping my scripts in the user folder i was wondering where and how i > can change the files that python looks in when looking for programs i > would like to make it so that i can have separate folders in the user > folder for different projects > any help would be great > thanks > > ___ > Tutor maillist - Tutor python.org > http://mail.python.org/mailman/listinfo/tutor > > I've always just added paths to the PYTHONPATH environment variable. It's value is now: /home/brendan/scripts/Python:/home/brendan/lib/python:. This is on Linux, but I don't see why it shouldn't work identically on OSX. Cheers, - Brendan ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Program review
> > Maybe it is my poor understanding of exception handling. My intention > here is to open the first file, if error then report in logging and > finish normally, else open the 2nd file, if error then report in > logging > close the 1st file and finish normally. If no error then process. > Right, but it helps to break up the error handling and the cleanup. Right now the error reporting exception handlers are intermixed with your cleanup error handlers. Separating them makes the code clearer. def open_file(filename): try : return open(filename) except Exception: logging.error('No pude abrir "%s"' % filename, exec_info=True) raise # Goes into configuration class def mails(self): fIncl = open_file(self.direcciones) try: fExcl = open_file(self.excluidas) try: return enumerate( set(addr.strip() for addr in fIncl) - set(excl.strip() for excl in fExcl)) finally: fExcl.close() finally: fIncl.close() Or if you're using python 2.5 then you can use with statements: from __future__ import with_statements from contextlib import closing ... def mails(self): with closing(open_file(self.direcciones)) as fIncl: with closing(open_file(self.excluidas)) as fExcl: return enumerate( set(addr.strip() for addr in fIncl) - set(excl.strip() for excl in fExcl)) > close the 1st file and finish normally. If no error then process. If an exception is raised then the code terminates right there and then. So, if procesar is written as: def procesar(mensaje): mails = mensaje.mails() miCorreo = Correo(mensaje) then if mensaje.mails() raises an exception then the code terminates immediately, and the body of Correo will only be executed if there is no error. As you have it written it terminates, but it also silently consumes the exception. If something goes wrong with your program then there is no way of diagnosing the problem because the failure cause is never reported. -jeff ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor