3

I am certain I am doing this "incorrectly" even though it works. Right now when I call a function I just pass the whole object i.e.

class my_file_obj:
    def __init__(self,filename):
        self.filename = filename
        self.owner = None
        self.file_type = None
        self.fileflag = 0
        self.md5 = None

The function call, where file_obj1 is an instance of my_file_obj:

some_function(file_obj1)

and then referencing the attributes I need as needed within the function.

What is the "python"/correct way of doing this?

  • some_function(file_obj1)

  • some_function(file_obj1.filename)

  • the_filename = file_obj1.filename
    some_function(the_filename)
Michael J. Barber
  • 24,518
  • 9
  • 68
  • 88
user982599
  • 975
  • 13
  • 28
  • 1
    It's really your call. Do you only need to use the file name? Do you have cases where you'd pass in a file name that does not have an object associated with it? – Rafe Kettler Nov 01 '11 at 13:28
  • @RafeKettler: I think that suffices as an answer. – Blender Nov 01 '11 at 13:29
  • Not sure if directly accessing the data members of an object is recommended in Python. You may use access functions for this, like `def getFilename(self)` or something similar (see http://en.wikipedia.org/wiki/Mutator_method for more information). – hochl Nov 01 '11 at 13:32

5 Answers5

5

Well, it's quite obvious. It depends on whether some_function needs the whole object or just the filename, in which case you pass the whole my_file_obj instance or just the filename.

Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
  • thanks for the responses. i wasnt sure if python had interfaces or if a getter type function was the preferred method. i am assuming that passing the whole object would be more memory/computationally expensive, correct? – user982599 Nov 01 '11 at 13:34
  • 1
    @user982599: All names in Python are references. The only difference is in attribute lookup time (`foo` vs `foo.bar`), but that's likely to be negligible. – Cat Plus Plus Nov 01 '11 at 13:36
  • I don't have benchmarks, but under the hood what you are actually doing is passing a reference to the instance of object to the function, not the object itself. So it should not be any more computationally intensive to do it this way. – ZenGyro Nov 01 '11 at 13:38
1

I think some_function(file_obj1) is the most pythonic.

some_function(file_obj1.filename) doesn't pass the object to the function, it only passes the filename attribute as a string. It then would require a lot of fiddly code to get the rest of the object's attributes.

ZenGyro
  • 176
  • 1
  • 6
1

All the ways are acceptable and which you will choose will depend on your application (or design) choices.

# with this call the file_obj1 object reference is sent to some_function()
some_function(file_obj1)

# with this call there is no pass by reference. If filename is a 
# string it is copied to some_function
some_function(file_obj1.filename)

# same as before, but here you are allocating a new var and copying the content
# to some_function
the_filename = file_obj1.filename
some_function(the_filename)
Carlo Pires
  • 4,606
  • 7
  • 32
  • 32
  • Technically speaking, this is misleading - Python is really [call-by-object](http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference/986495#986495). In your second example you're still passing the actual string object, but it just happens to be immutable, unlike the `file_obj1` instance. – Wayne Werner Nov 01 '11 at 13:53
0

Or you may add a def __str__(self): return self.filename method to your class (because, maybe, printing a file object should return its name in your design anyways) and accept any kind of object for your function. The function then, for example, looks like this:

def openFile(obj):
    return open(str(obj), 'rU')

Like this, the function accepts both strings and objects of your class. See http://en.wikipedia.org/wiki/Duck_typing.

Not sure if this design is recommended -- just want to point out something less obvious. Maybe this is even pythonic?

hochl
  • 12,524
  • 10
  • 53
  • 87
0

Well, it depends on what you want to do and what your goal is.

If you have a function that looks something like this:

def some_function(file_thingy):
   with open(file_thingy.filename, 'w') as f:
       f.write("Icky Icky Icky Patang NeeeeWom!")

Then it makes things much more generic - as long as you pass an object in that has a .filename attribute that is a string then your function will work. A more common example of this is when people talk about duck typing. If it looks like a duck, walks like a duck, and quacks like a duck, well then it's a duck!

So if you have the following function:

def do_duck_things(a_duck):
    print(a_duck.appearance)
    a_duck.waddle()
    a_duck.quack()
    print("It must be a duck!")

Then you could pass it an instance of:

class Duck:
    def __init__(self):
        self.appearance = "White, like the AFLAC duck"

    def quack(self):
        print("Quaaaaaack!")

    def waddle(self):
        print("The duck waddles.")

or an instance of either of these classes:

class UglyDuckling:
    def __init__(self):
        self.appearance = "Suspiciously like a baby goose"

    def waddle(self):
        print("The ugly duckling waddles a bit like a duck.")

    def quack(self):
        print("Hoooonk!")

class Human:
    def __init__(self):
        self.appearance = "Looks like a human in a duck costume"

    def waddle(self):
        print("Surprisingly, he waddles quite like a duck.")

    def quack(self):
        print("<A sound quite like Donald Duck would make>")

So in your case, it really depends on what your function should be doing. If all it's doing is reading the contents of a file, then you can (and probably should) just send it a filename. But if you want to do something like, say, check the file against your stored MD5, or set that MD5, then it's perfectly appropriate to pass in the object.

HTH

Wayne Werner
  • 49,299
  • 29
  • 200
  • 290