A class is more or less a fancy wrapper for a dict of attributes to objects. When you instantiate a class you can assign to its attributes, and those will be stored in foo.__dict__; likewise, you can look in foo.__dict__ for any attributes you have already written.
This means you can do some neat dynamic things like:
class Employee: pass
def foo(self): pass
Employee.foo = foo
as well as assigning to a particular instance. (EDIT: added self parameter)
A class is more or less a fancy wrapper for a dict of attributes to objects. When you instantiate a class you can assign to its attributes, and those will be stored in foo.__dict__; likewise, you can look in foo.__dict__ for any attributes you have already written.
This means you can do some neat dynamic things like:
class Employee: pass
def foo(self): pass
Employee.foo = foo
as well as assigning to a particular instance. (EDIT: added self parameter)
Try with lambda:
john.greet = lambda : print( 'hello world!' )
The you'll be able to do:
john.greet()
EDIT: Thanks Thomas K for the note - this works on Python 3.2 and not for Python2, where print appeared to be statement. But this will work for lambdas, without statements (right? Sorry, I know only python3.2 (: )
Videos
When you create a new class, you are creating a new type. This newly created type may have some properties, or may not. These properties allow to hold data, methods etc.
Empty class that doesn't inherit any base class would be useful as placeholder.
class ServiceWrapper(object):
pass
def sendMessage(svc:ServiceWrapper):
#do something
#pass
On the other hand, empty classes that inherit other classes is a very common pattern. Specially when defining user exceptions.
class Networkerror(RuntimeError):
pass
try:
raise Networkerror()
except Networkerror:
#do something
#pass
Also recently, the python collections.abc allows creating interface like functionalities.
class ServiceWrapper(ABC):
@abstractmethod
def send(self):...
def sendMessage(svc:ServiceWrapper):
svc.send()
#pass
I recently found myself using empty Python classes as unique "tags" for an observer system.
For example, something like this...
from collections import defaultdict
class OnCreate:
pass
class OnModify:
pass
class OnDelete:
pass
class ObserverSystem:
def __init__(self):
self.observers = defaultdict(list)
def register(self, event, callback):
self.observers[event].append(callback)
def notify(self, event, *args, **kwargs):
for callback in self.observers[event]:
callback(*args, **kwargs)
observer = ObserverSystem()
observer.register(OnCreate, lambda entity: print(f"Entity {entity} created"))
observer.register(OnModify, lambda entity: print(f"Entity {entity} modified"))
observer.register(OnDelete, lambda entity: print(f"Entity {entity} deleted"))
observer.notify(OnCreate, 1)
observer.notify(OnModify, 2)
observer.notify(OnDelete, 3)
I guess, I could have used a of numeric value, or even a string as the "tag", but the class is unique, it's hashable so I can use it as dict key, etc. Seems to work well.
This is just fine:
class Parent:
# the __init__ is inherited from parent
pass
class Child(Parent):
# the __init__ is inherited from parent
pass
This is also fine:
class Parent:
# the __init__ is inherited from parent
pass
class Child(Parent):
def __init__(self):
# __init__ is called on parent
super().__init__()
This may seem ok, and will usually work fine, but not always:
class Parent:
# the __init__ is inherited from parent
pass
class Child(Parent):
def __init__(self):
# this does not call parent's __init__,
pass
Here is one example where it goes wrong:
class Parent2:
def __init__(self):
super().__init__()
print('Parent2 initialized')
class Child2(Child, Parent2):
pass
# you'd expect this to call Parent2.__init__, but it won't:
Child2()
This is because the MRO of Child2 is: Child2 -> Child -> Parent -> Parent2 -> object.
Child2.__init__ is inherited from Child and that one does not call Parent2.__init__, because of the missing call to super().__init__.
No it isn't necessary. It is necessary when you want the parent's logic to run as well.
class Parent:
def __init__(self):
self.some_field = 'value'
class Child(Parent):
def __init__(self):
self.other_field = 'other_value'
super().__init__()
child = Child()
child.some_field # 'value'
Note: This post contains two different implementation techniques to allow for what you want.
Solution Through Indirection
The easiest way around this issue is to refactor the code so that the child classes does not directly override the function used by the public interface.
Instead provide the public functionality directly in the base-class, and make children override a "worker" (implementation detail) of said function that is later called by the function invoked "from the outside".
Example Implementation
class Base (object):
def get_message (self):
try:
return self.get_message_impl ()
except Exception as detail:
print ("error:", detail)
return None
def get_message_impl (self):
raise Exception ("Not Implemented")
class Foo (Base):
def get_message_impl (self):
return "Hello World";
class Bar (Base):
def get_message_impl (self):
raise Exception ("Bar.get_message_impl always fails!")
f = Foo ()
b = Bar ()
f_msg = f.get_message ()
b_msg = b.get_message ()
print ("f_msg:", f_msg)
print ("b_msg:", b_msg)
output
error: Bar.get_message_impl always fails!
f_msg: Hello World
b_msg: None
opt-in protection
If you would like to maintain the possibility to override the public functionality presented in the base class, while still being able to easily call a "protected" version of the functions at a later time, you could create a simply wrapper such as the below:
class Base (object):
class Protected (object):
def __init__ (self, target):
self.target = target
def get_message (self):
try:
return self.target.get_message ()
except Exception as detail:
print ("error:", detail)
return None
def __init__ (self):
self.protected = self.Protected (self)
def get_message (self):
raise Exception ("Not Implemented")
class Foo (Base):
def get_message (self):
return "Hello World";
class Bar (Base):
def get_message (self):
raise Exception ("Bar.get_message_impl always fail!")
f = Foo ()
b = Bar ()
f_msg = f.protected.get_message () # protected from failure
b_msg = b.protected.get_message () # protected from failure
b_msg = b.get_message () # will raise exception
NotImplementedError is an exception; don't return it, raise it as an exception:
class Crawler():
def get_image_source_url(self, image_page_soup):
raise NotImplementedError("method get_image_source_url must be implemented")
def get_image_thumbnail_url(self, image_page_soup):
raise NotImplementedError("method get_image_thumbnail_url must be implemented")
def get_tags_container(self, image_page_soup):
raise NotImplementedError("method get_tags_container must be implemented")
You don't need to 'wrap' anything here. If the subclass implements the method, the original method won't be called an no exception is raised.
If further processing is needed, and the subclass implementation is optional but should not be visible to the outside API, you could require subclasses to implement a method by a different name, called from the base class method:
class Crawler():
def _image_source_url_implementation(self, image_page_soup):
raise NotImplementedError("method get_image_source_url must be implemented")
def get_image_source_url(self, image_page_soup):
try:
url = self._image_source_url_implementation(image_page_soup)
except NotImplementedError:
# do something default
url = 'something else'
# process the produced URL further
return processed_result
Here self.get_image_source_url() delegates to an optional self._image_source_url_implementation() method.
It sounds like you want a class factory:
def make_baked_type(fruit, bake):
class baked_item(fruit, bake):
pass
return baked_item
ApplePie = make_baked_type(Apple, Pie)
item = ApplePie()
print(item.flavour())
# or
def make_baked_item(fruit, bake):
return make_baked_type(fruit, bake)()
item = make_baked_item(Apple, Pie)
print(item.flavour())
One possible solution that I don't particularly like is having the individual classes as a properties in a class
class BakedFruitItem:
fruit: Fruit
baked_item: BakedItem
Yes, in Python 3.3 SimpleNamespace was added
Unlike object, with SimpleNamespace you can add and remove attributes. If a SimpleNamespace object is initialized with keyword arguments, those are directly added to the underlying namespace.
Example:
import types
x = types.SimpleNamespace()
x.happy = True
print(x.happy) # True
del x.happy
print(x.happy) # AttributeError. object has no attribute 'happy'
You can use type to create a new class on the fly and then instantiate it. Like so:
>>> t = type('test', (object,), {})()
>>> t
<__main__.test at 0xb615930c>
The arguments to type are: Class name, a tuple of base classes, and the object's dictionary. Which can contain functions (the object's methods) or attributes.
You can actually shorten the first line to
>>> t = type('test', (), {})()
>>> t.__class__.__bases__
(object,)
Because by default type creates new style classes that inherit from object.
type is used in Python for metaprogramming.
But if you just want to create an instance of object. Then, just create an instance of it. Like lejlot suggests.
Creating an instance of a new class like this has an important difference that may be useful.
>>> a = object()
>>> a.whoops = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'whoops'
Where as:
>>> b = type('', (), {})()
>>> b.this_works = 'cool'
>>>