Python: How should I make instance variables available? - python

Suppose I have:
class myclass:
def __init__(self):
self.foo = "bar"
where the value of foo needs to be available to users of myclass. Is it OK to just read the value of foo directly from an instance of myclass? Should I add a get_foo method to myclass or perhaps add a foo property? What's the best practice here?

The applicable Python maxim would be "we're all adults here" - if users need direct access to the value of foo, let them access it directly. A getter or property would make sense if you need to run some code when it's accessed, otherwise the direct way is best.
Also, you can always transparently turn it into a property later if you need to.

I think it should be alright to expose "foo" as it is. Even if you hide it behind a "getter", an insistent user will still be able to access it. As tzaman mentioned "we're all adults here".
If you wish to restrict the usage a bit (ie. make it harder to set), you might consider exposing it using a property. Properties are particularly handy if you need to expose an attribute that has been derived based on others.

Python tutorial has a very nice and concise discussion about this, so check it out. As there is no access control in Python, and recomendation is: if there is something you would make private in C++, start the name with an _ in Python and "play nice". Otherwise just access it directly.

My suggestion, go for the easiest! Directly access the instance variables.
You can argue that if you change the inner representation of your data, you would like to access the data the same way without caring about the inner representation. But hey ! if you have get_foo and set_foo, semanticaly, it means you're changing a variable. So just do so :)
PS: I love the ruby approach there :)

Depends on what you mean by "available to users of myclass". I think that you are talking about a class attribute, like this:
>>> class Myclass(object):
... foo = "bar"
...
>>> a = Myclass()
>>> a.foo
'bar'
>>> b = Myclass()
>>> b.foo
'bar'
>>> Myclass.foo = "zot"
>>> a.foo
'zot'
>>> b.foo
'zot'
>>>

Related

don't understand explanations for Python descriptors cannot be instance variables

I was searching the rationale about descriptors cannot be instance variables, and found this post. In #nneonneo's answer he quoted an answer from Python mail list. I put the quote here.
The answer listed two reasons that I have doubts: for the first reason, it said
if the "M" descriptor is defined by some instances rather than by the class, then knowing that the object "reg" is an instance of Register does not tell me anything about whether "reg.M" is a valid attribute or an error.
But my question is that if "M" descriptor was defined in __init__(), how come it is defined by some instances? Every instance should have an "M" descritor attribute after initialization. Then "reg.M" should always be valid attribute.
for the second reason, the ObjectHolder example,
Instead of treating "holder.obj" as a simple data
attribute, it would start invoking the descriptor protocol on accesses
to "holder.obj" and ultimately redirect them to the non-existent and
meaningless "holder.foo" attribute, which is certainly not what the
author of the class intended.
the original question is about why descriptors cannot be instance variables, this second reason just uses existing mechanism to explain a hypothetical situation. I mean if descriptors are going to be valid as instance variables, there should be some checks and transforms coming along to make it work. I dont' think you can use the mechanism for "descriptors as class variables" to explain "descriptors as instance variables", especially the latter does not exist for now and maybe can be developed to valid in future.
Thanks,
I cannot stress this enough:
The behavior is by design. [1]
That's it. This is they way the language was implemented and why decorators work better with classes is a consequence of that. Resources you provided go into detail why decorators on classes work better, so I will no repeat myself.
Regarding your questions...
If "M" descriptor was defined in init(), how come it is defined by some instances?
It is not, you're right. Ian was presententing the point that, in general, per-instance initialisation based on some conditions may not quarantee that the "reg.M" will not raise AttributeError. This is not the case with class decorators. If you're always initializting in the __init__ then you're fine. Until, for example, someone overrides your __init__ or does del on the attribute. With class, you only need to watch the class.
Instead of treating "holder.obj" as a simple data attribute, it would start invoking the descriptor protocol on accesses to "holder.obj" and ultimately redirect them to the non-existent and meaningless "holder.foo" attribute, which is certainly not what the author of the class intended.
Ok, let's assume we have an object:
>>> a = property(lambda o: o.eggs)
>>> a
<property object at 0x7f9db318a838>
This is perfectly legal, right? Ok, what if I want to store it on an instance of some class? I would do:
>>> class Foo: pass
...
>>> foo = Foo()
>>> foo.a = a
>>> foo.a
<property object at 0x7f9db318a838>
Ok, so this works, cool!
The problem with instance decorators here is that this would not be possible if Python applied decorator protocol to a. Typing foo.a would make it try to evaluate eggs yielding AttributeError. Therefore, in order to have two behaviours possible, the decorator protocol is not invoked on the instance foo.
I hope this clears it up a bit. :)
[1] https://mail.python.org/pipermail/python-list/2012-January/618572.html
[2] https://mail.python.org/pipermail/python-list/2012-January/618570.html

hasattr on class names

hasattr documentation says that it takes an object and an attribute name and lets you know if that attribute exists on that object.
I have discovered that it seems to work on class names too (i.e. not an instance object).
Something like:
class A:
def Attr1(self):
pass
> hasattr(A, 'Attr1')
True
>
I would like to use this to make some test code easier to write, but don't want to be bitten later in case this is a side effect of the implementation and not really intended.
Please don't ask to see the test code to see if I can do something else, as that is not really the question.
Is there any official python stance on this? I presume the object referred to, in the documentation is talking about an instance object.
I tried googling (and looking at some questions in StackOverflow), but didn't seem to find anything.
The fact that it works on a class in addition to an instance is intentional. In fact, hasattr should work on any object that you pass to it. Basically, it does something like this:
def hasattr(obj, attribute):
try:
getattr(obj, attribute)
except:
return False
return True
You can rely on that and not be afraid of getting bit by a change later. Note, there is some discussion on python-dev about hasattr being broken by design. The gist of it is that hasattr catches any exception which can be misleading.
Note that, in python classes are themselves instances of type.
>>> class Foo(object):
... pass
...
>>> type(Foo)
<type 'type'>
so everything is an instance of something1.
1type is an instance of itself which is something that would be impossible to do in pure python...
I do not have a reference on the "official Python stance" at hand, but this is perfectly normal and intentional. Remember that
instance_of_SomeClass.some_method(parameters, ...)
is in fact syntactic sugar for
SomeClass.some_method(instance_of_SomeClass, parameters, ...)
i.e. those methods are in fact attributes of the class and thus can be tested with hasattr.
Just want a reference (even for the sentence that everything is an object...)
I recommend you to read this chapter (or the whole book if you have the time):
http://www.diveintopython.net/getting_to_know_python/everything_is_an_object.html

Why do methods include strong-references to instances/classes?

If you examine a method in python, you'll find the im_class & im_self attributes. If you look closer, you'll see that these are strong-references!
Maybe i'm alone in this; but the way i figure it, if methods themselves are dependent upon their respective class/instance (i.e., the self argument), then the method should "go down with its ship", no? Why would the authors choose to store strong references in the method objects instead of weak references? This forces users that want to avoid circular-referencing to use workarounds. Does anyone have any use cases where strong referencing the class/instance is preferable?
Example:
from weakref import proxy
class Foo(object):
def func(self):
pass
>>> foo = Foo()
>>> func = foo.func
>>> _foo = proxy(foo)
>>> func.im_self is _foo
False
This is only true of method wrappers, which are bound to a specific instance of a class. Using a strong reference avoids interesting surprises; for example, for a class X, func = X().foo; func() does what you'd expect (with a weak reference, the X() would be deleted and the subsequent func() call would fail unexpectedly).
If you want to have "weak referenced methods", the simplest way is just to pass around a tuple of (class method, weak instance), e.g. (X.foo, weakref.ref(x)) instead of x.foo.

Find a way to determine inside function if method is called on the return value?

My class looks like this:
class A:
def __init__(self):
self.bar = []
...
#property
def foo(self):
return bar
Is there a way to find out inside foo whether a method will be called on its return value? I would like to be able to change the return value of foo depending on whether
a.foo.foobar()
or
a.foo
is called.
You could use a proxy class wrapping self.bar (or just self FWIW) in foo()) and overload the proxy's __getattr__() or __getattribute__ methods (more tricky and can slow down your program quite a bit but well...).
Now the question is: what is your real problem ? There might be better / safer solutions...
for the fun of it...
#!/usr/bin/python
import traceback
def how_was_i_called():
call=traceback.extract_stack(limit=2)[0][3]
print "I was called like this: %s"%call
how_was_i_called()
try:
how_was_i_called().foobar()
except AttributeError:
pass
returns:
I was called like this: how_was_i_called()
I was called like this: how_was_i_called().foobar()
but please do not use hacks like this in real applications...
No, there is not. foo returns, and what happens with the return value after that is an entirely separate issue.
You could do this, for example:
result = a.foo
if some_condition:
result.foobar()
e.g. accessing the foobar method on a.foo is an entirely separate expression that may or may not be executed. This could happen at a much later time too, or in a separate thread, or after serialising the object to disk, then loading it again, etc.
You can hook into attribute access on the returned object, but that'll be too late for your foo property to alter behaviour.

Python Module Initialization

Is it bad practice to initialize the objects in the module, in the module code?
in Module.py:
class _Foo(object):
def __init__(self):
self.x = 'Foo'
Foo = _Foo()
Than in user code, you could:
>>> from Module import Foo
>>> print Foo.x
'Foo'
>>>
...without having to initialize the Foo class in the user code. Of course, only useful if you don't need arguments to initialize the object.
Is there a reason not to do this?
Typically, you only want to run the minimum necessary to have your module usable. This will have an overall effect on performance (loading time), and can also make debugging easier.
Also, usually more than one instance will be created from any given class.
Having said that, if you have good reasons (such as only wanting one instance of a class), then certainly initialize it at load time.
I do this sometimes, when it's really convenient, but I tend to do foo = Foo(). I really dislike the idea of making the class appear private, and making the instance available as Foo. As a developer using your code I'd find that pretty disconcerting.

Categories

Resources