1

I try to make a class containing file names in a folder. But I want it to behave like set. Now I have this:

class Files():

    def __init__(self, in_dir):
        self.in_dir = in_dir
        self.files = set(map(os.path.basename, glob.glob(self.in_dir + "/*.txt")))

    def __add__(self, other):
        return self.files + other.files    

    def __or__(self, other):
        return self.files | other.files

    def __and__(self, other):
        return self.files & other.files

    def __xor__(self, other):
        return self.files ^ other.files

This work and I can do like this:

f1 = Files(inDir1)
f2 = Files(inDir2)

diff_files = f1 ^ f2 % this give files that are in f1 or f2 folder but not in both  folders

This is ok, but the problem is that diff_files is not instance of Files. How to change my class, to behave like set in python 3.x?

user3654650
  • 5,283
  • 10
  • 27
  • 28
  • Any reason you're not using a `set` directly? I imagine there's more code you're not showing, but as it stands I would take the code you have in `__init__` and just make that a function that returns a set. – Ismail Badawi Jun 09 '14 at 03:57
  • this is small example. I want Files to have custom functions, like delete files in self.files. – user3654650 Jun 09 '14 at 04:01

2 Answers2

3

First, make in_dir argument optional:

def __init__(self, in_dir=None):
    if in_dir:
        self.in_dir = in_dir
        self.files = set(map(os.path.basename, glob.glob(self.in_dir + "/*.txt")))

Then, change the __xor__():

def __xor__(self, other):
    instance = Files()
    instance.files = self.files ^ other.files
    return instance

Also, I don't see the reason to keep in_dir as an instance variable. You can simplify the __init__():

def __init__(self, in_dir=None):
    if in_dir:
        self.files = set(map(os.path.basename, glob.glob(in_dir + "/*.txt")))

Alternatively, you can allow to initialize Files by passing a files set:

def __init__(self, in_dir=None, files=None):
    if in_dir:
        self.files = set(map(os.path.basename, glob.glob(in_dir + "/*.txt")))
    if files:
        self.files = files

Then, the __xor__() method would be even simpler:

def __xor__(self, other):
    return Files(files=self.files ^ other.files)
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • Thank you. I also think about extending set class, but dont know how. Is that better than like now? – user3654650 Jun 09 '14 at 04:04
  • @user3654650 I'm pretty much ok with the approach you currently have. But, take a look anyway: http://stackoverflow.com/questions/798442/what-is-the-correct-or-best-way-to-subclass-the-python-set-class-adding-a-new and http://www.itmaybeahack.com/book/python-2.6/html/p03/p03c04_extending.html. Hope that helps. – alecxe Jun 09 '14 at 04:09
1

I'm not sure I understand what you mean by "behaves like set" but I do understand that you want to return an instance of Files and not only the "diff", so for that:

change:

def __xor__(self, other):
        return self.files ^ other.files

to:

def __xor__(self, other):
        result = Files()
        result.in_dir = self.in_dir
        result.files = self.files ^ other.files
        return result
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129