I'm relatively new to Python and have problems with immutable variables.
I'm trying to change the value of a class attribute (e.g. car.color). The difficulty is, that I can not use the namespace of car for doing this.
Up to now I did not find a satisvying answer to my questions. In the code below I tried to summarize the possible solutions (workarrounds) I found and their disadvantages:
class Car:
def __init__(self):
self.color = "green"
self.color_list = ["green"]
self.color_attrib = "green"
self.name = "VW Golf"
"""
and many more attributes...
"""
def makesetter(self, attribute):
def set_value(value):
attribute=value
return set_value
def set_color(self, value):
"in this function I directly have access to car.color and can change its value: "
self.color = value
def set_attrib(self, attribute_string, value):
setattr(self,attribute_string,value)
def change_attribute(attribute, value):
"In this function I can not access car.color directly"
attribute=value
def change_attribute_list(attribute, value):
"In this function I can not access car.color directly"
attribute[0] = value
if __name__ == "__main__":
car1 = Car()
change_attribute(car1.color, "red")
print(car1.color) # Color does not change because car1.color is immutable
g = car1.makesetter(car1.color)
g("red")
print(car1.color) # Color does not change because car1.color is immutable
change_attribute_list(car1.color_list, "red")
print(car1.color_list) # Color changes but seems like a workarround
# Disadvantage: in the namespace of car1, the user has to use a list to access a string value "car1.color_list[0]"
car1.set_color("red")
print(car1.color) # Color changes but seems like a workarround
# Disadvantage: Car needs a setter function for each attribute
car1.set_attrib("color_attrib","red")
print(car1.color_attrib) # Color changes but seems like a workarround
# Disadvantage: Attribute has to be passed as string & no auto completion while coding
Actually the function setattr() is internally exactly doing what I want. But it works with a string argument.
I tried to look into this function but it seems to be written in C++.
So do I have to use C++ to solve this problem without a workarround?
Or is there a Pythionic way of doing this?
The problem is you are trying to redefine the value of an instance from outside of the class. Since in __init__ you are defining your variables with self, they are only available for that instance. This is the point of a class - it's what makes them extensible and reusable.
Ideally, you would make a method within the class that would update those attributes, however, if you really need to update the class from an external function, you will have to define it as a class level variable. For instance:
class Car:
def __init__(self):
Car.color = "green"
can now be updated using:
def change_attribute(attribute, value):
"In this function I can not access car.color directly"
Car.color=value
outside of the class because you have not assigned it to one specific instance. Doing this presents a problem, however. Since we don't have a separate instance variable, if we try to re-instantiate the class, we are stuck with what was previously changed, i.e.
if name == "main":
car1 = Car()
car2 = Car()
change_attribute(car1.color, "red")
print(car1.color) # Prints red
print(car2.color) # Prints red
change_attribute(car2.color, "blue")
print(car1.color) # Prints blue
print(car2.color) # Prints blue
This is why classes themselves should be self contained and are meant to be immutable - the instance itself should be changed.
Related
I would like construct a class composition that includes a function set_props for setting the instance variables of components.
The application for this is in defining new objects for drawing in matplotlib. One example is that I would like to have a function drawMyArrow that draws an arrow with possibly different colors (and other specifications) for its head, tail, and arc. I would like to be able to pass various specifications for the head, tail, and arc via keyword arguments in drawMyArrow. I haven't worked with classes before, but reading up on this online, I believe that the best way to solve my problem is to define a class MyArrow that is a composition of some classes ArrowHead and ArrowArc.
To illustrate my problem, I am using a toy example (that I also used for a previous question here). Let's define a class Room that is a composition of the classes wall, window, and door.
class Door:
def __init__(self, color='white', height=2.3, width=1.0, locked=True):
self.color = color
self.height = height
self.width = width
self.locked=locked
class Window:
def __init__(self, color='white', height=1.0, width=0.8):
self.color = color
self.height = height
self.width = width
class Wall:
def __init__(self, color='white', height=2.5, width=4.0):
self.color = color
self.height = height
self.width = width
class Room:
def __init__(self):
self.door = Door()
self.window = Window()
self.wall = Wall()
If I want to have a function for Room that can set properties of its components, I can do something like this:
def set_windowprops(r, color=None, width=None, height=None):
if not color==None: r.window.color=color
if not width==None: r.window.widht=width
if not height==None: r.window.height=height
return r
But if I decide to add more instance variables to Window, I would have to go back to this function and add the new instance variables. Can I write set_windowprops so that it automatically accepts all instance variables of Window as keywords?
Ideally, I would like to write a function like this:
def set_props(r, windowcolor=None, windowwidth=None, windowheight=None,
doorcolor=None, doorwidth=None, doorheight=None, doorlocked=None,
wallcolor=None, wallwidth=None, wallheight=None):
if not windowcolor==None: r.window.color=windowcolor
if not windowwidth==None: r.window.widht=windowwidth
if not windowheight==None: r.window.height=windowheight
if not doorcolor==None: r.door.color=doorcolor
if not doorwidth==None: r.door.widht=doorwidth
if not doorheight==None: r.door.height=dooorheight
if not doorlocked==None: r.door.locked=doorlocked
if not wallcolor==None: r.wall.color=wallcolor
if not wallwidth==None: r.wall.widht=wallwidth
if not wallheight==None: r.wall.height=wallheight
return r
but without the need of hardcoding all instance variables of components into the function.
I was looking into using keyword dictionaries like so:
window_vars = getNamesOfInstanceVariables(Window) #TODO
window_kwargs = {}
for v in window_vars:
window_kwargs[v] = None
def set_windowprops(r, **kwargs):
for kw in kwargs:
if not kwargs[kw]==None:
r["window"][kw] = kwargs[kw] #TODO
return r
Two issues keep me from getting this to work:
(1) In the last line, I am pretending that r is a dictionary (of dictionaries) and using dictionary syntax to assign a value to r.window.kw. But that doesn't work because r is an instance of Room and not a dictionary. What would be the syntax for setting instance variables if the name of the component class and the name of the instance variable are given as strings?
(2) I have tried using inspect to write getNamesOfInstanceVariables, but I am unable to get it to work robustly. Many classes in matplotlib inherit from base classes. I would like getNamesOfInstanceVariables to return all instance variables that a user can set for an object of this class. For example, the class FancyArrow in matplotlib has Patch as base class and instance variables head_length and head_width. So I would getNamesOfInstanceVariables(FancyArrow) to return ['head_length','head_width', *listOfInstanceVarsForPatch].
EDIT
Let me add a bit of background on why I am asking for a dynamical way to write these functions. Let's say I have finished my script and it includes the classes Window, Door, Wall and many class compositions of these three. One of these many class compositions is Room. This class Room has ten hardcoded set_ functions that look like this:
def set_windowcolor(r, color):
r.window.color = color
return r
I now decide that I want to add another instance variable to the class Window. For example,
class Window:
def __init__(self, color='white', height=1.0, width=0.8, open=False):
self.color = color
self.height = height
self.width = width
self.open = open # new attribute of Window
Similar to all the other instance variables of window, this new attribute of Window should be customizable in all classe compositions that contain a Window. So I would go through my code, find the class Room and add a function
def set_windowopen(r, open):
r.window.open = open
return r
I would also have to look for all other class compositions that contain a Window and update them manually as well. I don't want to do this because it is a lot of work and I am likely going to overlook some class dependencies in the process and introduce bugs into my code. I am looking for a solution that either
generates set functions for single properties (e.g. set_windowcolor) automatically in Room for all instance variables of Window or
automatically adjusts the list of keyword arguments in set_windowprops or set_props.
Here is what I would do
class Room:
def __init__(self, kw_door=None, kw_window=None, kw_wall=None):
if kw_door:
self.door = Door(**kw_door)
else:
self.door = Door()
if kw_window:
self.window = Window(**kw_window)
else:
self.window = Window()
if kw_wall:
self.wall = Wall(**kw_wall)
else:
self.wall = Wall()
effectively you are accepting a dictionary that will be unpacked into the instance creation, and when the class definition gets new attributes, they too will be unpacked if they are found in the passed dictionary.
To answer you first question. If you want to set window attribute of r and kw attribute of that `windows as in your example, you cat do the following:
setattr(getattr(r, "window"), kw, kwargs[kw])
You get attribute named window of r. And for that windows attributes set its own whose name is in variable kw to a new value from kwargs[kw]. As your line has attempted.
But to be perfectly honest, why a function with many possible arguments would be preferred over just accessing/setting the attributes themselves? Or in other words, on the face of it, it looks more complicated then it needs to be.
As for you second question. You should be also able to just use dir() to get list of instance attributes, but yes, inherited attributes will be getting in your way and I am not immediately sure if there is an elegant way around it (i.e. not walk the inheritance tree and do the pruning yourself). But if you genuinely wanted to dynamically walk attributes of an instance that are subject to for instance setting through a function, I'd say add a (class) attribute defining what those are to be for each type rely on that as a defined interface.
side note: There is only one instance of None (and True and False) and it can be tested for identity (not just equality) and since it reads a little better you would normally see if somevar is not None instead of if not somevar == None.
I am new to python ( started 1 week ago) and this is the first time i am doing coding so i am not able to understand fairly simple things as well.
can you explain this function to to me? i understand that a function is being defined with 2 input required self and my_object, but what is happening next? please explain like you would to a newbie.
class chain():
def __init__(self, my_object):
self.o = my_object
def __getattr__(self, attr):
x = getattr(self.o, attr)
if hasattr(x, '__call__'):
method = x
return lambda *args: self if method(*args) is None else method(*args)
else:
prop = x
return prop
Firstly, chain is not a Function, it's a Class.
A class in simple words is a definition of an object. (say Car)
Now the __init__ function of the class simply defines what's "in it" meaning what variables or properties does it has. Say for example a class Car:
class Car:
def __init__(self,maxspeed,color):
self.speed = maxspeed #So what's defined under **__init__** is a property of a class.
self.color = color
So here Class car has speed and color as variables(or attributes or properties)
Now there are methods , of simply function that control the behaviour of the object and it's functionalities.
class Car:
def __init__(self,maxspeed,color):
self.speed = maxspeed #So what's defined under **__init__** is a property of a class.
self.color = color
def accelarate(self): #Method to increase the speed of car object.
self.sepped = self.speed + 10
Now the method you have is a magical one , __getattr__
Say a scenario where you want to acess the brand of the car , now you haven't define self.brand in it's __init__ function so you you'll get an error when you call it like:
>>>red_car = Car(100,red) #Creating an object named red_car of class Car
>>>red_car.color
>>>'red'
>>>red_car.brand
>>> Attribute Error , Class car dosen't has attribute brand
Now remove this error when calling an undefined property for a object or put simple we tell tell the class what to do if an undefined variable is called we use the method __getattr__.
class Dummy(object):
def __getattr__(self, attr):
return attr.upper()
d = Dummy()
d.does_not_exist # 'DOES_NOT_EXIST'
d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE'
In the above code does_not_exist property (attribute) is NOT define but still we are not getting error as the getattr catches it and does as instructed. In this case it catches attr capitalises it and returns it rather than throwing an error in your face.
The class chain has a constructor that takes an argument my_object and assigns it to an instance variable self.o.
The method __getattr__ is a special magic method that has been overridden to delegate calls to the initial my_object variable we first received.
The result of the delegated call is checked for a method named __call__. If present, it is called and the returned value is returned. If not, the value itself is returned as-is.
I have the following problem and I need advice on how to solve it the best technically in Python. As I am new to programming I would like to have some advice.
So I will have the following object and they should store something. Here is an example:
object 1: cash dividends (they will have the following properties)
exdate (will store a list of dates)
recorddate (will store a list of dates)
paydate (will store a list of dates)
ISIN (will store a list of text)
object 2: stocksplits (they will have the following prpoerties)
stockplitratio (will be some ration)
exdate(list of dates)
...
I have tried to solve it like this:
class cashDividends(object):
def __init__(self, _gross,_net,_ISIN, _paydate, _exdate, _recorddate, _frequency, _type, _announceddate, _currency):
self.gross = _gross
self.net = _net
self.ISIN = _ISIN
self.paydate = _paydate
self.exdate = _exdate
self.recorddate = _recorddate
self.frequency = _frequency
self.type = _type
self.announceddate = _announceddate
self.currency = _currency
So if I have this I would have to create another class named stockplits and then define an __init__ function again.
However is there a way where I can have one class like "Corporate Actions" and then have stock splits and cashdividends in there ?
Sure you can! In python you can pass classes to other classes.
Here a simple example:
class A():
def __init__(self):
self.x = 0
class B():
def __init__(self):
self.x = 1
class Container():
def __init__(self, objects):
self.x = [obj.x for obj in objects]
a = A()
b = B()
c = Container([a,b])
c.x
[0,1]
If I understood correctly what you want is an object that has other objects from a class you created as property?
class CorporateActions(object):
def __init__(self, aCashDividend, aStockSplit):
self.cashDividend = aCashDividend
self.stockSplit = aStockSplit
myCashDividends = CashDividends(...) #corresponding parameters here
myStockSplit = StockSplit(...)
myCorporateActions = CorporateActions(myCashDividends, myStockSplit)
Strictly speaking this answer isn't an answer for the final question. However, it is a way to make your life slightly easier.
Consider creating a sort-of template class (I'm using this term loosely; there's no such thing in Python) that does the __init__ work for you. Like this:
class KwargAttrs():
def __init__(self, **kwargs):
for k,v in kwargs.items():
setattr(self, k, v)
def _update(self, **kwargs):
args_dict = {k:(kwargs[k] if k in kwargs else self.__dict__[k]) for k in self.__dict__}
self.__dict__.update(args_dict)
This class uses every supplied keyword argument as an object attribute. Use it this way:
class CashDividends(KwargAttrs):
def __init__(self, gross, net, ISIN, paydate, exdate, recorddate, frequency, type, announceddate, currency):
# save the namespace before it gets polluted
super().__init__(**locals())
# work that might pollute local namespace goes here
# OPTIONAL: update the argument values in case they were modified:
super()._update(**locals())
Using a method like this, you don't have to go through the argument list and assign every single object attribute; it happens automatically.
We bookend everything you need to accomplish in the __init__ method with method calls to the parent-class via super(). We do this because locals() returns a dict every variable in the function's current namespace, so you need to 1.) capture that namespace before any other work pollutes it and 2.) update the namespace in case any work changes the argument values.
The call to update is optional, but the values of the supplied arguments will not be updated if something is done to them after the call to super().__init__() (that is, unless you change the values using setattr(self, 'argname, value)`, which is not a bad idea).
You can continue using this class like so:
class StockSplits(KwargAttrs):
def __init__(self, stocksplitratio, gross, net, ISIN, paydate, exdate, recorddate, frequency, type, announceddate, currency):
super().__init__(**locals())
As mentioned in the other answers you can create a container for our other classes, but you can even do that using this same template class:
class CorporateActions(KwargAttrs):
def __init__(self, stock_splits , cash_dividends):
super().__init__(**locals())
ca = CorporateActions(stock_splits = StockSplits(<arguments>), cash_dividends = CashDividends(<arguments>) )
I am trying to understand the mechanism of __import__(fromlist=['MyClass']).
Imagine I have several classes WhiteBox:
class WhiteBox:
def __init__(self):
self.name = "White Box"
self.color = None
def use(self, color):
self.paint(color)
def paint(self, color):
self.color = color
I am importing these classes with __import__(fromlist=['WhiteBox']) statement.
I decide to repaint all boxes with the same color and create a loop:
for box in imported_boxes:
box.WhiteBox().use = "green"
print("REPAINTED:", box.WhiteBox().name, box.WhiteBox().color)
When I try to access box.WhiteBox().color attribute, I still get None.
REPAINTED: WhiteBox None
I expected that __import__ would allow to manipulate the object as if it was instantiated, it appears not true. How do I solve this issue?
Use are using "use" as a property but it it defined as a function:
box = box.WhiteBox() = "green"
#change it to:
box.WhiteBox().use("green")
Next problem:
You are creating WhiteBox again and again so it will always have the initial None Value...
box.WhiteBox().use("green") #created once
print("REPAINTED:", box.WhiteBox().name, box.WhiteBox().color) #two more times...
Here's the coding problem I am trying to solve... I have a base class, let's say Animal, and it has two subclasses, say Dog and Cat. My class Animal has a method, make_baby(), that both Dog and Cat will inherit. The trick I'm having trouble pulling off is that I want the return value to be a new instance of the subclass that called the function but with different attribute values, i.e. Dog.make_baby() should return a new Dog and Cat.make_baby() will return a new Cat.
I previously tried returning "type(self)()", but this is no good because type() return a type object, not a class.
Here is the full example code:
Class Animal():
def __init__(self, color):
self.color = color
def make_baby():
new_color = rand_color # a randomly chosen color
return #??? new class of the same type that called the method
Class Dog(Animal):
def pet():
print '*pant*'
Class Cat(Animal):
def pet():
print 'purrr'
So I'd like to avoid writing a make_baby() method for Dogs and Cats because the idea is that the method is exactly the same except for the returned class. I'd also like to avoid a bunch of if statements because I'd like to make and arbitrarily large number of subclasses to Animal.
You wrote:
this is no good because type() return a type object, not a class.
A type is a class, if you're using new-style classes. If you're using Python 3, you're set; all Python 3 classes are "new-style." If you're using Python 2.x, derive your class from object (or from something else that derives from object, like any built-in Python type).
But what you really want here is a class method, where you get a reference to the class passed in automatically.
class Animal(object):
def __init__(self, color):
self.color = color
#classmethod
def make_baby(cls):
return cls(rand_color) # randomly-chosen color
You can call it on the class (e.g. Animal.make_baby() or Dog.make_baby()) or on an instance; either way the method still receives the class as the first argument.
type() can be used to construct entirely new classes. What you want is:
class Animal():
def __init__(self, color):
self.color = color
def make_baby(self):
new_color = rand_color # a randomly chosen color
return self.__class__(new_color)
You approach will totally work! Just use new style classes.
Class Animal(object):
def __init__(self, color):
self.color = color
def make_baby(self):
new_color = rand_color # a randomly chosen color
return type(self)(new_color)
Class Dog(Animal):
def pet():
print '*pant*'
Class Cat(Animal):
def pet():
print 'purrr'
However, if make_baby(self) is not relying on details of self, what you want is a class-wide factory method, like in #Kindall's answer.