[Python-ideas] exclusively1, common, exclusively2 = set1 - set2, set1 & set2, set2 - set1

Steven D'Aprano steve at pearwood.info
Mon Jul 8 11:38:32 CEST 2013


On Mon, Jul 08, 2013 at 04:24:39AM -0400, Eric V. Smith wrote:
> On 7/8/2013 3:22 AM, Steven D'Aprano wrote:
> > On Sun, Jul 07, 2013 at 02:37:56PM -0700, David Mertz wrote:
> >> On Jul 7, 2013 2:09 PM, "Eric V. Smith" <eric at trueblade.com> wrote:
> >>>
> >>> On 7/7/2013 1:45 AM, David Mertz wrote:
> >>>> Maybe the generalization isn't worthwhile.  I was thinking that maybe a
> >>>> more general version should keep order in types that have order to start
> >>>> with, so I confess I'm not certain what the "correct" interface would
> >> be.
> >>>>
> >>>> But even if it were only for sets, I like the idea of a plain function
> >>>> much better than a method of a set, even if the only arguments it
> >>>> accepted were sets.
> >>>
> >>> If it were added, I think a classmember on set would be reasonable.
> >>
> >> I agree.
> > 
> > A class member? Do you mean a class *method*?
> 
> I did mean classmethod, thanks. Or maybe staticmethod, I haven't really
> thought it through. The point being, it need not be an instance method.

Strictly speaking, you're right. Being Python, you could make this any 
sort of callable you like. But what would be the point of making it 
something other than either an instance method or a function? It's an 
operation that requires two set arguments. The obvious way to handle it 
is as either a function with signature func(set1, set2) or as a method 
with signature method(self, other). There are no points for "Most 
Unusual and Imaginative API".

(A third alternative would be an operator, __op__(self, other), but I'm 
not seriously suggesting that.)


> > I think it would be freaky and weird if I did this:
> > 
> > some_set.venn_split(second_set, another_set)
> > 
> > (for lack of a better name) and the value of some_set was ignored. Class 
> > methods are okay for things like alternate constructors, but I don't 
> > think they are appropriate here.
> 
> set.venn_split(second_set, another_set)
> 
> It's no more surprising than this code not using the values from d:
> 
> >>> d = {'a':1, 'b':2}
> >>> d.fromkeys([3, 4, 5])
> {3: None, 4: None, 5: None}
> 
> versus:
> 
> >>> dict.fromkeys([3, 4, 5])
> {3: None, 4: None, 5: None}

It is standard behaviour for alternate constructors to ignore the value 
of the instance, hence they are usually classmethods.

A constructor normally depends on the class, not the instance: 
dict(args), not {}(args). And the args generally don't include an 
instance of the class you are trying to make. They can, of course, but 
generally we have things like Decimal.from_float(arg). Even when you 
call the constructor from an instance, you don't want the instance 
itself to make any difference to the result, the result should be 
specified entirely by the arguments. So constructors should ignore the 
instance, and should be classmethods.

None of these things apply to "venn_split". We're not talking about a 
constructor, but a set operation that requires two set arguments. One is 
conventionally taken to be `self`, the other explicitly given:

class set: 
    def venn_split(self, other):
        ...

not:

class set: 
    @classmethod
    def venn_split(cls, set1, set2):
        # ignore the value of cls
        ...


Making this "venn-split" operation a class or static method would be as 
weird as making (say) str.split a class method:

"a,b,c,d".split(",")
=> raise TypeError, too few arguments

"a,b,c,d".split("a,b,c,d", ",")
=> ["a", "b", "c", "d"]


That's a strange API. This is Python, you can do it, but you shouldn't.


-- 
Steven


More information about the Python-ideas mailing list