Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Malcolm XML
Aug 8, 2009

I always knew it would end like this.

JHVH-1 posted:

Is there a decent IDE out there for windows that would let me work on python code from a remote machine. Right now I just use WinSCP, then edit the file in windows VIM and run it from putty. Then I also have to do all the git checkins/outs.

It works but I don't know if there is a nicer way and maybe something more full featured.

mount your ssh endpoint via (win-)sshfs and just edit directly in any editor

Adbot
ADBOT LOVES YOU

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Symbolic Butt posted:

This is not true. a == b is just a.__eq__(b)

http://codepad.org/taSgse1T

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

Oh god, my life is a lie.

Jewel
May 2, 2009

To be fair, I think that's true for every non-base type. Base types are usually weird non-standard things that don't conform to other conventions like overloading or inheritance.

Edit: Though; is the python interpreter source up anywhere? Probably a dumb question but if it is it could be worth it to take a look what "==" does. I'd be interested.

BigRedDot
Mar 6, 2008

Jewel posted:

To be fair, I think that's true for every non-base type. Base types are usually weird non-standard things that don't conform to other conventions like overloading or inheritance.

Edit: Though; is the python interpreter source up anywhere? Probably a dumb question but if it is it could be worth it to take a look what "==" does. I'd be interested.

https://docs.python.org/2/reference/datamodel.html

quote:

There are no swapped-argument versions of these methods (to be used when the left argument does not support the operation but the right argument does); rather, __lt__() and __gt__() are each other’s reflection, __le__() and __ge__() are each other’s reflection, and __eq__() and __ne__() are their own reflection.

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord
The python documentation seems to be really unclear about what happens here.

http://docs.sympy.org/dev/python-comparisons.html#method-resolution

The March Hare
Oct 15, 2006

Je rêve d'un
Wayne's World 3
Buglord
Figure I'll ask here as well as on SO.

I've got a lil' app I've been working on that is my first foray into doing UI poo poo of any kind and also distribution of python code of any kind. It all works just fine if I run it as a python script, but once I package it into a .app and run it on os x it crashes every time I call qApp.quit(). I have no idea where to even start reading the stack trace or anything, and google has been basically no help at all.

http://pastebin.com/upxeBKbx <-- stack trace.

https://github.com/LarryBrid/glimmer-client <-- is the whole client, but the 'client.py' file is the main qt loop.

Do note that if you try to actually use the thing right now it won't actually function, but the client will run and let you close it no problem. I've been redoing the API over the past few days though so all of the actual functionality is broken.

In addition to a fix to this problem I'm open to having people tell me how dumb I am for doing anything dumb that I have done, and would really appreciate any time given to general code-quality crits because I would like to get better.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Jewel posted:

To be fair, I think that's true for every non-base type. Base types are usually weird non-standard things that don't conform to other conventions like overloading or inheritance.

Edit: Though; is the python interpreter source up anywhere? Probably a dumb question but if it is it could be worth it to take a look what "==" does. I'd be interested.

https://github.com/python/cpython/blob/master/Objects/object.c#L633

It's a bit confusing because of the "richcompare" vfunc, but that's just a C convenience API.

Python code:
def ==(a, b):
    if hasattr(a, "__eq__"):
        res = a.__eq__(b)
        if res is not NotImplemented:
            return res
    if hasattr(b, "__eq__"):
        res = b.__eq__(a)
        if res is not NotImplemented:
            return res
    # sensible default
    return id(a) == id(b)

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb
Is PyCharm supposed to be generating CSS files for LESS files that start with an underscore? Would that be a bug?

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Is there a resource that really breaks down python class and objects, for dummies? I'm having a really hard time wrapping my head around them.

code:
class Song(object):
    def __init__(self, lyrics):
          self.lyrics = lyrics
    def sing_me_a_song(self):
          for line in self.lyrics:
              print line

CrappySong = Song(["this is a song", "this song sucks"])

CrappySong.sing_me_a_song()
I'm getting tripped up on understanding __init__, and the use of self in any form.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Hughmoris posted:

Is there a resource that really breaks down python class and objects, for dummies? I'm having a really hard time wrapping my head around them.

code:
class Song(object):
    def __init__(self, lyrics):
          self.lyrics = lyrics
    def sing_me_a_song(self):
          for line in self.lyrics:
              print line

CrappySong = Song(["this is a song", "this song sucks"])

CrappySong.sing_me_a_song()
I'm getting tripped up on understanding __init__, and the use of self in any form.

OOP is something everyone struggles with learning, and then once they get it it's hard to understand in retrospect why it was so hard to get.

I could write a bunch of words, but I don't feel like it, so I'll write very few words that gloss over details and then you can ask for clarification...

When you Song(["this is a song", "this song sucks"]) you're basically calling the __init__ function.

self "contains" all the names that make up the class, like lyrics and sing_me_a_song. The only way you can access those things within a method is by passing self to it. You put it in the parameter list, and Python automatically passes it to the method when it's called.

Dominoes
Sep 20, 2007

To expand on Thermopyle's explanation:

__init__ is a function that runs whenever an instance of the class is created.

'self' in __init__'s arguments is boilerplate. The other arguments are variables you send to an instance you're creating.

'self.lyrics=lyrics' turns your argument into a variable built into the instance.

'def sing_me_a_song(self):' is a function that has easy access to the instance's 'self.' variables and methods. The 'self' argument is boilerplate, and other arguments are normal function arguments.

'CrappySong = Song(["this is a song", "this song sucks"])' creates an instance of Song, and sets its self.lyrics to the lyrics argument.

'CrappySong.sing_me_a_song()' runs sing_me_a_song(), which now automatically has access to ["this is a song", "this song sucks"]. This highlights why this class might be useful instead of just using a function - you don't have to provide lyrics every time you want to sing a song. You could have a bunch of Song instances. You'd set up the lyrics once for each, and could have each sing their own song whenever.

Dominoes fucked around with this message at 09:09 on Jun 20, 2014

evilentity
Jun 25, 2010
Also dont start instance variable name with Capital letter.

the
Jul 18, 2004

by Cowcaster
let's say I have a list of salaries like this:

code:
[["'Bill'", 34000],
["'Sally'", 36000],
["'Tom'", 23000]]
Can I sort the list by the second column numerically? I can't figure out if sorted() works for this or not.

edit: thanks \/\/, I saw an example like that on a page, but I couldn't figure out what the lambda was supposed to indicate

the fucked around with this message at 17:11 on Jun 20, 2014

Dominoes
Sep 20, 2007

Python code:
salaries.sort(key=lambda x: x[1])

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

the posted:

let's say I have a list of salaries like this:

code:
[["'Bill'", 34000],
["'Sally'", 36000],
["'Tom'", 23000]]
Can I sort the list by the second column numerically? I can't figure out if sorted() works for this or not.

code:
>>> sal = [["Bill", 34000], ["Sally", 36000], ["Tom", 23000]]
>>> sorted(sal, key=lambda x: x[1])
[['Tom', 23000], ['Bill', 34000], ['Sally', 36000]]
edit: ^

Dominoes
Sep 20, 2007

the posted:

edit: thanks \/\/, I saw an example like that on a page, but I couldn't figure out what the lambda was supposed to indicate
lambdas are a bit of functional programming used in Python. You can ignore them if you want, but they're useful for passing simple functions as arguments to other functions, like in this case.

Using Thermopyle's example, sorted(sal, key=lambda x: x[1]) is the same as

Python code:
def y(x):
    return x[1]

sorted(sal, key=y)
Another case would be QT signals or GUI callbacks:
Python code:
self.statusSignal.connect(lambda message: self.display_message(message))
Or cleaning up messy repetitive function calls:

Python code:
set_bg = lambda column, color: item.setBackground(
    column, QtGui.QBrush(QtGui.QColor(*color)))

set_bg(4, red)
set_bg(5, blue)
...

Dominoes fucked around with this message at 17:36 on Jun 20, 2014

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Thermopyle posted:

OOP is something everyone struggles with learning, and then once they get it it's hard to understand in retrospect why it was so hard to get.

I could write a bunch of words, but I don't feel like it, so I'll write very few words that gloss over details and then you can ask for clarification...

When you Song(["this is a song", "this song sucks"]) you're basically calling the __init__ function.

self "contains" all the names that make up the class, like lyrics and sing_me_a_song. The only way you can access those things within a method is by passing self to it. You put it in the parameter list, and Python automatically passes it to the method when it's called.

Dominoes posted:

To expand on Thermopyle's explanation:

__init__ is a function that runs whenever an instance of the class is created.

'self' in __init__'s arguments is boilerplate. The other arguments are variables you send to an instance you're creating.

'self.lyrics=lyrics' turns your argument into a variable built into the instance.

'def sing_me_a_song(self):' is a function that has easy access to the instance's 'self.' variables and methods. The 'self' argument is boilerplate, and other arguments are normal function arguments.

'CrappySong = Song(["this is a song", "this song sucks"])' creates an instance of Song, and sets its self.lyrics to the lyrics argument.

'CrappySong.sing_me_a_song()' runs sing_me_a_song(), which now automatically has access to ["this is a song", "this song sucks"]. This highlights why this class might be useful instead of just using a function - you don't have to provide lyrics every time you want to sing a song. You could have a bunch of Song instances. You'd set up the lyrics once for each, and could have each sing their own song whenever.

Thanks for this. I'll try and break the parts down and see if I can grasp things a little better.

Dominoes, I'm still a bit confused on how a class is more useful than just defining a function. Wouldn't it be easier to just define a function called sing_a_song(lyrics) and whenever I want it to sing a song, I just pass it whatever variable contains the song I want to sing? Ex: sing_a_song(big_booty_hoes)

I realize this example is poor, I just pulled it from a text I was reading.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Sure, but if you have a lot of things to sing (a song might have an artist, a title, the lyrics, and how long each lyric takes to sing), it can be painful to have to write out all the arguments every time. You can put all the arguments in one little object and then just refer to it later by one name later.

That said, there's no right way or wrong way to use a class. When to use a class and when to just write a function is something you'll pick up as your experience and tastes develop.

Dominoes
Sep 20, 2007

Hugh, your example works for learning how to structure classes, but it's too simple to show why they're useful.

Try writing most of your code without classes. Take a look at the more complicated and messy bits, and try turning them into classes. See if it makes them easier to read and maintain.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Hughmoris posted:

Thanks for this. I'll try and break the parts down and see if I can grasp things a little better.

Dominoes, I'm still a bit confused on how a class is more useful than just defining a function. Wouldn't it be easier to just define a function called sing_a_song(lyrics) and whenever I want it to sing a song, I just pass it whatever variable contains the song I want to sing? Ex: sing_a_song(big_booty_hoes)

I realize this example is poor, I just pulled it from a text I was reading.

That might be easier with this simple example because it ignores all the other things classes bring to the table.

In fact, people tend to overuse classes when functions would work just fine.

Anyway, the use for objects becomes more apparent in more complex cases. See if this helps:

Python code:
class Song(object):
	def __init__(self, lyrics):
		self.lyrics = lyrics

	def sing_me_a_song(self):
		for line in self.lyrics:
			print line

	def sing_in_reverse(self):
		print self._stringify[::-1] # This is an obtuse way of reversing a string.  It's not a very readable way to do it.

	@property
	def second_line(self):
		print self.lyrics[1]

	def _word_counter(self, word):
		return self._stringify().count(word)

	def _stringify(self):
		return "/n".join(self.lyrics)


class HipHopSong(Song):
	def bootys(self):
		print self._word_counter('booty')


class CountrySong(Song):
	def trucks(self):
		print self._word_counter('truck')

	def cliched_lines(self):
		for line in self.lyrics:
			if 'truck' in line and 'dog' in line:
				print line
Ask questions about what you don't understand.

Dominoes
Sep 20, 2007

Thermopyle posted:

Ask questions about what you don't understand.
When would you use @property? My take is that in this case, it would allow you to write mysong.second_line instead of mysong.second_line().

Would you do it in this case because slicing a string is a simple, cheap operation, so it doesn't need to be shown as explicitly running a method every time it's called? Would it be if it returned the second line instead of printed it, so you could do my_song.secondline = "My dog got run over by a truck" ?

Guides I've read talk about replacing get and set, using instance variables as examples, but I've never found a use for a get or set method.

Dominoes fucked around with this message at 18:25 on Jun 20, 2014

BeefofAges
Jun 5, 2004

Cry 'Havoc!', and let slip the cows of war.

Design question for you guys. My department (all SDETs) is trying to design a library to wrap and simplify interaction with several dozen internal REST API endpoints. The two competing strategies right now are to either have one endpoint per file, with just plain functions for doing GETs/POSTs/etc and building payloads and so on, or to put multiple endpoints in each file and have a class per endpoint, with the GETs/POSTs/etc in static methods (because there's no reason for an endpoint wrapper to be stateful or require initialization).

I favor the first option because it seems simpler, but my coworkers favor the 2nd, and I don't really have any good pros/cons for either approach. Thoughts?

QuarkJets
Sep 8, 2008

I don't understand decorators or why they're useful. Can someone explain them to me?

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Thermopyle posted:

Ask questions about what you don't understand.

That is a really bad example.

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb

Suspicious Dish posted:

That is a really bad example.

It doesn't seem so bad, why not elaborate?

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

fletcher posted:

It doesn't seem so bad, why not elaborate?

Because it's suspicious dish.

edit: Now that I'm at my PC...

I certainly wouldn't ever actually write those classes, but I think it quickly expands upon the original class to demonstrate the mechanics of classes just fine to show some ways a more complex thingamajig makes classes more useful.

As such, it is a good example. It's just not something you'd actually write for real software.

edit2: inserted important not into last sentence.

Thermopyle fucked around with this message at 20:53 on Jun 20, 2014

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Thermopyle posted:

Because it's suspicious dish.

edit: Now that I'm at my PC...

I certainly wouldn't ever actually write those classes, but I think it quickly expands upon the original class to demonstrate the mechanics of classes just fine to show some ways a more complex thingamajig makes classes more useful.

As such, it is a good example. It's just something you'd actually write for real software.

Yeah, the reason I didn't write anything before was because I was phone posting. I wanted to write a longer reply, but forgot about it for a bit while I did some real work. I'll try not to do that in the future, sorry.

The exact reason I don't like it is because it's not how I'd ever write the code myself, and examples that tell you "here's a thing that you can do but don't do it this way!!!" are bad examples. I really wouldn't expect a Song class to have any methods, but it depends on the system we're building. If I'm building a karaoke system that plays a bad instrumental track synced up to words on a monitor, I'd structure it like this:

Python code:
# Just contains the song itself.
class Song(object):
    def __init__(self, artist, title, file, lyrics):
        # Boring metadata
        self.artist = artist
        self.title = title

        # The filename of the audio
        self.file = file

        # Some information that has the lyrics of the song
        # and their timing 
        self.lyrics = lyrics

    # Gets the lyrics as a string at "secs" seconds into the song.
    def get_lyrics_at_time(self, secs):
        # Insert some less terrible algorithm here
        return self.lyrics[secs]

# The component that plays the audio
class SongPlayer(object):
    def __init__(self):
        self.current_song = None # Set to a "Song" object

    def play_on_output(self, output, msecs):
        some_audio_system.play_song_on_output(self.current_song, output)

class SongDisplayer(object):
    def __init__(self):
        self.current_song = None
        self.current_lyrics = None

    # Called periodically to draw the lyrics
    def update_display_for_time(self, secs):
        lyrics = self.current_song.get_lyrics_at_time(secs)
        some_display_system.draw_lyrics(lyrics)

# The component that synchronizes between the audio
# output and the display on the screen.
class CoreTimer(object):
     ...
Obviously, this is a very bad rough sketch and for more fancy features like word-specific timing and animations and custom backgrounds and multiple speaker and display support, it wouldn't work. But HipHopSong extends Song gives people a ridiculously bad idea for building real systems, I feel.

( I went looking for the "Goodbye, lovely "Car extends Vehicle" object-orientation tutorial" article in the initial post, but it seems the server went down. It has most of the same ideas. Just remembered to check the Wayback Machine, though, so: https://web.archive.org/web/20140416021831/http://lists.canonical.org/pipermail/kragen-tol/2011-August/000937.html )

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

QuarkJets posted:

I don't understand decorators or why they're useful. Can someone explain them to me?

Decorators are really simple.

Python code:
@my_decorator
def foo(a, b, c):
    return a*2, b*3, c*4
Is the exact same thing as:

Python code:
def foo(a, b, c):
    return a*2, b*3, c*4

foo = my_decorator(foo)
This can be useful for multiple things. One is a simple way of doing function wrapping:

Python code:
def print_on_called(func):
    def inner(*args, **kwargs):
        print func, "was called!"
        return func(*args, **kwargs)

    return inner

@print_on_called
def foo(a, b, c):
    return a*2, b*3, c*4
Here, we replace "foo" with "inner", which is a passthrough function which also happens to print before it calls "foo".

Another thing you can do is registration for a dispatch table. Frameworks like Flask use them for this purpose.

Python code:
routes = {}
def add_route(route):
    def inner(func):
        routes[route] = func
        return func
    return inner

@add_route('/')
def home():
    return "Welcome to my home page!"

# Reminder, this maps to
# home = add_route('/')(home)

@add_route('/zombo')
def zombo():
    return "You can do anything you want at zombo!"
Here, instead of replacing "func", we're simply leaving it untouched, and using it as a sort of "registration" system, where when the decorator is called, we insert the route passed to add_route and the view function into a dictionary, which we can then look up later.

While decorators can lead to cleaner and more declarative code with higher-level structures, they can also lead to crazy meta-programming shenanigans.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Suspicious Dish posted:

Yeah, the reason I didn't write anything before was because I was phone posting. I wanted to write a longer reply, but forgot about it for a bit while I did some real work. I'll try not to do that in the future, sorry.

I get what you're saying, but I just don't agree that it's always not useful for teaching the mechanics of how inheritance works. Especially not to the point where a person would be justified in saying it's "really bad".

I think that, while there's an overlap between the two, teaching the mechanics of how OO works and how to design OO code are not exactly the same thing. Particularly in this instance where we're discussing an already-existing example and talking about how __init__ and self work.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Dominoes posted:

When would you use @property? My take is that in this case, it would allow you to write mysong.second_line instead of mysong.second_line().

Would you do it in this case because slicing a string is a simple, cheap operation, so it doesn't need to be shown as explicitly running a method every time it's called? Would it be if it returned the second line instead of printed it, so you could do my_song.secondline = "My dog got run over by a truck" ?

Guides I've read talk about replacing get and set, using instance variables as examples, but I've never found a use for a get or set method.

I see a lot of people using @property a lot of different ways. Really, you could get away with never using them. However, I try to use them for every method without side effects.

Sometimes you have regular attributes and then something that needs computed but is related to your regular attributes in some way and you can just pretend it is a regular attribute by using @property.

It helps with refactoring. If you change from needing a function to not, you don't have to change any other code because everything just refers to the previously-@property-decorated method via the normal attribute syntax.

It just makes sense. If you're getting a side-effect-free value from an object, why should you have to think about if it's a method or an attribute? In this sense, properties help with information hiding...you don't worry about implementation details.

Alex Martelli talks some more about it here.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
Another good example of a useful decorator is functools.lru_cache, which is used to memoise functions. If you don't know what that means, basically it means caching the results of calling a function with a particular set of arguments, which is useful if you have a (side-effect-free) function that takes a lot of resources to execute and you don't want to dance around making sure you only call it when really necessary. You just decorate it with lru_cache and you get Python to check for you whether the function really needs to be called with the specified arguments or whether you already did it.

OnceIWasAnOstrich
Jul 22, 2006

Hammerite posted:

Another good example of a useful decorator is functools.lru_cache, which is used to memoise functions. If you don't know what that means, basically it means caching the results of calling a function with a particular set of arguments, which is useful if you have a (side-effect-free) function that takes a lot of resources to execute and you don't want to dance around making sure you only call it when really necessary. You just decorate it with lru_cache and you get Python to check for you whether the function really needs to be called with the specified arguments or whether you already did it.

I love this one. I'm always writing little scripts with sometimes long-running functions so I wrote my own that used memcached as a backend with month-long expiry times and decorate the poo poo out of any function that takes longer than a few milliseconds to run and have memcached running on all our lab computers.

QuarkJets
Sep 8, 2008

So what exactly does @property do, then?

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
@property turns something into a "getter property":

http://codepad.org/mUALdwe7

It does this through secret arcane magic known as "descriptors".

BigRedDot
Mar 6, 2008

Suspicious Dish posted:

@property turns something into a "getter property":

http://codepad.org/mUALdwe7

It does this through secret arcane magic known as "descriptors".

Everything to do with objects in python is done through descriptors: properties, slots, passing self, static and class methods

FoiledAgain
May 6, 2007

I'm working on a GUI, but my question might have a more general answer. I want to check if a user has modified a document before they do something like quit, or open another document (because only one can be open at a time). I have a "global" self.warn_about_changes that tracks when changes have been made. There are 5 different functions where I need to check this and then possibly issue a warning, and this number could potentially go up in the future. At the moment what I have done is to paste this code into each of the functions:

code:
def open_existing_file(self):
    if self.warn_about_changes:
        wants_to_continue = self.issue_changes_warning()#basically just FileDialog.askyesno()
        if not wants_to_continue:
            return
        else:
            self.warn_about_changes = False
    #body of the function goes here
This is obviously really messy, and there's a huge risk of introducing bugs when changes have to be made to any of these lines. What I want to do is to call some other magic function first for each of these cases, which pretty much has the above code in it, and use this other magic function to then call the save function, then go back and call the originally requested function.

At first I thought this would be a case where decorators might come in handy. I have never used them before, because I never saw the need, but this idea of wanting to first call another function seemed appropriate. But I cannot get this work properly.

Are decorators appropriate here? If not, what's a better idea? If so, I don't understand how/where to define them.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

FoiledAgain posted:

...

Are decorators appropriate here? If not, what's a better idea? If so, I don't understand how/where to define them.

I don't feel that I can confidently tell you whether this is a good idea design-wise or not (it seems like a decent enough idea to me, but I have limited experience designing big projects), but it is definitely something that you can use decorators for. It would be something like:

code:
def with_warning_about_unsaved_changes (func):
    def decorated_func (self, *args, **kwargs):
        if self.warn_about_changes:
            wants_to_continue = self.issue_changes_warning()#basically just FileDialog.askyesno()
            if not wants_to_continue:
                return
            else:
                self.warn_about_changes = False
        return func(self, *args, **kwargs)
    return decorated_func

class MyFile:

    ... # some class members and methods

    @with_warning_about_unsaved_changes
    def open_existing_file (self):
        ... # method contents, without the "are you sure? you have unsaved changes" boilerplate

    ... # some more class members and methods
It is important to realise that a decorator is itself just a function. More specifically, it is a function that accepts a function as input and returns another function as output, but the function returned as output is one that relates to the original function in some way (typically it calls it - or as in our example, may conditionally call it - but with some extra logic around the edges).

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
I'd just write a method. The more I encounter metaprogramming like decorators, the more I appreciate clear and straightforward code.

Python code:
class Editor(object):
    def check_unsaved(self):
        if self.has_unsaved_changes:
            self.show_unsaved_warning_dialog()
            return True
        else:
            return False

     def open_existing_file(self):
        if self.check_unsaved():
            return

        # ...

Adbot
ADBOT LOVES YOU

EAT THE EGGS RICOLA
May 29, 2008

I have to do something in python 2.6, apparently.

Is there a preferred way to do

code:
with open("filename1", "a") as f1, open("filename2", "a") as f2:
    ...
Should I just use contextlib.nested?

  • Locked thread