Questions related to classes - python

I have a problem understanding some concepts of data structures in Python, in the following code.
class Stack(object): #1
def __init__(self): #2
self.items=[]
def isEmpty(self):
return self.items ==[]
def push(self,item):
self.items.append(item)
def pop(self):
self.items.pop()
def peak(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
s = Stack()
s.push(3)
s.push(7)
print(s.peak())
print (s.size())
s.pop()
print (s.size())
print (s.isEmpty())
I don't understand what is this object argument
I replaced it with (obj) and it generated an error, why?
I tried to remove it and it worked perfectly, why?
Why do I have __init__ to set a constructor?
self is an argument, but how does it get passed? and which object does it represent, the class it self?
Thanks.

object is a class, from which class Stack inherits. There is no
class obj, hence error. However, you can define a class that does
not inherit from anything (at least, in Python 2).
self represents an object on which the method is called; for
example when you do s.pop(), self inside method pop refers to
the same object as s - it is not a class, it is an instance of the class.

1
object here is the class your new class inherits from. There is already a base class named object, but there is no class named obj which is why replacing object with obj would cause an error. Anyway in your example code it is not needed at all since all classes in python 3 implicitly extends the object class.
2
__init__ is the constructor of the object and self there represents the object that you are creating itself, not the class, just like in the other methods you made.

Point 1:
Some history required here... Originally Python had two distinct kind of types, those implemented in C (whether in the stdlib or C extensions) and those implemented in Python with the class statement. Python 2.2 introduced a new object model (known as "new-style classes") to unify both, but kept the "classic" (aka "old-style") model for compatibility. This new model also introduced quite a lot of goodies like support for computed attributes, cooperative super calls via the super() object, metaclasses etc, all of which coming from the builtin object base class.
So in Python 2.2.x to 2.7.x, you can either create a new-style class by inheriting from object (or any subclass of object) or an old-style one by not inheriting from object (nor - obviously - any subclass of object).
In Python 2.7., since your example Stack class does not use any feature of the new object model, it works as well as an 'old-style' or as a 'new-style' class, but try to add a custom metaclass or a computed attribute and it will break in one way or another.
Python 3 totally removed old-style classes support and object is the defaut base class if you dont explicitely specify one, so whatever you do your class WILL inherit from object and will work as well with or without explicit parent class.
You can read this for more details.
Point 2.1 - I'm not sure I understand the question actually, but anyway:
In Python, objects are not fixed C-struct-like structures with a fixed set of attributes, but dict-like mappings (well there are exceptions but let's ignore them for the moment). The set of attributes of an object is composed of the class attributes (methods mainly but really any name defined at the class level) that are shared between all instances of the class, and instance attributes (belonging to a single instance) which are stored in the instance's __dict__. This imply that you dont define the instance attributes set at the class level (like in Java or C++ etc), but set them on the instance itself.
The __init__ method is there so you can make sure each instance is initialised with the desired set of attributes. It's kind of an equivalent of a Java constructor, but instead of being only used to pass arguments at instanciation, it's also responsible for defining the set of instance attributes for your class (which you would, in Java, define at the class level).
Point 2.2 : self is the current instance of the class (the instance on which the method is called), so if s is an instance of your Stack class, s.push(42) is equivalent to Stack.push(s, 42).
Note that the argument doesn't have to be called self (which is only a convention, albeit a very strong one), the important part is that it's the first argument.
How s get passed as self when calling s.push(42) is a bit intricate at first but an interesting example of how to use a small feature set to build a larger one. You can find a detailed explanation of the whole mechanism here, so I wont bother reposting it here.

Related

How to decorate a python class and override a method?

I have a class
class A:
def sample_method():
I would like to decorate class A sample_method() and override the contents of sample_method()
class DecoratedA(A):
def sample_method():
The setup above resembles inheritance, but I need to keep the preexisting instance of class A when the decorated function is used.
a # preexisting instance of class A
decorated_a = DecoratedA(a)
decorated_a.functionInClassA() #functions in Class A called as usual with preexisting instance
decorated_a.sample_method() #should call the overwritten sample_method() defined in DecoratedA
What is the proper way to go about this?
There isn't a straightforward way to do what you're asking. Generally, after an instance has been created, it's too late to mess with the methods its class defines.
There are two options you have, as far as I see it. Either you create a wrapper or proxy object for your pre-existing instance, or you modify the instance to change its behavior.
A proxy defers most behavior to the object itself, while only adding (or overriding) some limited behavior of its own:
class Proxy:
def __init__(self, obj):
self.obj = obj
def overridden_method(self): # add your own limited behavior for a few things
do_stuff()
def __getattr__(self, name): # and hand everything else off to the other object
return getattr(self.obj, name)
__getattr__ isn't perfect here, it can only work for regular methods, not special __dunder__ methods that are often looked up directly in the class itself. If you want your proxy to match all possible behavior, you probably need to add things like __add__ and __getitem__, but that might not be necessary in your specific situation (it depends on what A does).
As for changing the behavior of the existing object, one approach is to write your subclass, and then change the existing object's class to be the subclass. This is a little sketchy, since you won't have ever initialized the object as the new class, but it might work if you're only modifying method behavior.
class ModifiedA(A):
def overridden_method(self): # do the override in a normal subclass
do_stuff()
def modify_obj(obj): # then change an existing object's type in place!
obj.__class__ = ModifiedA # this is not terribly safe, but it can work
You could also consider adding an instance variable that would shadow the method you want to override, rather than modifying __class__. Writing the function could be a little tricky, since it won't get bound to the object automatically when called (that only happens for functions that are attributes of a class, not attributes of an instance), but you could probably do the binding yourself (with partial or lambda if you need to access self.
First, why not just define it from the beginning, how you want it, instead of decorating it?
Second, why not decorate the method itself?
To answer the question:
You can reassign it
class A:
def sample_method(): ...
pass
A.sample_method = DecoratedA.sample_method;
but that affects every instance.
Another solution is to reassign the method for just one object.
import functools;
a.sample_method = functools.partial(DecoratedA.sample_method, a);
Another solution is to (temporarily) change the type of an existing object.
a = A();
a.__class__ = DecoratedA;
a.sample_method();
a.__class__ = A;

Getting private attribute in parent class using super(), outside of a method

I have a class with a private constant _BAR = object().
In a child class, outside of a method (no access to self), I want to refer to _BAR.
Here is a contrived example:
class Foo:
_BAR = object()
def __init__(self, bar: object = _BAR):
...
class DFoo(Foo):
"""Child class where I want to access private class variable from parent."""
def __init__(self, baz: object = super()._BAR):
super().__init__(baz)
Unfortunately, this doesn't work. One gets an error: RuntimeError: super(): no arguments
Is there a way to use super outside of a method to get a parent class attribute?
The workaround is to use Foo._BAR, I am wondering though if one can use super to solve this problem.
Inside of DFoo, you cannot refer to Foo._BAR without referring to Foo. Python variables are searched in the local, enclosing, global and built-in scopes (and in this order, it is the so called LEGB rule) and _BAR is not present in any of them.
Let's ignore an explicit Foo._BAR.
Further, it gets inherited: DFoo._BAR will be looked up first in DFoo, and when not found, in Foo.
What other means are there to get the Foo reference? Foo is a base class of DFoo. Can we use this relationship? Yes and no. Yes at execution time and no at definition time.
The problem is when the DFoo is being defined, it does not exist yet. We have no start point to start following the inheritance chain. This rules out an indirect reference (DFoo -> Foo) in a def method(self, ....): line and in a class attribute _DBAR = _BAR.
It is possible to work around this limitation using a class decorator. Define the class and then modify it:
def deco(cls):
cls._BAR = cls.__mro__[1]._BAR * 2 # __mro__[0] is the class itself
return cls
class Foo:
_BAR = 10
#deco
class DFoo(Foo):
pass
print(Foo._BAR, DFoo._BAR) # 10 20
Similar effect can be achieved with a metaclass.
The last option to get a reference to Foo is at execution time. We have the object self, its type is DFoo, and its parent type is Foo and there exists the _BAR. The well known super() is a shortcut to get the parent.
I have assumed only one base class for simplicity. If there were several base classes, super() returns only one of them. The example class decorator does the same. To understand how several bases are sorted to a sequence, see how the MRO works (Method Resolution Order).
My final thought is that I could not think up a use-case where such access as in the question would be required.
Short answer: you can't !
I'm not going into much details about super class itself here. (I've written a pure Python implementation in this gist if you like to read.)
But now let's see how we can call super:
1- Without arguments:
From PEP 3135:
This PEP proposes syntactic sugar for use of the super type to
automatically construct instances of the super type binding to the
class that a method was defined in, and the instance (or class object
for classmethods) that the method is currently acting upon.
The new syntax:
super()
is equivalent to:
super(__class__, <firstarg>)
...and <firstarg> is the first parameter of the method
So this is not an option because you don't have access to the "instance".
(Body of the function/methods is not executed unless it gets called, so no problem if DFoo doesn't exist yet inside the method definition)
2- super(type, instance)
From documentation:
The zero argument form only works inside a class definition, as the
compiler fills in the necessary details to correctly retrieve the
class being defined, as well as accessing the current instance for
ordinary methods.
What were those necessary details mentioned above? A "type" and A "instance":
We can't pass neither "instance" nor "type" which is DFoo here. The first one is because it's not inside the method so we don't have access to instance(self). Second one is DFoo itself. By the time the body of the DFoo class is being executed there is no reference to DFoo, it doesn't exist yet. The body of the class is executed inside a namespace which is a dictionary. After that a new instance of type type which is here named DFoo is created using that populated dictionary and added to the global namespaces. That's what class keyword roughly does in its simple form.
3- super(type, type):
If the second argument is a type, issubclass(type2, type) must be
true
Same reason mentioned in above about accessing the DFoo.
4- super(type):
If the second argument is omitted, the super object returned is
unbound.
If you have an unbound super object you can't do lookup(unless for the super object's attributes itself). Remember super() object is a descriptor. You can turn an unbound object to a bound object by calling __get__ and passing the instance:
class A:
a = 1
class B(A):
pass
class C(B):
sup = super(B)
try:
sup.a
except AttributeError as e:
print(e) # 'super' object has no attribute 'a'
obj = C()
print(obj.sup.a) # 1
obj.sup automatically calls the __get__.
And again same reason about accessing DFoo type mentioned above, nothing changed. Just added for records. These are the ways how we can call super.

What is the functionality difference between the Reference of a class and its object/instance in python while calling its objects?

I was searching for the meaning of default parameters object,self that are present as default class and function parameters, so moving away from it, if we are calling an attribute of a class should we use Foo (class reference) or should we use Foo() (instance of the class).
If you are reading a normal attribute then it doesn't matter. If you are binding a normal attribute then you must use the correct one in order for the code to work. If you are accessing a descriptor then you must use an instance.
The details of python's class semantics are quite well documented in the data model. Especially the __get__ semantics are at work here. Instances basically stack their namespace on top of their class' namespace and add some boilerplate for calling methods.
There are some large "it depends on what you are doing" gotchas at work here. The most important question: do you want to access class or instance attributes? Second, do you want attribute or methods?
Let's take this example:
class Foo(object):
bar = 1
baz = 2
def __init__(self, foobar="barfoo", baz=3):
self.foobar = foobar
self.baz = baz
def meth(self, param):
print self, param
#classmethod
def clsmeth(cls, param):
print cls, param
#staticmethod
def stcmeth(param):
print param
Here, bar is a class attribute, so you can get it via Foo.bar. Since instances have implicit access to their class namespace, you can also get it as Foo().bar. foobar is an instance attribute, since it is never bound to the class (only instances, i.e. selfs) - you can only get it as Foo().foobar. Last, baz is both a class and an instance attribute. By default, Foo.baz == 2 and Foo().baz == 3, since the class attribute is hidden by the instance attribute set in __init__.
Similarly, in an assignment there are slight differences whether you work on the class or an instance. Foo.bar=2 will set the class attribute (also for all instances) while Foo().bar=2 will create an instance attribute that shadows the class attribute for this specific instance.
For methods, it is somewhat similar. However, here you get the implicit self parameter for instance method (what a function is if defined for a class). Basically, the call Foo().meth(param=x) is silently translated to Foo.meth(self=Foo(), param=x). This is why it is usually not valid to call Foo.meth(param=x) - meth is not "bound" to an instance and thus lacks the self parameter.
Now, sometimes you do not need any instance data in a method - for example, you have strict string transformation that is an implementation detail of a larger parser class. This is where #classmethod and #staticmethod come into play. A classmethod's first parameter is always the class, as opposed to the instance for regular methods. Foo().clsmeth(param=x) and Foo.clsmeth(param=x) result in a call of clsmethod(cls=Foo, param=x). Here, the two are equivalent. Going one step further, a staticmethod doesn't get any class or instance information - it is like a raw function bound to the classes namespace.

What' the meaning of the brackets in the class?

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.

Python rookie: Headaches with Object Oriented Programming

What is the difference between these two class declarations? What does "object" do?
class className(object):
pass
class className:
pass
Why do I get this error when I run the below code: "Takes no arguments (1 given)"
class Hobbs():
def represent():
print "Hobbs represent!"
represent = classmethod(represent)
Hobbs.represent()
Why does "Foo.class_foo()" give no error even though I did not pass an argument to the function.
class Foo(object):
#staticmethod
def static_foo():
print "static method"
#classmethod
def class_foo(cls):
print "Class method. Automatically passed the class: %s" % cls
Foo.static_foo()
Foo.class_foo()
Why do I get this error when I run the below code?
class Foo(object):
def static_foo():
print "static method"
static_foo = staticmethod(static_foo)
def class_foo(cls):
print "Class method. Automatically passed the class: %s" % cls
class_foo = classmethod(class_foo)
Foo.static_foo()
Foo.class_foo()
"TypeError: unbound method static_foo() must be called with Foo
instance as first argument (got nothing instead)"
Using object as the base class for new classes has been convention since at least Python 2.2, and is called "New-Style Classes" - see this question for more details. Old style classes (i.e.: ones that don't inherit from object) are set to be deprecated in Python 3.0. The reasons for these changes are somewhat obscure, and have to do with low-level class resolution and inheritance patterns.
Python instance methods, by convention, take self as their first argument. This argument is passed implicitly - so if your method definition doesn't take self, then the interpreter will complain that the method you're trying to call doesn't accept the argument that's being automatically passed to it. This works exactly the same for classmethods, only instead of taking self, they usually take cls. (Just a naming convention.) A quick fix:
class Hobbs():
def represent(cls):
print "Hobbs represent!"
represent = classmethod(represent)
Hobbs.represent()
Calling Foo.class_foo() doesn't cause any issues, as Python automatically passes the class object to the class_foo method whenever you call it. These methods are called bound methods - meaning that they are regular functions, but bound to a class or instance object. Bound methods automatically take the class or instance object that they're bound to as their first argument.
Indentation level matters in Python. I've tried executing the code sample you've provided, but both the static_foo = and class_foo = lines must be within the Foo class definition, rather than below it or within other methods. When indented properly, the code runs fine:
class Foo(object):
def static_foo():
print "static method"
static_foo = staticmethod(static_foo)
def class_foo(cls):
print "Class method. Automatically passed the class: %s" % cls
class_foo = classmethod(class_foo)
Foo.static_foo()
Foo.class_foo()
The last two are identical - empty brackets is the same as omitting them. The first inherits from the builtin class object, making it a "new style class". The reason for new and old style classes is historical, and old-style are only kept around for backward compatibility - essentially, in Python 2, the advice is to always inherit from object if you don't inherit from anything else, because some of the fancy tricks you will learn eventually rely on it. If you upgrade to Python 3, this becomes the default behaviour, and all three class declarations are equivalent.
A classmethod needs to take a first argument similar to self - when you call Hobbs.represent(), Python end up passing Hobbs in as that first argument. This is the fundamental difference between classmethod and staticmethod - a classmethod takes a first argument (being the class it was called on), a staticmethod doesn't.
Same as 2 - class is passed in to the classmethod in place of the usual self.
This one appears to be an indentation issue - your code works as written if it is indented as:
def static_foo():
print "static method"
static_foo = staticmethod(staticfoo)
but not as
def static_foo():
print "static method"
static_foo = staticmethod(staticfoo)
Because the line reassigning static_foo needs to be in the class body, not part of the function itself. In the latter, that line isn't executed until the function is run (which means it isn't run, since the function errors) - and it assigns a staticmethod to a local variable rather than to the method itself. This type of error is one of the reasons it is good to use the decorator syntax:
class Hobbs:
#staticmethod
def static_foo():
print "static method"
works.
all class functions must take self as the first argument
class A:
def my_func(self):
print "In my func"
static methods are classes that are pretty much just a function in a namespace (and are rarely used in python)
class methods are functions in the class namespace that should be called on the class itself rather than an instance
Most of your questions aren't really about object orientation per se, but Python's specific implementation of it.
Python 2.x has undergone some evolution, with new features being added. So there are two ways to define classes, resulting in a "new-style class", and and "old-style class". Python 3.x has only "new style class".
The base object of new-style classes is called object. If you inherit from that you have a new-style class. It gives you some of the extra features such as certain decorators. If you have a bare (no inheritance) definition in Python 2.x you have an old-style class. This exists for backwards compatibility. In Python 3.x you will also get a new-style class (so inheriting from object is optional there).
You have made represent() and "class method". So it will get the class object as implicit first argument when it is called. But those only work with new-style classes. you have tried to use it with an old-style class. So it won't work.
Python automatically inserts the class object as argument zero for a class method. So that is the correct pattern and it works.
the method somehow didn't get make into a class method, maybe because the indentation is wrong.
class ClassName(OtherClass): means that ClassName inherits from
OtherClass. inheritance is a big subject but basically it means that
ClassName has at least the same functions and fields as OtherClass.
In python, Everything is an object and therefor, all classes inherit
implicitely or explicitely from object. This being said
the class ClassName(): declaration is an old syntax and should be avoided.
class ClassName: is equivalent to class ClassName(object):
A class method is not a static method. It is like any other instance method except it is passed the class as parameter rather than the instance.
Your class method declaration is wrong. It should have a cls parameter.
A static method in the other hand, is a method that is called out of context. Meaning it has no relation with any instance. It can be thought of as a independent function that is simply put in a class for semantic reasons.
This is why it does not require a self parameter and one is never passed to it.
You have an indentation error. That might be causing the error.

Categories