Explain this class,subclass,exception code, please - python

class AndTrigger(Trigger):
def __init__(self,object1,object2):
self.object1 = object1
self.object2 = object2
def evaluate(self,object):
return self.object1.evaluate(self) and self.object2.evaluate(self)
I implemented this AND trigger and it works as it is supposed to, but I was only able to make it work by trial and error--I have no idea what 'self' is doing in this class.
Here's what I think is going on: the __init__ is the constructor for the class, so any instance of the class uses this when created. The class has two attributes (object1, object2), the __init__ when the class is created tells the new instance that these new attributes will be called 'object1' and 'object2' so they are assigned to self.object1 etc.
Now, this evaluate function is supposed to prevent a raise notimplemented in Trigger, but that's not what I don't get. In this evaluate function, it looks like it has two arguments--the instance of AndTrigger and another object. But where is this other object in the definition of evaluate()? It's just a puzzle to me how this works, but it does!

When you're calling a bound member function, the first argument (self) is supplied automatically. It refers to the object on which the function is invoked.
Let's for the sake of illustration assume that both self.object1 and self.object2 are of type TriggerX. The following:
def evaluate(self, obj):
return self.object1.evaluate(self) and self.object2.evaluate(self)
is then equivalent to:
def evaluate(self, obj):
return TriggerX.evaluate(self.object1, self) and TriggerX.evaluate(self.object2, self)
I hope this clears things up.
P.S. I suspect from the context that the following:
def evaluate(self, obj):
return self.object1.evaluate(self) and self.object2.evaluate(self)
should be
def evaluate(self, obj):
return self.object1.evaluate(obj) and self.object2.evaluate(obj)
P.P.S. Please don't use object as a variable name, since this shadows a built-in class.

Related

What's the difference between calling a class decorator on a class instance and on a class definition?

class Deco:
def __init__(self, name):
self.name = name
def __call__(self, test_class):
def inner_func(whatisit):
return whatisit
test_class.method = inner_func
return test_class
class TestClass:
def __init__(self, name):
self.name = name
#Deco('deco')
class TestClassWrapped:
def __init__(self, name):
self.name = name
test = TestClass('test')
test = Deco('deco')(test)
test_wrapped = TestClassWrapped('test')
print(test.method('whatisit')) >> whatisist
print(test_wrapped == test_wrapped.method()) >> True
Why do test.method and test_wrapped.method return different results ?
It seems that the first argument in test_wrapped.method is self, while it isn't for test.method. Why does it differ from one to the other?
The difference isn't how the decoration works, but how calling works. When an instance calls a method defined on its class, as test_wrapped does, it always passes self as the first argument. Meanwhile, when an object calls an attribute of itself that happens to be a function, but doesn't exist on its class, it calls it without passing self. Consider this simple class:
class LoudTalker:
def __init__(self, name):
self.shout_hello = lambda: print("HELLO, I'M {}".format(name.upper()))
>>> john = LoudTalker("John")
>>> LoudTalker.shout_hello()
HELLO, I'M JOHN
Note that john did not pass self to shout_hello (which would have thrown the error <lambda>() takes 0 positional arguments but 1 was given) because shout_hello was defined directly on the instance, not on the class.
Walking through your code step-by-step:
You create a regular TestClass named test.
You manually call Deco and provide it with test, with the line test = Deco('deco')(test).
This makes your code go through the __call__ function, which modifies the passed class test to set its method attribute to the nested function. It then returns it, and so test now contains a successfully modified TestClass : calling test.method('whatisit') will successfully return 'whatisit'. Importantly, you're NOT accessing a method here : you're accessing a FUNCTION through an ATTRIBUTE. self is passed to every method of classes in Python, but since this isn't a method, it doesn't come into play here. Try printing type(test.method), you'll see <class 'function'> and not <class 'method'>. Importantly, you've passed an INSTANCE of a TestClass, not the class definition itself : and only this instance named test has had its method attribute set.
You then create a TestClassWrapped named test_wrapped. Upon creating it, it enters the __call__ once more, passing it TestWrappedClass as the test_class parameter. Importantly, you've passed a DEFINITION of the TestWrappedClass, not an instance of it. Setting method here will modify it for every instance of TestWrappedClass you'll later create, and can even be accessed without instantiating anything. Try calling TestClassWrapped.method("abc") : it will print abc without instantiating a TestClassWrapped at all. Interestingly, when set in this way, it's not set as an attribute but as a method! Try printing type(test_wrapped.method). This is what I believe to be the source of confusion.
In the case of print(test_wrapped.method()), you have to remember that every method of instantiated classes take self as their first parameter. This means that test_wrapped.method() will return self : hence why test_wrapped == test_wrapped.method(). Note that this doesn't apply to methods called from a class definition, like I've shown earlier. TestClassWrapped.method("abc") HAS to take a parameter of some sort (like abc), else it will complain it's lacking an argument.
So this is why test.method('whatisit') returns 'whatisit' and doesn't take self as parameter, and why test_wrapped.method() does return self.

Function to behave differently on class vs on instance

I'd like a particular function to be callable as a classmethod, and to behave differently when it's called on an instance.
For example, if I have a class Thing, I want Thing.get_other_thing() to work, but also thing = Thing(); thing.get_other_thing() to behave differently.
I think overwriting the get_other_thing method on initialization should work (see below), but that seems a bit hacky. Is there a better way?
class Thing:
def __init__(self):
self.get_other_thing = self._get_other_thing_inst()
#classmethod
def get_other_thing(cls):
# do something...
def _get_other_thing_inst(self):
# do something else
Great question! What you seek can be easily done using descriptors.
Descriptors are Python objects which implement the descriptor protocol, usually starting with __get__().
They exist, mostly, to be set as a class attribute on different classes. Upon accessing them, their __get__() method is called, with the instance and owner class passed in.
class DifferentFunc:
"""Deploys a different function accroding to attribute access
I am a descriptor.
"""
def __init__(self, clsfunc, instfunc):
# Set our functions
self.clsfunc = clsfunc
self.instfunc = instfunc
def __get__(self, inst, owner):
# Accessed from class
if inst is None:
return self.clsfunc.__get__(None, owner)
# Accessed from instance
return self.instfunc.__get__(inst, owner)
class Test:
#classmethod
def _get_other_thing(cls):
print("Accessed through class")
def _get_other_thing_inst(inst):
print("Accessed through instance")
get_other_thing = DifferentFunc(_get_other_thing,
_get_other_thing_inst)
And now for the result:
>>> Test.get_other_thing()
Accessed through class
>>> Test().get_other_thing()
Accessed through instance
That was easy!
By the way, did you notice me using __get__ on the class and instance function? Guess what? Functions are also descriptors, and that's the way they work!
>>> def func(self):
... pass
...
>>> func.__get__(object(), object)
<bound method func of <object object at 0x000000000046E100>>
Upon accessing a function attribute, it's __get__ is called, and that's how you get function binding.
For more information, I highly suggest reading the Python manual and the "How-To" linked above. Descriptors are one of Python's most powerful features and are barely even known.
Why not set the function on instantiation?
Or Why not set self.func = self._func inside __init__?
Setting the function on instantiation comes with quite a few problems:
self.func = self._funccauses a circular reference. The instance is stored inside the function object returned by self._func. This on the other hand is stored upon the instance during the assignment. The end result is that the instance references itself and will clean up in a much slower and heavier manner.
Other code interacting with your class might attempt to take the function straight out of the class, and use __get__(), which is the usual expected method, to bind it. They will receive the wrong function.
Will not work with __slots__.
Although with descriptors you need to understand the mechanism, setting it on __init__ isn't as clean and requires setting multiple functions on __init__.
Takes more memory. Instead of storing one single function, you store a bound function for each and every instance.
Will not work with properties.
There are many more that I didn't add as the list goes on and on.
Here is a bit hacky solution:
class Thing(object):
#staticmethod
def get_other_thing():
return 1
def __getattribute__(self, name):
if name == 'get_other_thing':
return lambda: 2
return super(Thing, self).__getattribute__(name)
print Thing.get_other_thing() # 1
print Thing().get_other_thing() # 2
If we are on class, staticmethod is executed. If we are on instance, __getattribute__ is first to be executed, so we can return not Thing.get_other_thing but some other function (lambda in my case)

Python: How to call the constructor from within member function

This Question / Answer (Python call constructor in a member function) says it is possible to to call the constructor from within a member function.
How do I do that?
Is it good a style?
I tried it with the following code:
class SomeClass(object):
def __init__(self, field):
self.field = field
def build_new(self):
self = SomeClass(True)
def main():
inst = SomeClass(False)
inst.build_new()
print(inst.field)
if __name__ == '__main__':
main()
As output I get: False
Since I called the build_new() method inst.field should be True or not?
The problem is not in calling the constructor, but what you're doing with the result. self is just a local variable: assigning to it won't change anything at all about the current instance, it will just rebind the name to point to a new instance which is then discarded at the end of the method.
I'm not totally certain what you are trying to do, but perhaps you want a classmethod?
class SomeClass(object):
...
#classmethod
def build_new(cls):
return cls(True)
SomeClass.build_new(False)
I believe what you are looking for is just calling the init function again.
class SomeClass(object):
def __init__(self, field):
self.field = field
def build_new(self):
self.__init__(True)
This will cause the field variable to be set to True over False. Basically, you are re-initializing the instance rather than creating a brand new one.
Your current code creates a new instance and just loses the reference to it when it goes out of scope (i.e. the function returning) because you are just rebinding the name of self to a different value not actually changing the inner contents of self.

Python: make every instance have a different superclass

In Python, I currently have instances of a class like MyClass('name1'), MyClass('name2') and so on.
I want to make it so that each instance has its own superclass, i.e., I want MyClass('name1') to be an instance of Name1MyClass and MyClass('name2') to be an instance of Name2MyClass. Name1MyClass and Name2MyClass would be dynamically generated subclasses of MyClass. I can't figure out how to do this, because it seems that Python always makes whatever is returned from __new__ an instance of that class. It isn't clear to me how to do it in a metaclass either.
The reason I want to do this is that I want to define __doc__ docstrings on the instances. But it seems that help completely ignores __doc__ on instances; it only looks on classes. So to put a different docstring on each instance, I need to make each instance have its own custom class.
I could be wrong, but I don't think you want a metaclass here. __metaclass__es are used when the class is created, not when you call the class to construct a new instance of the class (or something else).
Here's an answer using __new__ without a metaclass. It feels a bit hacky, but it seems to work:
_sentinel = Ellipsis
class MyClass(object):
def __new__(cls, name):
if name is _sentinel:
return object.__new__(cls)
else:
instance = type(name + cls.__name__, (MyClass,), {})(_sentinel)
# Initialization goes here.
return instance
print type(MyClass('name1'))
print type(MyClass('name2'))
There's a catch here -- All the business logic of initializing then new instance must be done in __new__. Since __new__ is returning a different type than the class it is bound to, __init__ won't get called.
Another option is to create a class factory:
class MyClass(object):
pass
def class_factory(name):
new_cls = type(name + MyClass.__name__, (MyClass,), {})
return new_cls() # Or pass whatever you want in here...
print type(class_factory('name1'))
print type(class_factory('name2'))
Finally, you could even create a non-__new__ class method:
class MyClass(object):
#classmethod
def class_factory(cls, name):
new_cls = type(name + cls.__name__, (cls,), {})
return new_cls() # Or pass whatever you want in here...
print type(MyClass.class_factory('name1'))
print type(MyClass.class_factory('name2'))

Call a function inside a class when calling the class in python

This simple example is what I dont get to work or understand in my more complex script:
class printclass():
string="yes"
def dotheprint(self):
print self.string
dotheprint(self)
printclass()
When the class is called, I expected it to run the function, but instead it will tell me that "self is not defined". Im aware this happens on the line:
dotheprint(self)
But I dont understand why. What should I change for the class to run the function with the data it already has within? (string)
You misunderstand how classes work. You put your call inside the class definition body; there is no instance at that time, there is no self.
Call the method on the instance:
instance = printclass()
instance.dotheprint()
Now the dotheprint() method is bound, there is an instance for self to refer to.
If you need dotheprint() to be called when you create an instance, give the class an __init__ method. This method (the initializer) is called whenever you create an instance:
class printclass():
string="yes"
def __init__(self):
self.dotheprint()
def dotheprint(self):
print self.string
printclass()
You really need to understand Object-Oriented Programming and its implementation in Python.
You cannot "call" a class like any function. You have to create an instance, which has a lifetime and methods linked to it :
o = printclass() # new object printclass
o.dotheprint() #
A better implementation of your class
class printclass():
string="yes" #beware, this is instance-independant (except if modified later on)
def dotheprint(self):
print self.string
def __init__(self): # it's an initializer, a method called right after the constructor
self.dotheprint()

Categories