What' the meaning of the brackets in the class? - python

In python, when I read others' code, I meet this situation where a class is defined and after it there is a pair of brackets.
class AStarFoodSearchAgent(SearchAgent):
def __init__():
#....
I don't know what is the meaning of '(SearchAgent)',because what I usually meet and use doesn't seem that.

It indicates that AStarFoodSearchAgent is a subclass of SearchAgent. It's part of a concept called inheritance.
What is inheritance?
Here's an example. You might have a Car class, and a RaceCar class. When implementing the RaceCar class, you may find that it has a lot of behavior that is very similar, or exactly the same, as a Car. In that case, you'd make RaceCar a subclass ofCar`.
class Car(object):
#Car is a subclass of Python's base objeect. The reasons for this, and the reasons why you
#see some classes without (object) or any other class between brackets is beyond the scope
#of this answer.
def get_number_of_wheels(self):
return 4
def get_engine(self):
return CarEngine(fuel=30)
class RaceCar(Car):
#Racecar is a subclass of Car
def get_engine(self):
return RaceCarEngine(fuel=50)
my_car = Car() #create a new Car instance
desired_car = RaceCar() #create a new RaceCar instance.
my_car.get_engine() #returns a CarEngine instance
desired_car.get_engine() #returns a RaceCarEngine instance
my_car.get_number_of_wheels() #returns 4.
desired_car.get_number_of_wheels() # also returns 4! WHAT?!?!?!
We didn't define get_number_of_wheels on RaceCar, and still, it exists, and returns 4 when called. That's because RaceCar has inherited get_number_of_wheels from Car. Inheritance is a very nice way to reuse functionality from other classes, and override or add only the functionality that needs to be different.
Your Example
In your example, AStarFoodSearchAgent is a subclass of SearchAgent. This means that it inherits some functionality from SearchAgemt. For instance, SearchAgent might implement a method called get_neighbouring_locations(), that returns all the locations reachable from the agent's current location. It's not necessary to reimplement this, just to make an A* agent.
What's also nice about this, is that you can use this when you expect a certain type of object, but you don't care about the implementation. For instance, a find_food function may expect a SearchAgent object, but it wouldn't care about how it searches. You might have an AStarFoodSearchAgent and a DijkstraFoodSearchAgent. As long as both of them inherit from SearchAgent, find_food can use ìsinstanceto check that the searcher it expects behaves like aSearchAgent. Thefind_food`function might look like this:
def find_food(searcher):
if not isinstance(searcher, SearchAgent):
raise ValueError("searcher must be a SearchAgent instance.")
food = searcher.find_food()
if not food:
raise Exception("No, food. We'll starve!")
if food.type == "sprouts":
raise Exception("Sprouts, Yuk!)
return food
Old/Classic Style Classes
Upto Python 2.1, old-style classes were the only type that existed. Unless they were a subclass of some other class, they wouldn't have any parenthesis after the class name.
class OldStyleCar:
...
New style classes always inherit from something. If you don't want to inherit from any other class, you inherit from object.
class NewStyleCar(object):
...
New style classes unify python types and classes. For instance, the type of 1, which you can obtain by calling type(1) is int, but the type of OldStyleClass() is instance, with new style classes, type(NewStyleCar) is Car.

SearchAgent is the superclass of the class AStarFoodSearchAgent. This basically means that an AStarFoodSearchAgent is a special kind of SearchAgent.

It means that class AStarFoodSearchAgent extends SearchAgent.
Check section 9.5 here
https://docs.python.org/2/tutorial/classes.html

This is inheritance in python, just like in any other OO language
https://docs.python.org/2/tutorial/classes.html#inheritance

It means that SearchAgent is a base class of AStarFoodSearchAgent. In other word, AStarFoodSearchAgent inherits from SearchAgent class.
See Inheritance - Python tutorial.

Related

how could a class inherit from another class after create as instance

I am wondering if I can able to inherit one of class after the instance has been initialized. As following I have two class as Child and 'Outfit' and after create a instance as child. I would like it to be inherited from class Outfit so I can use the function get_cloth to return blue. For some reason, I do not want Child to inherit from Outfit class
class Outfit(object):
def __init__(self):
self.cloth = 'blue' if self.gender == 'M' else 'red'
def get_cloth(self):
return self.cloth
class Child:
def __init__(self, name, gender):
self.name = name
self.gender = gender
child = Child('tom', 'M')
print(child.get_cloth())
It doesn't make sense to do what you're trying to do. Objects don't inherit, only types do. The instance child has a type that can inherit (be a subtype of) another type, but that type is Child, and you said that you don't want Child to inherit from Outfit.
This isn't something that necessarily has to be true for any object-oriented programming language; rather, it's the fundamental difference between class-based OO (Python, Ruby, Smalltalk, C++, Java, etc.) and prototype-based OO (JavaScript, Self, IO, and a few other languages you've never heard of).
There are some things you can do that are somewhat close to what you're asking for, but they're all things you very rarely want to do.
If you're interested in subtyping—that is, making isinstance(child, Outfit) true:
You can change Child to inherit from Outfit after it's been created (e.g., by setting its __mro__ attribute). You can even after the child instance has been created. Then child will now be an instance of something that subtypes Outfit.
You can change the type of child to a different type after creation (by setting its __class__ attribute). But you'd still need to create some type that is a subtype of Outfit. Maybe a type that's a copy of the Child class but with different bases, or maybe it's an empty class whose bases are Child and Outfit.
You can make Child into a "virtual subclass" of Outfit by defining an Outfit.__subclasscheck__ method. This will work even after Outfit, Child, and child have all been created. In this case, although isinstance(child, Outfit) will pass, it's not actually going to act like an Outfit; you're just fooling isinstance. Or, put a different way, you're getting nominal subtyping without behavioral subtyping.
You can make child into a "virtual instance" of Outfit, without making Child into a virtual subclass, by defining an Outfit.__instancecheck__ method.
You can build a Prototype metaclass that effectively flattens out the distinction between classes and instances for its types, and instead gives you something like the Self or JavaScript object model. This is a lot of work, and your Prototype classes will do weird things when interacting with "normal" classes, but it is doable. Having done that, you can then modify child's prototype chain however you want.
If you're only interested in inheriting behavior—not just duck typing as an Outfit, but letting Outfit do the work for you—the easiest way to do that is to forget about types and just compose an Outfit instance into child and forward. But unfortunately, that's not as easy as it sounds:
You can define a __getattr__. But that won't actually be called for child.spam, only for getattr(child, 'spam'); only the type's __getattr__ makes a difference for normal member access. If that matters (and it almost certainly does) you need to build a new type and reassign __class__, as described earlier.
You can iterate all of the methods of Outfit, or of the composed outfit instance, and explicitly add forwarding (bound) methods to child. But only a small subset of special methods will look at the instance instead of the class. So, while child.spam() will work, child + 2 will not. If that's a problem (and it usually is, but not quite as universally as the last case), you still need to build a new type and reassign __class__.
Anyway, all of these things are possible, because they are very occasionally useful, but none of them are made easy for you, because they are almost always the wrong thing to do. (If you do decide you want to do any of them, and it isn't obvious how to do it from the docs, and there isn't another question here that explains how, create a new question, explaining clearly which one you want to do and why.)
As described in the previous answers, applying the concept of inheritance at the instance level rather than the class level does not make much sense. If what you really want is just for child to have access to the get_cloth method of Outfit, you can assign it explicitly:
child = Child('tom', 'M')
child.get_cloth = Outfit().get_cloth
print(child.get_cloth())
Note that I use Outfit().get_cloth and not Outfit.get_cloth to extract get_cloth as a method on not just as a function.
The fact that this is easily possible comes down to the design choice of the Python language of having self be an argument to every method, instead of some fixed non-local variable.
You could do this a bit more safely by making Child intentionally pass on unknown attributes:
class Outfit(object):
def __init__(self, child_self):
self.cloth = 'blue' if child_self.gender == 'M' else 'red'
def get_cloth(self):
return self.cloth
class Child:
def __init__(self, name, gender):
self.super_self = None
...
def __getattr__(self, name):
if self.super_self is None:
raise AttributeError(name)
else:
return getattr(self.super_self , name)
child = Child(...)
child.super_self = Outfit(child)
print(child.get_cloth()) # Should work now

Add a user selected method to a meta base class in python

I have base class that cannot be instanciated (BaseFruit in my simplified example) and a few derived classes (for instance Apple in my example) that should all share a same method (printfuture). However, they are many possible variants, and I would like to let the user choose what variant should be used (for instance sadfuture and saddestfuture).
As my printfuture method is common to all my derived class, I thought that it would be appropriated to catch the user argument for the variant with the __new__ method of my base class and assign the method to the base class itself. As written in the example below:
# my custom methods
def sadfuture(self):
"""A sad future"""
print 'It looks {}!'.format(self.aspect)
print 'Mmm yummy !'
def saddestfuture(self):
"""A saddest future"""
print 'It looks {}'.format(self.aspect)
print 'Garbage !'
# my base class
class BaseFruit(object):
"""Fruit base class"""
def __new__(cls, *args, **kwargs):
setattr(cls, 'printfuture', kwargs['usermethod'])
return object.__new__(cls)
# My class
class Apple(BaseFruit):
"""An apple class"""
def __init__(self, aspect, usermethod=sadfuture):
self.aspect = aspect
if __name__ == '__main__':
goodapple = Apple(aspect='delicious', usermethod=sadfuture)
goodapple.printfuture() # ==> ok
badapple = Apple(aspect='rotten', usermethod=saddestfuture)
goodapple.printfuture() # ==> not ok anymore
badapple.printfuture() # ==> ok
Which prints:
It looks delicious!
Mmm yummy !
It looks delicious
Garbage !
It looks rotten
Garbage !
instead of the expected behavior:
It looks delicious!
Mmm yummy !
It looks delicious!
Mmm yummy !
It looks rotten
Garbage !
I do understand that I have overwritten my base class and my first object has changed its behavior. So, my main question is: how can I achieve the expected behavior while keeping my custom methods out of the base class?
Comments on best practices and on proper designs for such problems are also welcome.
The "expected" behavior is truly what is actually printed. So, the behavior is not what "you were expecting", which is a different thing. Let's se why:
What you are doing is creating a new method on the instantiated class (in this case, Apple) each time you mak ea new instance of Apple. The line setattr(cls, 'printfuture', kwargs['usermethod']) does exactly that, each time you create a new instance of BaseFruit or any subclass of it. (By the way, this line could be simply cls.printfuture = kwargs['usermethod'], there is no need for setattr if the attribute name is hardcoded).
So, when you create your second instance of Apple, the callbadapple = Apple(aspect='rotten', usermethod=saddestfuture) just make saddestfuture the printfuture for the Apple class to be saddestfuture, not just the method for badapple, but for any instance of Apple.
Fixing that has no need for a metaclass - you can use the code in __new__ itself to create a "pseudomethod", attached to the instance instead - as you intend. But you have to do that on the instance, after it is created, when you have a reference to the instance, not before instantiation, whenyou just have a reference to the class itself.
Since there is no actual code you need to run on before instatianting the class, you may as well bind the method-like function in __init__, and leave customizing __new__ just for when it is really needed. And while at that, it won't hurt to use super instead of hardcoding the superclass's call:
...
# my base class
class BaseFruit(object):
"""Fruit base class"""
def __init__(self, *args, **kwargs):
printfuture = kwargs.pop('usermethod')
super(BaseFruit, self).__init__(*args, **kwargs)
# Wrap the call to the passed method in a function
# that captures "self" from here, since Python do not
# insert "self" in calls to functions
# attributed to instances.
self.printfuture = lambda: printfuture(self)
# My class
class Apple(BaseFruit):
"""An apple class"""
def __init__(self, aspect, usermethod=sadfuture):
super(Apple, self).__init__(usermethod)
self.aspect = aspect
And as for metaclasses, this has no need for them - to the contrary, you have to customize each instance as it is created. We usually make use of metaclasses when we have to customize the class itself. Your original code is doing that (customizing the class itself), but the code for that is run when each instance is created, which made for the behavior you were not expecting. If the code to create the printfuture method where on the metaclass __new__ method instead, what is not the same as being in a superclass, that would happen just once, when each subclass is declared (and all instances of that subclass would share the same printifuture method).
Now, once you grasp how this works, please, just move to Python 3 to continue learning this stuff. Python 2 will be at complete end of line in 2 years from now, and will be useless in any prokect. One thing is having to keep legacy code in Python 2, another is learning or starting new projects - you should only use Python 3 for that.
I think that the problem is coming from the base class.
When you used the BaseFruit and used it as base class for the Apple-Class, python will assign any value that exist in the Apple-Class and the BaseFruit-Class directly to the BaseFruit Class. Since both 'apples' are based on the same Base Class, they share the values that come from this class.
When you set the saddestfuture as function to be executed you set it kind of 'globally' for all objects based on the BaseFruit-Class.
You need a line
self.userm = usermethod
in the __init__ of the apple. Then you pass this self.userm to the BaseClass as an kwarg and not the string "usermethod".
I don't know excatly the syntax for this operation as I have not worked with python inheritance rules for a long time and I admit I have forgotten the syntax. Maybe somebody else can propose code in a comment or you find that out yourself :-) .

pick a subclass based on a parameter

I have a module (db.py) which loads data from different database types (sqlite,mysql etc..) the module contains a class db_loader and subclasses (sqlite_loader,mysql_loader) which inherit from it.
The type of database being used is in a separate params file,
How does the user get the right object back?
i.e how do I do:
loader = db.loader()
Do I use a method called loader in the db.py module or is there a more elegant way whereby a class can pick its own subclass based on a parameter? Is there a standard way to do this kind of thing?
Sounds like you want the Factory Pattern. You define a factory method (either in your module, or perhaps in a common parent class for all the objects it can produce) that you pass the parameter to, and it will return an instance of the correct class. In python the problem is a bit simpler than perhaps some of the details on the wikipedia article as your types are dynamic.
class Animal(object):
#staticmethod
def get_animal_which_makes_noise(noise):
if noise == 'meow':
return Cat()
elif noise == 'woof':
return Dog()
class Cat(Animal):
...
class Dog(Animal):
...
is there a more elegant way whereby a class can pick its own subclass based on a parameter?
You can do this by overriding your base class's __new__ method. This will allow you to simply go loader = db_loader(db_type) and loader will magically be the correct subclass for the database type. This solution is mildly more complicated than the other answers, but IMHO it is surely the most elegant.
In its simplest form:
class Parent():
def __new__(cls, feature):
subclass_map = {subclass.feature: subclass for subclass in cls.__subclasses__()}
subclass = subclass_map[feature]
instance = super(Parent, subclass).__new__(subclass)
return instance
class Child1(Parent):
feature = 1
class Child2(Parent):
feature = 2
type(Parent(1)) # <class '__main__.Child1'>
type(Parent(2)) # <class '__main__.Child2'>
(Note that as long as __new__ returns an instance of cls, the instance's __init__ method will automatically be called for you.)
This simple version has issues though and would need to be expanded upon and tailored to fit your desired behaviour. Most notably, this is something you'd probably want to address:
Parent(3) # KeyError
Child1(1) # KeyError
So I'd recommend either adding cls to subclass_map or using it as the default, like so subclass_map.get(feature, cls). If your base class isn't meant to be instantiated -- maybe it even has abstract methods? -- then I'd recommend giving Parent the metaclass abc.ABCMeta.
If you have grandchild classes too, then I'd recommend putting the gathering of subclasses into a recursive class method that follows each lineage to the end, adding all descendants.
This solution is more beautiful than the factory method pattern IMHO. And unlike some of the other answers, it's self-maintaining because the list of subclasses is created dynamically, instead of being kept in a hardcoded mapping. And this will only instantiate subclasses, unlike one of the other answers, which would instantiate anything in the global namespace matching the given parameter.
I'd store the name of the subclass in the params file, and have a factory method that would instantiate the class given its name:
class loader(object):
#staticmethod
def get_loader(name):
return globals()[name]()
class sqlite_loader(loader): pass
class mysql_loader(loader): pass
print type(loader.get_loader('sqlite_loader'))
print type(loader.get_loader('mysql_loader'))
Store the classes in a dict, instantiate the correct one based on your param:
db_loaders = dict(sqlite=sqlite_loader, mysql=mysql_loader)
loader = db_loaders.get(db_type, default_loader)()
where db_type is the paramter you are switching on, and sqlite_loader and mysql_loader are the "loader" classes.

What is the correct way to extend a parent class method in modern Python

I frequently do this sort of thing:
class Person(object):
def greet(self):
print "Hello"
class Waiter(Person):
def greet(self):
Person.greet(self)
print "Would you like fries with that?"
The line Person.greet(self) doesn't seem right. If I ever change what class Waiter inherits from I'm going to have to track down every one of these and replace them all.
What is the correct way to do this is modern Python? Both 2.x and 3.x, I understand there were changes in this area in 3.
If it matters any I generally stick to single inheritance, but if extra stuff is required to accommodate multiple inheritance correctly it would be good to know about that.
You use super:
Return a proxy object that delegates
method calls to a parent or sibling
class of type. This is useful for
accessing inherited methods that have
been overridden in a class. The search
order is same as that used by
getattr() except that the type itself
is skipped.
In other words, a call to super returns a fake object which delegates attribute lookups to classes above you in the inheritance chain. Points to note:
This does not work with old-style classes -- so if you are using Python 2.x, you need to ensure that the top class in your hierarchy inherits from object.
You need to pass your own class and instance to super in Python 2.x. This requirement was waived in 3.x.
This will handle all multiple inheritance correctly. (When you have a multiple inheritance tree in Python, a method resolution order is generated and the lookups go through parent classes in this order.)
Take care: there are many places to get confused about multiple inheritance in Python. You might want to read super() Considered Harmful. If you are sure that you are going to stick to a single inheritance tree, and that you are not going to change the names of classes in said tree, you can hardcode the class names as you do above and everything will work fine.
Not sure if you're looking for this but you can call a parent without referring to it by doing this.
super(Waiter, self).greet()
This will call the greet() function in Person.
katrielalex's answer is really the answer to your question, but this wouldn't fit in a comment.
If you plan to go about using super everywhere, and you ever think in terms of multiple inheritance, definitely read the "super() Considered Harmful" link. super() is a great tool, but it takes understanding to use correctly. In my experience, for simple things that don't seem likely to get into complicated diamond inheritance tangles, it's actually easier and less tedious to just call the superclass directly and deal with the renames when you change the name of the base class.
In fact, in Python2 you have to include the current class name, which is usually more likely to change than the base class name. (And in fact sometimes it's very difficult to pass a reference to the current class if you're doing wacky things; at the point when the method is being defined the class isn't bound to any name, and at the point when the super call is executed the original name of the class may not still be bound to the class, such as when you're using a class decorator)
I'd like to make it more explicit in this answer with an example. It's just like how we do in JavaScript. The short answer is, do that like we initiate the constructor using super.
class Person(object):
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, I'm {self.name}")
class Waiter(Person):
def __init__(self, name):
super().__init__(name)
# initiate the parent constructor
# or super(Waiter, self).__init__(name)
def greet(self):
super(Waiter, self).greet()
print("Would you like fries with that?")
waiter = Waiter("John")
waiter.greet()
# Hello, I'm John
# Would you like fries with that?

Need help with the class and instance concept in Python

I have read several documentation already but the definition of "class" and "instance" didnt get really clear for me yet.
Looks like that "class" is like a combination of functions or methods that return some result is that correct? And how about the instance? I read that you work with the class you creat trough the instance but wouldnt be easier to just work direct with the class?
Sometimes geting the concepts of the language is harder than working with it.
Your question is really rather broad as classes and instances/objects are vital parts of object-oriented programming, so this is not really Python specific. I recommend you buy some books on this as, while initially basic, it can get pretty in-depth. In essense, however:
The most popular and developed model of OOP is a class-based model, as opposed to an object-based model. In this model, objects are entities that combine state (i.e., data), behavior (i.e., procedures, or methods) and identity (unique existence among all other objects). The structure and behavior of an object are defined by a class, which is a definition, or blueprint, of all objects of a specific type. An object must be explicitly created based on a class and an object thus created is considered to be an instance of that class. An object is similar to a structure, with the addition of method pointers, member access control, and an implicit data member which locates instances of the class (i.e. actual objects of that class) in the class hierarchy (essential for runtime inheritance features).
So you would, for example, define a Dog class, and create instances of particular dogs:
>>> class Dog():
... def __init__(self, name, breed):
... self.name = name
... self.breed = breed
... def talk(self):
... print "Hi, my name is " + self.name + ", I am a " + self.breed
...
>>> skip = Dog('Skip','Bulldog')
>>> spot = Dog('Spot','Dalmatian')
>>> spot.talk()
Hi, my name is Spot, I am a Dalmatian
>>> skip.talk()
Hi, my name is Skip, I am a Bulldog
While this example is silly, you can then start seeing how you might define a Client class that sets a blueprint for what a Client is, has methods to perform actions on a particular client, then manipulate a particular instance of a client by creating an object and calling these methods in that context.
Sometimes, however, you have methods of a class that don't really make sense being accessed through an instance of the class, but more from the class itself. These are known as static methods.
I am not sure of what level of knowledge you have, so I apologize if this answer is too simplified (then just ignore it).
A class is a template for an object. Like a blueprint for a car. The instance of a class is like an actual car. So you have one blueprint, but you can have several different instances of cars. The blueprint and the car are different things.
So you make a class that describes what an instance of that class can do and what properties it should have. Then you "build" the instance and get an object that you can work with.
It's fairly simple actually. You know how in python they say "everything is an object". Well in simplistic terms you can think of any object as being an 'instance' and the instructions to create an object as the class. Or in biological terms DNA is the class and you are an instance of DNA.
class HumanDNA(): # class
... class attributes ...
you = HumanDNA() # instance
See http://homepage.mac.com/s_lott/books/python/htmlchunks/ch21.html
Object-oriented programming permits us
to organize our programs around the
interactions of objects. A class
provides the definition of the
structure and behavior of the objects;
each object is an instance of a class.
Objects ("instances") are things which interact, do work, persist in the file system, etc.
Classes are the definitions for the object's behavior.
Also, a class creates new objects that are members of that class (share common structure and behavior)
In part it is confusing due to the dynamically typed nature of Python, which allows you to operate on a class and an instance in essentially the same way. In other languages, the difference is more concrete in that a class provides a template by which to create an object (instance) and cannot be as directly manipulated as in Python. The benefit of operating on the instance rather than the class is that the class can provide a prototype upon which instances are created.

Categories