Replacing member objects with subclasses in Python - python

I have the following problem that I will attempt to illustrate with the following example.
class Brick():
def __init__(self):
self.weight = 1
class House():
def __init__(self, number_bricks):
self.bricks = [Brick() for i in range(number_bricks)]
def get_weight(self):
return reduce(lambda x,y: x+y, [brick.weight for brick in self.bricks])
But now suppose I create a new kind of Brick, StrongBrick, so that I make a house, a subclass StrongHouse, where StrongBrick plays exactly the same role in StrongHouse as Brick plays in House. How can I do this in a nice way (not just retyping all the class definitions)?
So the basic idea is, how can I change a class which is composed of some objects to the same class but composed of say a subclass of the original member objects?
Thanks very much for any help you can give me.

You could have a factory (a brickyard?) and pass that to House.__init__().
class Brick(object): pass
class StrongBrick(Brick): pass
class House(object):
def __init__(self, brick_factory, num_bricks):
self.bricks = [brick_factory() for i in range(num_bricks)]
house = House(Brick, 10000)
strong_house = House(StrongBrick, 10000)
As you can see, subclassing House isn't even necessary to be able to construct houses from different types of bricks.

There are various ways to do this. You could make the relevant Brick class an attribute of the House class:
class House(object):
brick_class = Brick
def __init__(self, number_bricks):
self.bricks = [self.brick_class() for i in range(number_bricks)]
class StrongHouse(House):
brick_class = StrongBrick
Or, you could pass in the Brick class you want to use when constructing the House:
class House(object):
def __init__(self, brick_class, number_bricks):
self.bricks = [brick_class() for i in range(number_bricks)]

One nice pattern could be this:
class Brick(object):
weight = 1
class StrongBrick(Brick):
weight = 42
class House(object):
brick_type = Brick
def __init__(self, number_bricks):
self.bricks = [self.brick_type() for i in range(number_bricks)]
def get_weight(self):
return reduce(lambda x, y: x + y, [brick.weight for brick in self.bricks])
class StrongHouse(House):
brick_type = StrongBrick
Another is to make a function making a factory, and using an argument for the brick_type with default value:
class House(object):
def __init__(self, number_bricks, brick_type=Brick):
self.bricks = [brick_type() for i in range(number_bricks)]
def get_weight(self):
return reduce(lambda x, y: x + y, [brick.weight for brick in self.bricks])
def make_house_factory(brick_type):
def factory(number_bricks):
return House(number_bricks, brick_type)
return factory
StrongHouse = make_house_factory(StrongBrick)
Of course all such objects would be instances of the House only, even though I named StrongHouse here so that it resembles a class name.

But now suppose I create a new kind of Brick, StrongBrick, so that I make a house, a subclass StrongHouse, where StrongBrick plays exactly the same role in StrongHouse as Brick plays in House. How can I do this in a nice way (not just retyping all the class definitions)?
As all of the other answers have explained, you really don't want to create this parallel hierarchy at all. But to answer your direct question: You can create classes dynamically, so you can create a parallel hierarchy without copying and pasting all the class definitions. Classes are, after all, first-class objects.
Again, let me stress that you almost certainly don't want to do this, and I'm just showing that it is possible.
def make_house_class(brick_type):
class NewHouse(House):
def __init__(self, number_bricks):
self.bricks = [brick_type() for i in range(number_bricks)]
return NewHouse
Now, you could statically create all the house types:
StrongHouse = make_house_class(StrongBrick)
CheapHouse = make_house_class(CheapHouse)
# ...
… or maybe build them dynamically from a collection of all of your brick type:
brick_types = (StrongBrick, CheapBrick)
house_types = {brick_type: make_house_class(brick_type) for brick_type in brick_types}
… or even add some hacky introspection to just create a new FooHouse type for every FooBrick type in the current module:
for name, value in globals().items():
if name.endswith('Brick') and name != 'Brick' and isinstance(value, type):
globals()[name.replace('Brick', 'House')] = make_house_class(value)
… or even create them on the fly as needed in the factory-maker:
def make_house_factory(brick_type):
house_type = make_house_class(brick_type)
def factory(number_bricks):
return house_type(number_bricks, brick_type)
return factory
… or even the generated factory:
def make_house_factory(brick_type):
def factory(number_bricks):
return make_house_class(brick_type)(number_bricks, brick_type)
return factory

Add a parameter to the House.__init__ so that you can specify the Brick type:
import functools
class Brick():
def __init__(self):
self.weight = 1
class StrongBrick():
def __init__(self):
self.weight = 10
class House():
def __init__(self, number_bricks,brick_type=Brick):
self.bricks = [brick_type() for i in range(number_bricks)]
def get_weight(self):
return reduce(lambda x,y: x+y, [brick.weight for brick in self.bricks])
#not a new class, but an alias with a different default brick_type
StrongHouse = functools.partial(House,brick_type=StrongBrick)

Related

Following stratergy pattern; give interface access to parent attributes/methods

I'm learning strategy pattern and I would like to use parent class attributes in the dynamically assigned functions.
For example (you can guess the book):
class Duck():
def __init__(self, wingspan: int, quack_behavior, fly_behavior):
self.wingspan = wingspan
self.quack = quack_behavior.quack
self.fly = fly_behavior.fly
def quack(self):
pass
def fly(self):
pass
class FlyWithWings():
def fly(self):
print("I'm flying with wings")
print(f"speed of {self.wingspan*1.1}")
class Quack():
def quack(self):
print("Quack, quack!")
class MallardDuck(Duck):
def __init__(self):
super().__init__(wingspan=22, quack_behavior=Quack(), fly_behavior = FlyWithWings())
if __name__ == "__main__":
# welcome to the duck pond simulator
first_duck = MallardDuck()
first_duck.quack()
first_duck.fly()
This fails with
AttributeError: 'FlyWithWings' object has no attribute 'wingspan'
A side note:
I'm violating the loose coupling principal because FlyWithWings() class depends on an attribute named wingspan. But I've run into problems with functions that needed a dozen attributes, which become hard to maintain.
FlyWithWings is not aware of the specific wingspan of the object it's being used in. You can create a closure with the wingspan using functools.partial. This creates a function object with "frozen" arguments. So you can do:
from functools import partial
class Duck():
def __init__(self, wingspan: int, quack_behavior, fly_behavior):
self.wingspan = wingspan
self.quack = quack_behavior.quack
self.fly = partial(fly_behavior.fly, wingspan)
And change FlyWthWings to:
class FlyWithWings():
def fly(self, wingspan):
print("I'm flying with wings")
print(f"speed of {wingspan*1.1}")

Initialising nested classes in Python

Let's say I want to create a class 'House' that has some attributes of its own, but also has a (nested?) 'Resident' class which has some attributes and has a mandatory attribute 'surname'. A house instance may exist though without any residents. How can create this so that I can eventually do the following?
myhouse = House()
residentX = myhouse.resident('Smith')
Currently I set this up as a nested class but run into trouble when I try and initialise myhouse given that it is requiring a surname at this point for the nested Resident class (which I don't necessarily have at this point)
class House:
def __init__(self):
self.someattribute = <someattribute>
self.resident = self.Resident()
class Resident:
def __init__(self, surname):
self.surname = surname
I know I can restructure the code to not use nested classes and then explicitly tie any resident to a house in my code. However, I would like to use the dot notation here (myhouse.resident) to automatically tie a resident to a house.
Also, I understand that nested classes in python are somewhat frowned upon - I'm open to suggestions on how to do the above in a more pythonic manner.
I would break out the Resident class and use a property/setter for .resident
Like this:
class House:
def __init__(self):
self.someattribute = <someattribute>
self._resident = None
#property
def resident(self):
return self._resident
#resident.setter
def resident(self, surname):
r = Resident(surname)
self._resident = r
class Resident:
def __init__(self, surname):
self.surname = surname
However, if you want .resident to be callable but also want to track the house's residents, you can still break out the Resident class, and use:
class House:
def __init__(self):
self.someattribute = <someattribute>
self.residents = []
def resident(self, surname):
'''
Add a resident to the house
'''
r = Resident(surname)
self.residents.append(r)
return r
class Resident:
def __init__(self, surname):
self.surname = surname

Dynamically creating properties of a class

Take a look at this code snippet:
class Face():
pass
class Cube():
def __init__(self):
self.faces = {
'front': Face(1),
...
}
#property
def front(self):
return self.faces['front']
#front.setter
def front(self, f):
pass
I've created getters and setters for all the faces. Is there any way to make this code more compact, maybe by dynamically creating the getters and setters?
The following code assumes that you
have a reason to have the self.faces dict instead of setting attributes like front directly on the instance
and/or want to implement some meaningful getter and setter logic for the keys in self.faces.
Otherwise, this exercise is pretty pointless because as Corentin Limier noted you can simply set self.front = Face(1), and so on.
You can use descriptors, a class variable holding the face names and a class decorator. Think of descriptors as reusable properties.
In the following sample code I added a num instance variable to Face and the face 'side' just for demonstration purposes.
class FaceDescriptor:
def __get__(self, instance, owner):
# your custom getter logic
# dummy implementation
if instance is not None:
return instance.faces[self.face]
def __set__(self, instance, value):
# your custom setter logic
# dummy implementation
instance.faces[self.face] = value
def set_faces(cls):
for face in cls._faces:
desc = FaceDescriptor()
desc.face = face
setattr(cls, face, desc)
return cls
class Face():
def __init__(self, num):
self.num = num
#set_faces
class Cube():
_faces = ['front', 'side']
def __init__(self):
self.faces = {face:Face(i) for i, face in enumerate(self._faces, 1)}
In action:
>>> c = Cube()
>>> c.front.num
1
>>> c.side.num
2
>>> c.front = 'stuff'
>>> c.front
'stuff'
>>> c.faces
{'front': 'stuff', 'side': <__main__.Face at 0x7fd0978f37f0>}
Assuming that's all your class does, you could do something like
class Cube:
...
def __getattr__(self, name):
return self.faces[name]
def __setattr__(self, name, value):
self.faces[name] = value
if you really want to do that you could use __getattr__ and __setattr__:
class Cube:
...
def __getattr__(self, item):
return self.faces[item]
def __setattr__(self, item, value):
self.faces[item] = value
but as you set front in the __init__ methoud you could just as well make it a regular member...
Your code is redundant, since instance attributes are already stored in a dictionary which is the __dict__ property. I recognize that you are focused on writing your code in fewer lines. It is a good challenge to keep yourself growing, but in the long term you should be focused on the clarity of your code instead.
Here is a simpler way to write your code without using properties:
class Face():
pass
class Cube():
def __init__(self):
self.front = Face()
self.rear = Face()
It is a tenet of encapsulation that you should hide your "attributes" behind "properties". Even though this isn't strongly enforced in python, it's not a bad idea to do that. Here's the proper way to do that:
class Face():
pass
class Cube():
def __init__(self):
self._front = Face()
#property
def front(self):
return self._front
#front.setter
def front(self, value):
self._front = value
To answer your question at the end, yes you can dynamically create properties.
https://stackoverflow.com/a/1355444/3368572
But keep in mind that writing dynamic code should be reserved for special cases since it will make it more difficult for your IDE to follow the flow of your program. If you use the conventions as they are intended then your code becomes self-explanatory to people and to your IDE.

Python: showing attributes assigned to a class object in the class code

One of my classes does a lot of aggregate calculating on a collection of objects, then assigns an attribute and value appropriate to the specific object: I.e.
class Team(object):
def __init__(self, name): # updated for typo in code, added self
self.name = name
class LeagueDetails(object):
def __init__(self): # added for clarity, corrected another typo
self.team_list = [Team('name'), ...]
self.calculate_league_standings() # added for clarity
def calculate_league_standings(self):
# calculate standings as a team_place_dict
for team in self.team_list:
team.place = team_place_dict[team.name] # a new team attribute
I know, as long as the calculate_league_standings has been run, every team has team.place. What I would like to be able to do is to scan the code for class Team(object) and read all the attributes, both created by class methods and also created by external methods which operate on class objects. I am getting a little sick of typing for p in dir(team): print p just to see what the attribute names are. I could define a bunch of blank attributes in the Team __init__. E.g.
class Team(object):
def __init__(self, name): # updated for typo in code, added self
self.name = name
self.place = None # dummy attribute, but recognizable when the code is scanned
It seems redundant to have calculate_league_standings return team._place and then add
#property
def place(self): return self._place
I know I could comment a list of attributes at the top class Team, which is the obvious solution, but I feel like there has to be a best practice here, something pythonic and elegant here.
If I half understand your question, you want to keep track of which attributes of an instance have been added after initialization. If this is the case, you could use something like this:
#! /usr/bin/python3.2
def trackable (cls):
cls._tracked = {}
oSetter = cls.__setattr__
def setter (self, k, v):
try: self.initialized
except: return oSetter (self, k, v)
try: self.k
except:
if not self in self.__class__._tracked:
self.__class__._tracked [self] = []
self.__class__._tracked [self].append (k)
return oSetter (self, k, v)
cls.__setattr__ = setter
oInit = cls.__init__
def init (self, *args, **kwargs):
o = oInit (self, *args, **kwargs)
self.initialized = 42
return o
cls.__init__ = init
oGetter = cls.__getattribute__
def getter (self, k):
if k == 'tracked': return self.__class__._tracked [self]
return oGetter (self, k)
cls.__getattribute__ = getter
return cls
#trackable
class Team:
def __init__ (self, name, region):
self.name = name
self.region = region
#set name and region during initialization
t = Team ('A', 'EU')
#set rank and ELO outside (hence trackable)
#in your "aggregate" functions
t.rank = 4 # a new team attribute
t.ELO = 14 # a new team attribute
#see witch attributes have been created after initialization
print (t.tracked)
If I did not understand the question, please do specify which part I got wrong.
Due to Python's dynamic nature, I don't believe there is a general answer to your question. An attribute of an instance can be set in many ways, including pure assignment, setattr(), and writes to __dict__ . Writing a tool to statically analyze Python code and correctly determine all possible attributes of an class by analyzing all these methods would be very difficult.
In your specific case, as the programmer you know that class Team will have a place attribute in many instances, so you can decide to be explicit and write its constructor like so:
class Team(object):
def __init__(name ,place=None):
self.name = name
self.place = place
I would say there is no need to define a property of a simple attribute, unless you wanted side effects or derivations to happen at read or write time.

What's an example use case for a Python classmethod?

I've read What are Class methods in Python for? but the examples in that post are complex. I am looking for a clear, simple, bare-bones example of a particular use case for classmethods in Python.
Can you name a small, specific example use case where a Python classmethod would be the right tool for the job?
Helper methods for initialization:
class MyStream(object):
#classmethod
def from_file(cls, filepath, ignore_comments=False):
with open(filepath, 'r') as fileobj:
for obj in cls(fileobj, ignore_comments):
yield obj
#classmethod
def from_socket(cls, socket, ignore_comments=False):
raise NotImplemented # Placeholder until implemented
def __init__(self, iterable, ignore_comments=False):
...
Well __new__ is a pretty important classmethod. It's where instances usually come from
so dict() calls dict.__new__ of course, but there is another handy way to make dicts sometimes which is the classmethod dict.fromkeys()
eg.
>>> dict.fromkeys("12345")
{'1': None, '3': None, '2': None, '5': None, '4': None}
I don't know, something like named constructor methods?
class UniqueIdentifier(object):
value = 0
def __init__(self, name):
self.name = name
#classmethod
def produce(cls):
instance = cls(cls.value)
cls.value += 1
return instance
class FunkyUniqueIdentifier(UniqueIdentifier):
#classmethod
def produce(cls):
instance = super(FunkyUniqueIdentifier, cls).produce()
instance.name = "Funky %s" % instance.name
return instance
Usage:
>>> x = UniqueIdentifier.produce()
>>> y = FunkyUniqueIdentifier.produce()
>>> x.name
0
>>> y.name
Funky 1
The biggest reason for using a #classmethod is in an alternate constructor that is intended to be inherited. This can be very useful in polymorphism. An example:
class Shape(object):
# this is an abstract class that is primarily used for inheritance defaults
# here is where you would define classmethods that can be overridden by inherited classes
#classmethod
def from_square(cls, square):
# return a default instance of cls
return cls()
Notice that Shape is an abstract class that defines a classmethod from_square, since Shape is not really defined, it does not really know how to derive itself from a Square so it simply returns a default instance of the class.
Inherited classes are then allowed to define their own versions of this method:
class Square(Shape):
def __init__(self, side=10):
self.side = side
#classmethod
def from_square(cls, square):
return cls(side=square.side)
class Rectangle(Shape):
def __init__(self, length=10, width=10):
self.length = length
self.width = width
#classmethod
def from_square(cls, square):
return cls(length=square.side, width=square.side)
class RightTriangle(Shape):
def __init__(self, a=10, b=10):
self.a = a
self.b = b
self.c = ((a*a) + (b*b))**(.5)
#classmethod
def from_square(cls, square):
return cls(a=square.length, b=square.width)
class Circle(Shape):
def __init__(self, radius=10):
self.radius = radius
#classmethod
def from_square(cls, square):
return cls(radius=square.length/2)
The usage allows you to treat all of these uninstantiated classes polymorphically
square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle):
this_shape = polymorphic_class.from_square(square)
This is all fine and dandy you might say, but why couldn't I just use as #staticmethod to accomplish this same polymorphic behavior:
class Circle(Shape):
def __init__(self, radius=10):
self.radius = radius
#staticmethod
def from_square(square):
return Circle(radius=square.length/2)
The answer is that you could, but you do not get the benefits of inheritance because Circle has to be called out explicitly in the method. Meaning if I call it from an inherited class without overriding, I would still get Circle every time.
Notice what is gained when I define another shape class that does not really have any custom from_square logic:
class Hexagon(Shape):
def __init__(self, side=10):
self.side = side
# note the absence of classmethod here, this will use from_square it inherits from shape
Here you can leave the #classmethod undefined and it will use the logic from Shape.from_square while retaining who cls is and return the appropriate shape.
square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle, Hexagon):
this_shape = polymorphic_class.from_square(square)
I find that I most often use #classmethod to associate a piece of code with a class, to avoid creating a global function, for cases where I don't require an instance of the class to use the code.
For example, I might have a data structure which only considers a key valid if it conforms to some pattern. I may want to use this from inside and outside of the class. However, I don't want to create yet another global function:
def foo_key_is_valid(key):
# code for determining validity here
return valid
I'd much rather group this code with the class it's associated with:
class Foo(object):
#classmethod
def is_valid(cls, key):
# code for determining validity here
return valid
def add_key(self, key, val):
if not Foo.is_valid(key):
raise ValueError()
..
# lets me reuse that method without an instance, and signals that
# the code is closely-associated with the Foo class
Foo.is_valid('my key')
Another useful example of classmethod is in extending enumerated types. A classic Enum provides symbolic names which can be used later in the code for readability, grouping, type-safety, etc. This can be extended to add useful features using a classmethod. In the example below, Weekday is an enuerated type for the days of the week. It has been extended using classmethod so that instead of keeping track of the weekday ourselves, the enumerated type can extract the date and return the related enum member.
from enum import Enum
from datetime import date
class Weekday(Enum):
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5
SATURDAY = 6
SUNDAY = 7
#
#classmethod
def from_date(cls, date):
return cls(date.isoweekday())
Weekday.from_date(date.today())
<Weekday.TUESDAY: 2>
Source: https://docs.python.org/3/howto/enum.html
in class MyClass(object):
'''
classdocs
'''
obj=0
x=classmethod
def __init__(self):
'''
Constructor
'''
self.nom='lamaizi'
self.prenom='anas'
self.age=21
self.ville='Casablanca'
if __name__:
ob=MyClass()
print(ob.nom)
print(ob.prenom)
print(ob.age)
print(ob.ville)

Categories

Resources