I am writing a python class to store data and then another class will create an instance of that class to print different variables. Some class variables require a lot of formatting which may take multiple lines of code to get it in its "final state".
Is it bad practice to just access the variables from outside the class with this structure?
class Data():
def __init__(self):
self.data = "data"
Or is it better practice to use an #property method to access variables?
class Data:
#property
def data(self):
return "data"
Be careful, if you do:
class Data:
#property
def data(self):
return "data"
d = Data()
d.data = "try to modify data"
will give you error:
AttributeError: can't set attribute
And as I see in your question, you want to be able to transform the data until its final state, so, go for the other option
class Data2():
def __init__(self):
self.data = "data"
d2 = Data2()
d2.data = "now I can be modified"
or modify the previus:
class Data:
def __init__(self):
self._data = "data"
#property
def data(self):
return self._data
#data.setter
def data(self, value):
self._data = value
d = Data()
d.data = "now I can be modified"
Common Practice
The normal practice in Python is to exposure the attributes directly. A property can be added later if additional actions are required when getting or setting.
Most of the modules in the standard library follow this practice. Public variables (not prefixed with an underscore) typically don't use property() unless there is a specific reason (such as making an attribute read-only).
Rationale
Normal attribute access (without property) is simple to implement, simple to understand, and runs very fast.
The possibility of use property() afterwards means that we don't have to practice defensive programming. We can avoid having to prematurely implement getters and setters which bloats the code and makes accesses slower.
Basically you could hide lot of complexity in the property and make it look like an attribute. This increases code readability.
Also, you need to understand the difference between property and attribute.
Please refer What's the difference between a Python "property" and "attribute"?
Related
Sometimes when I am designing a new method for a class that needs to act on certain variable, I can't say if it's better to pass this variable as a method parameter or if it's better to save this variable as an instance attribute and just use it inside the method. What are the advantages/disadvantages of both approaches?
class A:
def __init__(self, data):
self.data = data
def my_method(self):
# does something with self.data
Or
class B:
def my_method(self, data):
# does something with data
It depends on all the other things the class may do.
Most generally, what is the abstraction that your class encapsulates?
Does it need data for lots of operations, or only this? Will data change? If data is the "point" of this class, then it should probably be in the __init__, but if it uses data to act on the object, then probably not.
We need to know more....
When developing code for test automation, I often transform responses from the SUT from XML / JSON / whatever to a Python object model to make working with it afterwards easier.
Since the client should not alter the information stored in the object model, it would make sense to have all instance attributes read-only.
For simple cases, this can be achieved by using a namedtuple from the collections module. But in most cases, a simple namedtuple won't do.
I know that the probably most pythonic way would be to use properties:
class MyReadOnlyClass(object):
def __init__(self, a):
self.__a = a
#property
def a(self):
return self.__a
This is OK if I'm dealing only with a few attributes, but it gets lengthy pretty soon.
So I was wondering if there would be any other acceptable approach? What I came up with was this:
MODE_RO = "ro"
MODE_RW = "rw"
class ReadOnlyBaseClass(object):
__mode = MODE_RW
def __init__(self):
self.__mode = MODE_RO
def __setattr__(self, key, value):
if self.__mode != MODE_RW:
raise AttributeError("May not set attribute")
else:
self.__dict__[key] = value
I could then subclass it and use it like this:
class MyObjectModel(ReadOnlyBaseClass):
def __init__(self, a):
self.a = a
super(MyObjectModel, self).__init__()
After the super call, adding or modifying instance attributes is not possible (... that easily, at least).
A possible caveat I came to think about is that if someone was to modify the __mode attribute and set it to MODE_RO, no new instances could be created. But that seems acceptable since its clearly marked as "private" (in the Pyhon way).
I would be interested if you see any more problems with this solution, or have completely different and better approaches.
Or maybe discourage this at all (with explanation, please)?
Is it possible to modify/extend an inherited method from the middle. I realize I can call super and get the original method, then either put code before or after that call which will extend the original. Is there a technique of doing something similar but from the middle of a method?
class Base():
def __init__(self):
self.size = 4
def get_data(self):
data = []
for num in range(self.size):
data.append("doing stuff")
data.append("doing stuff")
### add here from child##
data.append("doing stuff")
data.append("doing stuff")
return data
class MyClass(Base):
def __init__(self):
super().__init__()
def get_data(self):
# inherited parent code
# Do something else here
# inherited parent code
Despite Python's powerful introspection and code-modifying capabilities, there is no "clean" way of doing this. It could be done only by directly modifying the bytecode in the original function and shoehorsing a new method call in there - which would also implying in creating a new code and function objects - definitely not something to do in production code - even because bytecode is not guaranteed to be unchanged across Python versions or Python implementations.
Refactoring the original method:
But it can be done if the original method is coded in a way it is "aware" of points were subclasses might want to run additional code (maybe even being split up in several methods):
For your example, you'd have something like:
class Base():
def __init__(self):
self.size = 4
def get_data(self):
self.data = data = []
for num in range(self.size):
data.append("doing stuff")
data.append("doing stuff")
self.do_extra_things_with_data()
data.append("doing stuff")
data.append("doing stuff")
return data
def do_extra_things_with_data():
"""Override this on subclasses"""
class MyClass(Base):
def __init__(self):
super().__init__()
def do_extra_things_with_data():
print(len(self.data), "objects defined so far")
One technical name for this is "slot". (It is used for templating in certain web frameworks - the derived page uses the parent template for columns and general layout, and defines "slots" for the content areas)
One other thing to watch are descriptors such as "properties": you can't change the superclass'method code - but if the code retrieves instance attributes for its computations, you can define these attributes as properties on the subclasses to run custom code.
Using descriptors:
One other way of doing that is to use descriptors such as "properties": you can't change the superclass'method code - but if the code retrieves instance attributes for its computations, you can define these attributes as properties on the subclasses to run custom code.
Let's suppose your method makes use of the self.size attribute, but it is exactly for calculating it that you might want to run more code - keeping exactly the same Base class you can do:
class MyClass(Base):
#property
def size(self):
# put extr calculation to retrieve the dynamc value
of self.size here
return value
Is there a technique of doing something similar but from the middle of
a method?
Not really. The def compiles into a function object that has a self-contained code object that is usually treated as being opaque.
When a need like this arises, it is usually an indication that the parent method needs to be split into reusable components that can be called separately.
If you can't refactor the parent method, then the unfortunate alternative is that the subclass will have to override the method and duplicate some of the code from the parent.
In short, Pythonic object oriented design is treats methods and attributes as the atomic units of composability.
I am trying to find the best way of accessing an instance variable from another instance. So far I've been able to pass that variable as an argument and save it in the new instance. But I am wondering if there is some sort of "Global" variable that will work best. Specially if the classes are from different modules.
Here is my example:
class A(object):
def __init__(self):
self.globalObject = "Global Object"
self.listB = self.generateBList()
def generateBList(self):
return [B(self.globalObject, i) for i in range(10)]
class B(object):
def __init__(self, globalObject, index):
self.index = index
self.globalObject = globalObject
def splitGlobalObject(self):
return self.globalObject.split(" ")
a = A()
firstB = a.listB[0]
print firstB.splitGlobalObject()
Here when I generateBList() I need to pass always that globalObject as an argument B(self.globalObject, i), and then this object gets saved into B.globalObject, butif i had many classes that needed to access that global object im not sure if passing it always as an argument would be the best option. What would be the best way of accessing it without having to pass it always as an argument when you create instances?
I hope I explained my way properly.
Your example seems unnecessarily complicated, so I'll try to illustrate one way I've used before that I think may do what you want. If you think of creating a "world" that is the stage for what you want to happen, you can have each class instance inside the world, know the world. Like this:
class Thing(object):
def __init__self(self, world, name):
self.world = world
self.name = name
class Word(object):
def __init__(self):
self.everyone = [Thing(self, i) for i in range(10)]
if __name__ == '__main__':
world = World()
In this example, the World class instance carries around an attribute called everyone that is a list of ten Thing objects. More importantly for your example, each instance of Thing now carries around a pointer called self.world that points to the world class. So all Things can access all other Things via self.world.everyone, as well as anything else in the world. I also passed i into each Things init so they have a unique name in the form of an integer between 0 and 9, but that may be extra for what you need.
From here there's basically nothing that your instances can't do to each other via methods, and all without using lots of globals.
Edit: I should add that being from different modules will make no difference here, just import as many as you want and create instances of them that pass knowledge of the World instance into them. Or obviously tailor the structure to your needs while using the same idea.
It's possible to use global variables in python.
class A(object):
def __init__(self):
global globalObject
globalObject = "Global Object"
self.listB = self.generateBList()
def generateBList(self):
return [B(i) for i in range(10)]
class B(object):
def __init__(self, index):
self.index = index
def splitGlobalObject(self):
return globalObject.split(" ")
Usually you want to avoid globals. Visit http://www.python-kurs.eu/python3_global_lokal.php for more examples.
I have a question that is puzzling me recently about which is the best way to retrieve attributes from outside.
Let say I have a class:
class Thing:
def __init__(self, whatever):
self.whatever = whatever
x = Thing('foo')
Now I know that if I want to retrieve whatever attribute I can do this:
x.whatever
I have the habit (probably because I come from other oo languages) to define methods to retrieve class attributes as needed and use them insted of retrieve them directly, like:
class Thing:
def __init__(self, whatever):
self.whatever = whatever
def getWhatever(self):
return self.whatever
In my little experience I've found that using this approach make things easier to mantain in the long term because if I edit the structure of data attributes I have to edit only the specific method.
But since I am not really a python veteran I'd love to know if I am doin' it right or if some other approaches are better and more pythonic. Thoughts?
Defining explicit getters and setters is a bad practice in Python. Instead, use properties:
class Thing(object): # New-style class
def __init__(self, whatever):
self._whatever = whatever
#property
def whatever(self):
return self._whatever # Insert complicated calculation here
So instead of pre-planning by using get methods, just introduce a property when you actually need advanced behavior, and not any earlier.
#phihag has the right idea, and mentions in their answer, but to be more explicit about it: The first step is simply to use the attribute directly:
class Thing(object):
def __init__(self, whatever):
self.whatever = whatever
t = Thing(12)
assert t.whatever == 12
Later, if you find you need to make the whatever attribute more sophisticated, you can turn it into a property:
class Thing(object):
def __init__(self, whatever):
self._whatever = whatever
#property
def whatever(self):
return something_complicated(self._whatever)
t = Thing(12)
assert t.whatever == 12
This way, the calling code doesn't change, and you have a nice clean API to your object.
check python property() http://docs.python.org/library/functions.html#property