Classes in Python - python

In Python is there any way to make a class, then make a second version of that class with identical dat,a but which can be changed, then reverted to be the same as the data in the original class?
So I would make a class with the numbers 1 to 5 as the data in it, then make a second class with the same names for sections (or very similar). Mess around with the numbers in the second class then with one function then reset them to be the same as in the first class.
The only alternative I've found is to make one aggravatingly long class with too many separate pieces of data in it to be readily usable.

A class is a template, it allows you to create a blueprint, you can then have multiple instances of a class each with different numbers, like so.
class dog(object):
def __init__(self, height, width, lenght):
self.height = height
self.width = width
self.length = length
def revert(self):
self.height = 1
self.width = 2
self.length = 3
dog1 = dog(5, 6, 7)
dog2 = dog(2, 3, 4)
dog1.revert()

Here's another answer kind of like pobk's; it uses the instance's dict to do the work of saving/resetting variables, but doesn't require you to specify the names of them in your code. You can call save() at any time to save the state of the instance and reset() to reset to that state.
class MyReset:
def __init__(self, x, y):
self.x = x
self.y = y
self.save()
def save(self):
self.saved = self.__dict__.copy()
def reset(self):
self.__dict__ = self.saved.copy()
a = MyReset(20, 30)
a.x = 50
print a.x
a.reset()
print a.x
Why do you want to do this? It might not be the best/only way.

Classes don't have values. Objects do. Is what you want basically a class that can reset an instance (object) to a set of default values?
How about just providing a reset method, that resets the properties of your object to whatever is the default?
I think you should simplify your question, or tell us what you really want to do. It's not at all clear.

I think you are confused. You should re-check the meaning of "class" and "instance".
I think you are trying to first declare a Instance of a certain Class, and then declare a instance of other Class, use the data from the first one, and then find a way to convert the data in the second instance and use it on the first instance...
I recommend that you use operator overloading to assign the data.

class ABC(self):
numbers = [0,1,2,3]
class DEF(ABC):
def __init__(self):
self.new_numbers = super(ABC,self).numbers
def setnums(self, numbers):
self.new_numbers = numbers
def getnums(self):
return self.new_numbers
def reset(self):
__init__()

Just FYI, here's an alternate implementation... Probably violates about 15 million pythonic rules, but I publish it per information/observation:
class Resettable(object):
base_dict = {}
def reset(self):
self.__dict__ = self.__class__.base_dict
def __init__(self):
self.__dict__ = self.__class__.base_dict.copy()
class SomeClass(Resettable):
base_dict = {
'number_one': 1,
'number_two': 2,
'number_three': 3,
'number_four': 4,
'number_five': 5,
}
def __init__(self):
Resettable.__init__(self)
p = SomeClass()
p.number_one = 100
print p.number_one
p.reset()
print p.number_one

Related

Python Fix Dependancy Cycle

I'm working on a game using python.
The AI in the game uses variables that the player has, and vice versa.
For an example:
class Player():
def __init__(self, canvas...):
self.id = canvas.create_rectangle(...)
...
def touching_AI(self):
aipos = canvas.coords(AI object)
pos = canvas.coords(self.id)
...
#the function above checks if the player is touching the AI if it
#is, then call other functions
this = player(canvas...)
class AI():
def __init__(self, canvas...):
self.id = canvas.create_rectangle(...)
def chase_player(self):
playerpos = canvas.coords(this.id)
pos = canvas.coords(self.id)
...
# a lot of code that isn't important
Obviously, Python says that the AI object in the player class isn't defined. Both classes depend on the other to work. However, one isn't defined yet, so if I put one before the other, it returns an error. While there is probably a workaround for these two functions only, there are more functions that I didn't mention.
In summary, is there a way (pythonic or non-pythonic) to use and/or define an object before it is created (i.e even making more files)?
you do not
instead use arguments
class Player():
def __init__(self, canvas...):
self.id = canvas.create_rectangle(...)
...
def touching(self,other):
aipos = canvas.coords(other.object)
pos = canvas.coords(self.id)
...
#the function above checks if the player is touching the AI if it
#is, then call other functions
class AI():
def __init__(self, canvas...):
self.id = canvas.create_rectangle(...)
def chase(self,player):
playerpos = canvas.coords(player.id)
pos = canvas.coords(self.id)
then
player = Player(canvas...)
ai = AI(...)
ai.chase(player)
player.touching(ai)
but even better is to define a base object type that defines your interface
class BaseGameOb:
position = [0,0]
def distance(self,other):
return distance(self.position,other.position)
class BaseGameMob(BaseGameOb):
def chase(self,something):
self.target = something
def touching(self,other):
return True or False
then all your things inherit from this
class Player(BaseGameMob):
... things specific to Player
class AI(BaseGameMob):
... things specific to AI
class Rat(AI):
... things specific to a Rat type AI
You do not have a dependency cycle problem. But, you have the following problem,
You are trying it use an AI object, but you did not create the object anywhere. It needs to look like,
foo = AI() #creating the object
bar(foo) #using the object
The syntax is wrong around canvas.coords(AI object).
The way to call a function is foo(obj) without the type.
When defining a function you can optionally mention the type like def foo(bar : 'AI'):
The proof you can depend classes on each other, https://pyfiddle.io/fiddle/b75f2de0-2956-472d-abcf-75a627e77204/
You can initialize one without specifying the type and assign it in afterwards. Python kind of pretends everyone are grown-ups so..
e.g.:
class A:
def __init__(self, val):
self.val = val
self.b = None
class B:
def __init__(self, a_val):
self.a = A(a_val)
a_val = 1
b = B(1)
a = b.a
a.b = b

Python: object with a list of objects - create methods based on properties of list members

I have a class which contains a list like so:
class Zoo:
def __init__(self):
self._animals = []
I populate the list of animals with animal objects that have various properties:
class Animal:
def __init__(self, speed, height, length):
self._speed = speed
self._height = height
self._length = length
You can imagine subclasses of Animal that have other properties. I want to be able to write methods that perform the same calculation but on different attributes of the Animal. For example, an average. I could write the following in Zoo:
def get_average(self, propertyname):
return sum(getattr(x, propertyname) for x in self.animals) / len(self.animals)
That string lookup not only messes with my ability to document nicely, but using getattr seems odd (and maybe I'm just nervous passing strings around?). If this is good standard practice, that's fine. Creating get_average_speed(), get_average_height(), and get_average_length() methods, especially as I add more properties, seems unwise, too.
I realize I am trying to encapsulate a one-liner in this example, but is there a better way to go about creating methods like this based on properties of the objects in the Zoo's list? I've looked a little bit at factory functions, so when I understand them better, I think I could write something like this:
all_properties = ['speed', 'height', 'length']
for p in all_properties:
Zoo.make_average_function(p)
And then any instance of Zoo will have methods called get_average_speed(), get_average_height(), and get_average_length(), ideally with nice docstrings. Taking it one step further, I'd really like the Animal objects themselves to tell my Zoo what properties can be turned into get_average() methods. Going to the very end, let's say I subclass Animal and would like it to indicate it creates a new average method: (the following is pseudo-code, I don't know if decorators can be used like this)
class Tiger(Animal):
def __init__(self, tail_length):
self._tail_length = tail_length
#Zoo.make_average_function
#property
def tail_length(self):
return self._tail_length
Then, upon adding a Tiger to a Zoo, my method that adds animals to Zoo object would know to create a get_average_tail_length() method for that instance of the Zoo. Instead of having to keep a list of what average methods I need to make, the Animal-type objects indicate what things can be averaged.
Is there a nice way to get this sort of method generation? Or is there another approach besides getattr() to say "do some computation/work on an a particular property of every member in this list"?
Try this:
import functools
class Zoo:
def __init__(self):
self._animals = []
#classmethod
def make_average_function(cls, func):
setattr(cls, "get_average_{}".format(func.__name__), functools.partialmethod(cls.get_average, propertyname=func.__name__))
return func
def get_average(self, propertyname):
return sum(getattr(x, propertyname) for x in self._animals) / len(self._animals)
class Animal:
def __init__(self, speed, height, length):
self._speed = speed
self._height = height
self._length = length
class Tiger(Animal):
def __init__(self, tail_length):
self._tail_length = tail_length
#property
#Zoo.make_average_function
def tail_length(self):
return self._tail_length
my_zoo = Zoo()
my_zoo._animals.append(Tiger(10))
my_zoo._animals.append(Tiger(1))
my_zoo._animals.append(Tiger(13))
print(my_zoo.get_average_tail_length())
Note: If there are different zoos have different types of animals, it will lead to confusion.
Example
class Bird(Animal):
def __init__(self, speed):
self._speed = speed
#property
#Zoo.make_average_function
def speed(self):
return self._speed
my_zoo2 = Zoo()
my_zoo2._animals.append(Bird(13))
print(my_zoo2.get_average_speed()) # ok
print(my_zoo.get_average_speed()) # wrong
print(my_zoo2.get_average_tail_length()) # wrong

How subclass master AND another class used by master in Python

I have subclassed a large master class from a library. My subclass works fine but I now want to also subclass another class used by the master. But, I don't see how without editing the master class to use my new subclass. Put another way, I want to signal that usage of class "abc' in subclass of master should be replaced by a subclass of 'abc' Here is some pseudocode to illustrate the problem where I want to inherit getenginestats but using a subclassed return type. I know I can override a method or two but the second class is used all over the master so that is not a practical approach.
class vehicle(object):
horsepower = 0
def getenginestats():
# returns an enginestats object
stats = EngineStats()
stats.rpm = 1000
return stats
class EngineStats(object):
rpm = 0
class MyEngineStats(EngineStats):
# add battery voltage to stats
voltage = 0
class ElectricCar(vehicle)
batterysize = 0
prius = ElectricCar()
# how do I get ElectricCar.getenginestats into a MyEngineStats object??
mystats = prius.getenginestats
myvoltage = mystats.voltage
Bill
You need to call the function getenginestats() and fix some typos:
class vehicle(object):
horsepower = 0
def getenginestats(self):
# returns an enginestats object
stats = MyEngineStats()
stats.rpm = 1000
return stats
class EngineStats(object):
rpm = 0
class MyEngineStats(EngineStats):
# add battery voltage to stats
voltage = 1500
class ElectricCar(vehicle):
batterysize = 0
prius = ElectricCar()
mystats = prius.getenginestats()
myvoltage = mystats.voltage
print(myvoltage)
returns:
1500
You would need to overwrite the randint function (for example):
import random
def _randint(a, b):
return MyInt(random.original_randint(a, b))
class MyInt(int):
def __new__(cls, *args, **kwargs):
return super(MyInt, cls).__new__(cls, args[0])
def isOdd(self):
return
_min = MyInt(0)
_max = MyInt(9)
random.original_randint = random.randint
random.randint = _randint
x = random.randint(_min, _max)
print(type(x), x)
Returns:
(<class '__main__.MyInt'>, 3)
Thanks for the feedback. Sounds like it is not possible to do this "nested subclassing"?
I think this would be useful to others too given that many libraries have helper classes for structures and enums. If I can subclass somebiglibrary, why not allow me to also subclass the somebiglibrarystatus(enum) into my subclass.
Easy to work around but would have been nice.
Thanks
Bill

Clean pythonic composition with default parameters

Suppose I want to compose two objects and I'd like to be able to be able to define multiple constructors that respect the default arguments.
class A:
def __init__(x,y=0):
self.x = x
self.y = y
class B:
def __init__(w,objA, z=1):
self.w = w
self.objA = objA
self.z = z
I'd like to have multiple constructors for B which allow me to either pass an object A or pass parameters and then construct A. Looking at What is a clean, pythonic way to have multiple constructors in Python? I can do:
class B:
def __init__(w, objA, z=1):
self.w = w
self.objA = objA
self.z=z
#classmethod
def from_values(cls,w,z,x,y):
objA = A(x,y)
return cls(w,objA,z)
The problem is that the default values are being overwritten and I'd like to keep them. The following of course does not work.
#classmethod
def from_values(cls,w,x,**kwargs):
objA = A(x,**kwargs)
return cls(w,objA,**kwargs)
So it seems I'm stuck with remembering the default values and calling them like this
#classmethod
def from_values(cls,w,x,z=1,y=0):
objA = A(x,y)
return cls(w,objA,z)
This is not what I want since I'd rather have the objects themselves handle the default values and not be forced remember the default values. I could do one better than the above and use:
#classmethod
def from_values(cls,w,x,z=1,**kwargs):
objA = A(x,**kwargs)
return cls(w,objA,z)
But in this case I still need to "remember" the default value for z. Is there a Pythonic solution to this? Is this a design problem? Can someone point me to a good design pattern or best practices? This problem compounds when composing with several objects...
class L:
def __init__(objM,objN):
self.objM = objM
self.objN = objN
#classmethod
def from_values(cls, m1,m2,m3,n1,n2):
objM = M(m1,m2,m3)
objN = N(n1,n2)
return cls(objM, objN)
First I would argue that this isn't what you want to do. As this scales up, trying to call your constructor will be tedious and error-prone.
You can solve both of our problems with an explicit dictionary.
class A:
def __init__(self, config):
self.x = config.get('x')
assert self.x # if you need it
self.y = config.get('y', 0)
class B:
def __init__(self, b_config, objA):
self.w = b_config.get('w')
self.objA = objA
self.z = b_config.get('z', 1)
#classmethod
def from_values(cls,b_config,a_config):
return cls(b_config, A(a_config))
B.from_values({'w':1, 'z':2}, {'x': 3, 'y': 4})
It's probably not as clever or neat as what you're looking for, but it does let you construct from an A if you already have it, or to pass in a configurable set of parameters in a more structured way.

Create multiple classes or multiple objects in Python?

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>) )

Categories