Python DRY class inititialization [duplicate] - python-3.x

When I define a class, I often want to set a collection of attributes for that class upon object creation. Until now, I have done so by passing the attributes as arguments to the init method. However, I have been unhappy with the repetitive nature of such code:
class Repository(OrderedDict,UserOwnedObject,Describable):
def __init__(self,user,name,gitOriginURI=None,gitCommitHash=None,temporary=False,sourceDir=None):
self.name = name
self.gitOriginURI = gitOriginURI
self.gitCommitHash = gitCommitHash
self.temporary = temporary
self.sourceDir = sourceDir
...
In this example, I have to type name three times, gitOriginURI three times, gitCommitHash three times, temporary three times, and sourceDir three times. Just to set these attributes. This is extremely boring code to write.
I've considered changing classes like this to be along the lines of:
class Foo():
def __init__(self):
self.a = None
self.b = None
self.c = None
And initializing their objects like:
f = Foo()
f.a = whatever
f.b = something_else
f.c = cheese
But from a documentation standpoint, this seems worse, because the user of the class then needs to know which attributes need to be set, rather than simply looking at the autogenerated help() string for the class's initializer.
Are there any better ways to do this?
One thing that I think might be an interesting solution, would be if there was a store_args_to_self() method which would store every argument passed to init as an attribute to self. Does such a method exist?
One thing that makes me pessimistic about this quest for a better way, is that looking at the source code for the date object in cPython's source, for example, I see this same repetitive code:
def __new__(cls, year, month=None, day=None):
...
self._year = year
self._month = month
self._day = day
https://github.com/python/cpython/blob/master/Lib/datetime.py#L705
And urwid, though slightly obfuscated by the use of setters, also has such "take an argument and set it as an attribute to self" hot-potato code:
def __init__(self, caption=u"", edit_text=u"", multiline=False,
align=LEFT, wrap=SPACE, allow_tab=False,
edit_pos=None, layout=None, mask=None):
...
self.__super.__init__("", align, wrap, layout)
self.multiline = multiline
self.allow_tab = allow_tab
self._edit_pos = 0
self.set_caption(caption)
self.set_edit_text(edit_text)
if edit_pos is None:
edit_pos = len(edit_text)
self.set_edit_pos(edit_pos)
self.set_mask(mask)
https://github.com/urwid/urwid/blob/master/urwid/widget.py#L1158

You could use the dataclasses project to have it take care of generating the __init__ method for you; it'll also take care of a representation, hashing and equality testing (and optionally, rich comparisons and immutability):
from dataclasses import dataclass
from typing import Optional
#dataclass
class Repository(OrderedDict, UserOwnedObject, Describable):
name: str
gitOriginURI: Optional[str] = None
gitCommitHash: Optional[str] = None
temporary: bool = False
sourceDir: Optional[str] = None
dataclasses were defined in PEP 557 - Data Classes, which has been accepted for inclusion in Python 3.7. The library will work on Python 3.6 and up (as it relies on the new variable annotation syntax introduced in 3.6).
The project was inspired by the attrs project, which offers some more flexibility and options still, as well as compatibility with Python 2.7 and Python 3.4 and up.

Well, you could do this:
class Foo:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
foo = Foo(a=1, b='two', c='iii')
print(foo.a, foo.b, foo.c)
output
1 two iii
But if you do, it's probably a Good Idea to check that the keys in kwargs are sane before dumping them into your instances __dict__. ;)
Here's a slightly fancier example that does a little bit of checking of the passed-in args.
class Foo:
attrs = ['a', 'b', 'c']
''' Some stuff about a, b, & c '''
def __init__(self, **kwargs):
valid = {key: kwargs.get(key) for key in self.attrs}
self.__dict__.update(valid)
def __repr__(self):
args = ', '.join(['{}={}'.format(key, getattr(self, key)) for key in self.attrs])
return 'Foo({})'.format(args)
foo = Foo(a=1, c='iii', d='four')
print(foo)
output
Foo(a=1, b=None, c=iii)

For Python 2.7 my solution is to inherit from namedtuple and use namedtuple itself as only argument to init. To avoid overloading new every time we can use decorator. The advantage is that we have explicit init signature w/o *args, **kwargs and, so, nice IDE suggestions
def nt_child(c):
def __new__(cls, p): return super(c, cls).__new__(cls, *p)
c.__new__ = staticmethod(__new__)
return c
ClassA_P = namedtuple('ClassA_P', 'a, b, foo, bar')
#nt_child
class ClassA(ClassA_P):
def __init__(self, p):
super(ClassA, self).__init__(*p)
self.something_more = sum(p)
a = ClassA(ClassA_P(1,2,3,4)) # a = ClassA(ClassA_P( <== suggestion a, b, foo, bar
print a.something_more # print a. <== suggesion a, b, foo, bar, something_more

I'll just leave another one recipe here. attrs is useful, but have cons, main of which is lack of IDE suggestions for class __init__.
Also it's fun to have initialization chains, where we use instance of parent class as first arg for __init__ instead of providing all it's attrs one by one.
So I propose the simple decorator. It analyses __init__ signature and automatically adds class attributes, based on it (so approach is opposite to attrs's one). This gave us nice IDE suggestions for __init__ (but lack of suggestions on attributes itself).
Usage:
#data_class
class A:
def __init__(self, foo, bar): pass
#data_class
class B(A):
# noinspection PyMissingConstructor
def __init__(self, a, red, fox):
self.red_plus_fox = red + fox
# do not call parent constructor, decorator will do it for you
a = A(1, 2)
print a.__attrs__ # {'foo': 1, 'bar': 2}
b = B(a, 3, 4) # {'fox': 4, 'foo': 1, 'bar': 2, 'red': 3, 'red_plus_fox': 7}
print b.__attrs__
Source:
from collections import OrderedDict
def make_call_dict(f, is_class_method, *args, **kwargs):
vnames = f.__code__.co_varnames[int(is_class_method):f.__code__.co_argcount]
defs = f.__defaults__ or []
d = OrderedDict(zip(vnames, [None] * len(vnames)))
d.update({vn: d for vn, d in zip(vnames[-len(defs):], defs)})
d.update(kwargs)
d.update({vn: v for vn, v in zip(vnames, args)})
return d
def data_class(cls):
inherited = hasattr(cls, '_fields')
if not inherited: setattr(cls, '_fields', None)
__init__old__ = cls.__init__
def __init__(self, *args, **kwargs):
d = make_call_dict(__init__old__, True, *args, **kwargs)
if inherited:
# tricky call of parent __init__
O = cls.__bases__[0] # put parent dataclass first in inheritance list
o = d.values()[0] # first arg in my __init__ is parent class object
d = OrderedDict(d.items()[1:])
isg = o._fields[O] # parent __init__ signature, [0] shows is he expect data object as first arg
O.__init__(self, *(([o] if isg[0] else []) + [getattr(o, f) for f in isg[1:]]))
else:
self._fields = {}
self.__dict__.update(d)
self._fields.update({cls: [inherited] + d.keys()})
__init__old__(self, *args, **kwargs)
cls.__attrs__ = property(lambda self: {k: v for k, v in self.__dict__.items()
if not k.startswith('_')})
cls.__init__ = __init__
return cls

Related

Ensure a class always uses its own version of a method rather than the one defined in a subclass?

I have this code:
class A:
def __init__(self, vals: list):
self._vals = vals
def __len__(self) -> int:
# some side effects like logging maybe
return len(self._vals)
def print_len(self) -> None:
# some function that uses the len above
print(len(self))
class B(A):
def __len__(self) -> int:
return 0
The issue is, I want print_len to always call A.__len__. I can do this:
class A:
def __init__(self, vals: list):
self._vals = vals
def __len__(self) -> int:
return len(self._vals)
def print_len(self) -> None:
print(A.__len__(self))
class B(A):
def __len__(self) -> int:
return 0
But it feels wrong. Basically I want B to lie about __len__ to outside callers, but internally use the correct len specified in A.
So
a = A([1, 2, 3])
print(len(a)) # print 3
a.print_len() # print 3 - no surprises there
b = B([1, 2, 3])
print(len(b)) # print 0 - overload the __len__
b.print_len() # want this to be 3 using A's __len__, not 0 using B's __len__
Is there any way to ensure a class always uses its own version of a method rather than a subclass' version? I thought name mangling of dunder methods would help here.
I think your approach is a good one. The zen of Python states that "There should be one-- and preferably only one --obvious way to do it." and I think you've found it.
That being said, you can do this via name mangling. You just need to prefix the method with double underscores (don't add them to the end like magic methods). This will create a private method which won't ever be overwritten by subclasses.
I think this might be self-defeating since you're now putting the computation in a different method.
class A:
def __init__(self, vals: list):
self._vals = vals
def __len__(self) -> int:
return self.__length()
def __length(self) -> int:
return len(self._vals)
def print_len(self) -> None:
print(self.__length())

dynamic inheritance with type and super

I'm looking for a way to dynamically inherit a parent class with its attributes and methods, by using type for class creation and super for inheritance, like so:
class A:
def __init__(self,a,b):
self.a = a
self.b = b
def some_method(self,q):
return (self.a + self.b)**q
def B_init(self,**kwargs):
super().__init__(**kwargs)
def another_method(self,):
return 1
def class_B_factory(parent_class):
return type(
'B',
(parent_class, some_other_parent_class),
{'__init__':B_init,
'another_method':another_method
}
)
And then be able to call...
model = class_B_factory(A)(a = 1, b = 5)
print(model.some_method(2)) # outputs to (1 + 5)**2 = 36
I'm not sure how to proceed. I don't think I'll need a custom metaclass since I'm pretty sure you can't call the parent class' __init__ method while also creating self in the process. I also tried overriding the default __init__ method outside the scope of class_B_factory like so:
def class_B_factory(parent_class):
return type(
'B',
(parent_class, some_other_parent_class),
{'another_method':another_method
}
)
B = class_B_factory(A)
def B_init(self,**kwargs):
super(B,self).__init__(**kwargs)
B.__init__ = B_init
model = B(a = 1, b = 5)
because I figured type doesn't need __init__ right away, as it is only needed during instantiation. But then I get TypeError: __init__() got an unexpected keyword argument error, which seems like it didn't work, and its not clean anyway.
EDIT: I tried defining the methods outside the factory via the following but I am still unsuccessful. Not sure how to fix it. Python has trouble instantiating maybe?
class A:
...
def B_init(self, produced_class = None, **kwargs):
super(produced_class,self).__init__(**kwargs)
def another_method(self, q, parent_class = None):
if parent_class is not None:
return 3 * parent_class.some_method(self,q) # I expect any parent_class passed to have a method called some_method
return 1
def class_B_factory(parent_class, additional_methods):
methods = {}
for name, method in additional_methods.items():
if "parent_class" in signature(method).parameters:
method = partial(method, parent_class = parent_class) # freeze the parent_class argument, which is a cool feature
methods[name] = method
newcls = type(
'B',
(parent_class,),
methods # would not contain B_init
)
newcls.__init__ = partial(B_init, produced_class = newcls) # freeze the produced class that I am trying to fabricate into B_init here
return newcls
model = class_B_factory(parent_class = A, additional_methods = {"another_method": another_method})
print(signature(model.__init__).parameters) # displays OrderedDict([('self', <Parameter "self">),...]) so it contains self!
some_instance_of_model = model(a = 1, b = 5) # throws TypeError: B_init() missing 1 required positional argument: 'self'
The parameterless form of super() relies on it being physically placed inside a class body - the Python machinnery them will, under the hood, create a __class__ cell variable referring that "physical" class (roughly equivalent to a non-local variable), and place it as the first parameter in the super() call.
For methods not written inside class statements, one have to resort to explicitly placing the parameters to super, and these are the child class, and the instance (self).
The easier way to do that in your code is to define the methods inside your factory function, so they can share a non-local variable containing the newly created class in the super call: ​
def class_B_factory(parent_class):
def B_init(self,**kwargs):
nonlocal newcls # <- a bit redundant, but shows how it is used here
​super(newcls, self).__init__(**kwargs)
def another_method(self,):
​​return 1
​ newcls = type(
​'B',
​(parent_class, some_other_parent_class),
​{'__init__':B_init,
​'another_method':another_method
​}
return newcls
If you have to define the methods outside of the factory function (which is likely), you have to pass the parent class into them in some form. The most straightforward would be to add a named-parameter (say __class__ or "parent_class"), and use functools.partial inside the factory to pass the parent_class to all methods in a lazy way:
from functools import partial
from inspect import signature
class A:
...
# the "parent_class" argument name is given a special treatement in the factory function:
def B_init(self, *, parent_class=None, **kwargs):
nonlocal newcls # <- a bit redundant, but shows how it is used here
​super([parent_class, self).__init__(**kwargs)
def another_method(self,):
​​return 1
def class_B_factory(parent_class, additional_methods, ...):
methods = {}
for name, method in additional_methods.items():
if "parent_class" in signature(method).parameters:
method = partial(method, parent_class=parent_class)
# we populate another dict instead of replacing methods
# so that we create a copy and don't modify the dict at the calling place.
methods[name] = method
​ newcls = type(
​'B',
​(parent_class, some_other_parent_class),
methods
)
return newcls
new_cls = class_B_factory(B, {"__init__": B_init, "another_method": another_method})

Redefining a function for a different type [duplicate]

I know that Python does not support method overloading, but I've run into a problem that I can't seem to solve in a nice Pythonic way.
I am making a game where a character needs to shoot a variety of bullets, but how do I write different functions for creating these bullets? For example suppose I have a function that creates a bullet travelling from point A to B with a given speed. I would write a function like this:
def add_bullet(sprite, start, headto, speed):
# Code ...
But I want to write other functions for creating bullets like:
def add_bullet(sprite, start, direction, speed):
def add_bullet(sprite, start, headto, spead, acceleration):
def add_bullet(sprite, script): # For bullets that are controlled by a script
def add_bullet(sprite, curve, speed): # for bullets with curved paths
# And so on ...
And so on with many variations. Is there a better way to do it without using so many keyword arguments cause its getting kinda ugly fast. Renaming each function is pretty bad too because you get either add_bullet1, add_bullet2, or add_bullet_with_really_long_name.
To address some answers:
No I can't create a Bullet class hierarchy because thats too slow. The actual code for managing bullets is in C and my functions are wrappers around C API.
I know about the keyword arguments but checking for all sorts of combinations of parameters is getting annoying, but default arguments help allot like acceleration=0
What you are asking for is called multiple dispatch. See Julia language examples which demonstrates different types of dispatches.
However, before looking at that, we'll first tackle why overloading is not really what you want in Python.
Why Not Overloading?
First, one needs to understand the concept of overloading and why it's not applicable to Python.
When working with languages that can discriminate data types at
compile-time, selecting among the alternatives can occur at
compile-time. The act of creating such alternative functions for
compile-time selection is usually referred to as overloading a
function. (Wikipedia)
Python is a dynamically typed language, so the concept of overloading simply does not apply to it. However, all is not lost, since we can create such alternative functions at run-time:
In programming languages that defer data type identification until
run-time the selection among alternative
functions must occur at run-time, based on the dynamically determined
types of function arguments. Functions whose alternative
implementations are selected in this manner are referred to most
generally as multimethods. (Wikipedia)
So we should be able to do multimethods in Python—or, as it is alternatively called: multiple dispatch.
Multiple dispatch
The multimethods are also called multiple dispatch:
Multiple dispatch or multimethods is the feature of some
object-oriented programming languages in which a function or method
can be dynamically dispatched based on the run time (dynamic) type of
more than one of its arguments. (Wikipedia)
Python does not support this out of the box1, but, as it happens, there is an excellent Python package called multipledispatch that does exactly that.
Solution
Here is how we might use multipledispatch2 package to implement your methods:
>>> from multipledispatch import dispatch
>>> from collections import namedtuple
>>> from types import * # we can test for lambda type, e.g.:
>>> type(lambda a: 1) == LambdaType
True
>>> Sprite = namedtuple('Sprite', ['name'])
>>> Point = namedtuple('Point', ['x', 'y'])
>>> Curve = namedtuple('Curve', ['x', 'y', 'z'])
>>> Vector = namedtuple('Vector', ['x','y','z'])
>>> #dispatch(Sprite, Point, Vector, int)
... def add_bullet(sprite, start, direction, speed):
... print("Called Version 1")
...
>>> #dispatch(Sprite, Point, Point, int, float)
... def add_bullet(sprite, start, headto, speed, acceleration):
... print("Called version 2")
...
>>> #dispatch(Sprite, LambdaType)
... def add_bullet(sprite, script):
... print("Called version 3")
...
>>> #dispatch(Sprite, Curve, int)
... def add_bullet(sprite, curve, speed):
... print("Called version 4")
...
>>> sprite = Sprite('Turtle')
>>> start = Point(1,2)
>>> direction = Vector(1,1,1)
>>> speed = 100 #km/h
>>> acceleration = 5.0 #m/s**2
>>> script = lambda sprite: sprite.x * 2
>>> curve = Curve(3, 1, 4)
>>> headto = Point(100, 100) # somewhere far away
>>> add_bullet(sprite, start, direction, speed)
Called Version 1
>>> add_bullet(sprite, start, headto, speed, acceleration)
Called version 2
>>> add_bullet(sprite, script)
Called version 3
>>> add_bullet(sprite, curve, speed)
Called version 4
1. Python 3 currently supports single dispatch
2. Take care not to use multipledispatch in a multi-threaded environment or you will get weird behavior.
Python does support "method overloading" as you present it. In fact, what you just describe is trivial to implement in Python, in so many different ways, but I would go with:
class Character(object):
# your character __init__ and other methods go here
def add_bullet(self, sprite=default, start=default,
direction=default, speed=default, accel=default,
curve=default):
# do stuff with your arguments
In the above code, default is a plausible default value for those arguments, or None. You can then call the method with only the arguments you are interested in, and Python will use the default values.
You could also do something like this:
class Character(object):
# your character __init__ and other methods go here
def add_bullet(self, **kwargs):
# here you can unpack kwargs as (key, values) and
# do stuff with them, and use some global dictionary
# to provide default values and ensure that ``key``
# is a valid argument...
# do stuff with your arguments
Another alternative is to directly hook the desired function directly to the class or instance:
def some_implementation(self, arg1, arg2, arg3):
# implementation
my_class.add_bullet = some_implementation_of_add_bullet
Yet another way is to use an abstract factory pattern:
class Character(object):
def __init__(self, bfactory, *args, **kwargs):
self.bfactory = bfactory
def add_bullet(self):
sprite = self.bfactory.sprite()
speed = self.bfactory.speed()
# do stuff with your sprite and speed
class pretty_and_fast_factory(object):
def sprite(self):
return pretty_sprite
def speed(self):
return 10000000000.0
my_character = Character(pretty_and_fast_factory(), a1, a2, kw1=v1, kw2=v2)
my_character.add_bullet() # uses pretty_and_fast_factory
# now, if you have another factory called "ugly_and_slow_factory"
# you can change it at runtime in python by issuing
my_character.bfactory = ugly_and_slow_factory()
# In the last example you can see abstract factory and "method
# overloading" (as you call it) in action
You can use "roll-your-own" solution for function overloading. This one is copied from Guido van Rossum's article about multimethods (because there is little difference between multimethods and overloading in Python):
registry = {}
class MultiMethod(object):
def __init__(self, name):
self.name = name
self.typemap = {}
def __call__(self, *args):
types = tuple(arg.__class__ for arg in args) # a generator expression!
function = self.typemap.get(types)
if function is None:
raise TypeError("no match")
return function(*args)
def register(self, types, function):
if types in self.typemap:
raise TypeError("duplicate registration")
self.typemap[types] = function
def multimethod(*types):
def register(function):
name = function.__name__
mm = registry.get(name)
if mm is None:
mm = registry[name] = MultiMethod(name)
mm.register(types, function)
return mm
return register
The usage would be
from multimethods import multimethod
import unittest
# 'overload' makes more sense in this case
overload = multimethod
class Sprite(object):
pass
class Point(object):
pass
class Curve(object):
pass
#overload(Sprite, Point, Direction, int)
def add_bullet(sprite, start, direction, speed):
# ...
#overload(Sprite, Point, Point, int, int)
def add_bullet(sprite, start, headto, speed, acceleration):
# ...
#overload(Sprite, str)
def add_bullet(sprite, script):
# ...
#overload(Sprite, Curve, speed)
def add_bullet(sprite, curve, speed):
# ...
Most restrictive limitations at the moment are:
methods are not supported, only functions that are not class members;
inheritance is not handled;
kwargs are not supported;
registering new functions should be done at import time thing is not thread-safe
A possible option is to use the multipledispatch module as detailed here:
http://matthewrocklin.com/blog/work/2014/02/25/Multiple-Dispatch
Instead of doing this:
def add(self, other):
if isinstance(other, Foo):
...
elif isinstance(other, Bar):
...
else:
raise NotImplementedError()
You can do this:
from multipledispatch import dispatch
#dispatch(int, int)
def add(x, y):
return x + y
#dispatch(object, object)
def add(x, y):
return "%s + %s" % (x, y)
With the resulting usage:
>>> add(1, 2)
3
>>> add(1, 'hello')
'1 + hello'
In Python 3.4 PEP-0443. Single-dispatch generic functions was added.
Here is a short API description from PEP.
To define a generic function, decorate it with the #singledispatch decorator. Note that the dispatch happens on the type of the first argument. Create your function accordingly:
from functools import singledispatch
#singledispatch
def fun(arg, verbose=False):
if verbose:
print("Let me just say,", end=" ")
print(arg)
To add overloaded implementations to the function, use the register() attribute of the generic function. This is a decorator, taking a type parameter and decorating a function implementing the operation for that type:
#fun.register(int)
def _(arg, verbose=False):
if verbose:
print("Strength in numbers, eh?", end=" ")
print(arg)
#fun.register(list)
def _(arg, verbose=False):
if verbose:
print("Enumerate this:")
for i, elem in enumerate(arg):
print(i, elem)
The #overload decorator was added with type hints (PEP 484).
While this doesn't change the behaviour of Python, it does make it easier to understand what is going on, and for mypy to detect errors.
See: Type hints and PEP 484
This type of behaviour is typically solved (in OOP languages) using polymorphism. Each type of bullet would be responsible for knowing how it travels. For instance:
class Bullet(object):
def __init__(self):
self.curve = None
self.speed = None
self.acceleration = None
self.sprite_image = None
class RegularBullet(Bullet):
def __init__(self):
super(RegularBullet, self).__init__()
self.speed = 10
class Grenade(Bullet):
def __init__(self):
super(Grenade, self).__init__()
self.speed = 4
self.curve = 3.5
add_bullet(Grendade())
def add_bullet(bullet):
c_function(bullet.speed, bullet.curve, bullet.acceleration, bullet.sprite, bullet.x, bullet.y)
void c_function(double speed, double curve, double accel, char[] sprite, ...) {
if (speed != null && ...) regular_bullet(...)
else if (...) curved_bullet(...)
//..etc..
}
Pass as many arguments to the c_function that exist, and then do the job of determining which c function to call based on the values in the initial c function. So, Python should only ever be calling the one c function. That one c function looks at the arguments, and then can delegate to other c functions appropriately.
You're essentially just using each subclass as a different data container, but by defining all the potential arguments on the base class, the subclasses are free to ignore the ones they do nothing with.
When a new type of bullet comes along, you can simply define one more property on the base, change the one python function so that it passes the extra property, and the one c_function that examines the arguments and delegates appropriately. It doesn't sound too bad I guess.
It is impossible by definition to overload a function in python (read on for details), but you can achieve something similar with a simple decorator
class overload:
def __init__(self, f):
self.cases = {}
def args(self, *args):
def store_function(f):
self.cases[tuple(args)] = f
return self
return store_function
def __call__(self, *args):
function = self.cases[tuple(type(arg) for arg in args)]
return function(*args)
You can use it like this
#overload
def f():
pass
#f.args(int, int)
def f(x, y):
print('two integers')
#f.args(float)
def f(x):
print('one float')
f(5.5)
f(1, 2)
Modify it to adapt it to your use case.
A clarification of concepts
function dispatch: there are multiple functions with the same name. Which one should be called? two strategies
static/compile-time dispatch (aka. "overloading"). decide which function to call based on the compile-time type of the arguments. In all dynamic languages, there is no compile-time type, so overloading is impossible by definition
dynamic/run-time dispatch: decide which function to call based on the runtime type of the arguments. This is what all OOP languages do: multiple classes have the same methods, and the language decides which one to call based on the type of self/this argument. However, most languages only do it for the this argument only. The above decorator extends the idea to multiple parameters.
To clear up, assume that we define, in a hypothetical static language, the functions
void f(Integer x):
print('integer called')
void f(Float x):
print('float called')
void f(Number x):
print('number called')
Number x = new Integer('5')
f(x)
x = new Number('3.14')
f(x)
With static dispatch (overloading) you will see "number called" twice, because x has been declared as Number, and that's all overloading cares about. With dynamic dispatch you will see "integer called, float called", because those are the actual types of x at the time the function is called.
By passing keyword args.
def add_bullet(**kwargs):
#check for the arguments listed above and do the proper things
Python 3.8 added functools.singledispatchmethod
Transform a method into a single-dispatch generic function.
To define a generic method, decorate it with the #singledispatchmethod
decorator. Note that the dispatch happens on the type of the first
non-self or non-cls argument, create your function accordingly:
from functools import singledispatchmethod
class Negator:
#singledispatchmethod
def neg(self, arg):
raise NotImplementedError("Cannot negate a")
#neg.register
def _(self, arg: int):
return -arg
#neg.register
def _(self, arg: bool):
return not arg
negator = Negator()
for v in [42, True, "Overloading"]:
neg = negator.neg(v)
print(f"{v=}, {neg=}")
Output
v=42, neg=-42
v=True, neg=False
NotImplementedError: Cannot negate a
#singledispatchmethod supports nesting with other decorators such as
#classmethod. Note that to allow for dispatcher.register,
singledispatchmethod must be the outer most decorator. Here is the
Negator class with the neg methods being class bound:
from functools import singledispatchmethod
class Negator:
#singledispatchmethod
#staticmethod
def neg(arg):
raise NotImplementedError("Cannot negate a")
#neg.register
def _(arg: int) -> int:
return -arg
#neg.register
def _(arg: bool) -> bool:
return not arg
for v in [42, True, "Overloading"]:
neg = Negator.neg(v)
print(f"{v=}, {neg=}")
Output:
v=42, neg=-42
v=True, neg=False
NotImplementedError: Cannot negate a
The same pattern can be used for other similar decorators:
staticmethod, abstractmethod, and others.
I think your basic requirement is to have a C/C++-like syntax in Python with the least headache possible. Although I liked Alexander Poluektov's answer it doesn't work for classes.
The following should work for classes. It works by distinguishing by the number of non-keyword arguments (but it doesn't support distinguishing by type):
class TestOverloading(object):
def overloaded_function(self, *args, **kwargs):
# Call the function that has the same number of non-keyword arguments.
getattr(self, "_overloaded_function_impl_" + str(len(args)))(*args, **kwargs)
def _overloaded_function_impl_3(self, sprite, start, direction, **kwargs):
print "This is overload 3"
print "Sprite: %s" % str(sprite)
print "Start: %s" % str(start)
print "Direction: %s" % str(direction)
def _overloaded_function_impl_2(self, sprite, script):
print "This is overload 2"
print "Sprite: %s" % str(sprite)
print "Script: "
print script
And it can be used simply like this:
test = TestOverloading()
test.overloaded_function("I'm a Sprite", 0, "Right")
print
test.overloaded_function("I'm another Sprite", "while x == True: print 'hi'")
Output:
This is overload 3
Sprite: I'm a Sprite
Start: 0
Direction: Right
This is overload 2
Sprite: I'm another Sprite
Script:
while x == True: print 'hi'
You can achieve this with the following Python code:
#overload
def test(message: str):
return message
#overload
def test(number: int):
return number + 1
Either use multiple keyword arguments in the definition, or create a Bullet hierarchy whose instances are passed to the function.
I think a Bullet class hierarchy with the associated polymorphism is the way to go. You can effectively overload the base class constructor by using a metaclass so that calling the base class results in the creation of the appropriate subclass object. Below is some sample code to illustrate the essence of what I mean.
Updated
The code has been modified to run under both Python 2 and 3 to keep it relevant. This was done in a way that avoids the use Python's explicit metaclass syntax, which varies between the two versions.
To accomplish that objective, a BulletMetaBase instance of the BulletMeta class is created by explicitly calling the metaclass when creating the Bullet baseclass (rather than using the __metaclass__= class attribute or via a metaclass keyword argument depending on the Python version).
class BulletMeta(type):
def __new__(cls, classname, bases, classdict):
""" Create Bullet class or a subclass of it. """
classobj = type.__new__(cls, classname, bases, classdict)
if classname != 'BulletMetaBase':
if classname == 'Bullet': # Base class definition?
classobj.registry = {} # Initialize subclass registry.
else:
try:
alias = classdict['alias']
except KeyError:
raise TypeError("Bullet subclass %s has no 'alias'" %
classname)
if alias in Bullet.registry: # unique?
raise TypeError("Bullet subclass %s's alias attribute "
"%r already in use" % (classname, alias))
# Register subclass under the specified alias.
classobj.registry[alias] = classobj
return classobj
def __call__(cls, alias, *args, **kwargs):
""" Bullet subclasses instance factory.
Subclasses should only be instantiated by calls to the base
class with their subclass' alias as the first arg.
"""
if cls != Bullet:
raise TypeError("Bullet subclass %r objects should not to "
"be explicitly constructed." % cls.__name__)
elif alias not in cls.registry: # Bullet subclass?
raise NotImplementedError("Unknown Bullet subclass %r" %
str(alias))
# Create designated subclass object (call its __init__ method).
subclass = cls.registry[alias]
return type.__call__(subclass, *args, **kwargs)
class Bullet(BulletMeta('BulletMetaBase', (object,), {})):
# Presumably you'd define some abstract methods that all here
# that would be supported by all subclasses.
# These definitions could just raise NotImplementedError() or
# implement the functionality is some sub-optimal generic way.
# For example:
def fire(self, *args, **kwargs):
raise NotImplementedError(self.__class__.__name__ + ".fire() method")
# Abstract base class's __init__ should never be called.
# If subclasses need to call super class's __init__() for some
# reason then it would need to be implemented.
def __init__(self, *args, **kwargs):
raise NotImplementedError("Bullet is an abstract base class")
# Subclass definitions.
class Bullet1(Bullet):
alias = 'B1'
def __init__(self, sprite, start, direction, speed):
print('creating %s object' % self.__class__.__name__)
def fire(self, trajectory):
print('Bullet1 object fired with %s trajectory' % trajectory)
class Bullet2(Bullet):
alias = 'B2'
def __init__(self, sprite, start, headto, spead, acceleration):
print('creating %s object' % self.__class__.__name__)
class Bullet3(Bullet):
alias = 'B3'
def __init__(self, sprite, script): # script controlled bullets
print('creating %s object' % self.__class__.__name__)
class Bullet4(Bullet):
alias = 'B4'
def __init__(self, sprite, curve, speed): # for bullets with curved paths
print('creating %s object' % self.__class__.__name__)
class Sprite: pass
class Curve: pass
b1 = Bullet('B1', Sprite(), (10,20,30), 90, 600)
b2 = Bullet('B2', Sprite(), (-30,17,94), (1,-1,-1), 600, 10)
b3 = Bullet('B3', Sprite(), 'bullet42.script')
b4 = Bullet('B4', Sprite(), Curve(), 720)
b1.fire('uniform gravity')
b2.fire('uniform gravity')
Output:
creating Bullet1 object
creating Bullet2 object
creating Bullet3 object
creating Bullet4 object
Bullet1 object fired with uniform gravity trajectory
Traceback (most recent call last):
File "python-function-overloading.py", line 93, in <module>
b2.fire('uniform gravity') # NotImplementedError: Bullet2.fire() method
File "python-function-overloading.py", line 49, in fire
raise NotImplementedError(self.__class__.__name__ + ".fire() method")
NotImplementedError: Bullet2.fire() method
You can easily implement function overloading in Python. Here is an example using floats and integers:
class OverloadedFunction:
def __init__(self):
self.router = {int : self.f_int ,
float: self.f_float}
def __call__(self, x):
return self.router[type(x)](x)
def f_int(self, x):
print('Integer Function')
return x**2
def f_float(self, x):
print('Float Function (Overloaded)')
return x**3
# f is our overloaded function
f = OverloadedFunction()
print(f(3 ))
print(f(3.))
# Output:
# Integer Function
# 9
# Float Function (Overloaded)
# 27.0
The main idea behind the code is that a class holds the different (overloaded) functions that you would like to implement, and a Dictionary works as a router, directing your code towards the right function depending on the input type(x).
PS1. In case of custom classes, like Bullet1, you can initialize the internal dictionary following a similar pattern, such as self.D = {Bullet1: self.f_Bullet1, ...}. The rest of the code is the same.
PS2. The time/space complexity of the proposed solution is fairly good as well, with an average cost of O(1) per operation.
Use keyword arguments with defaults. E.g.
def add_bullet(sprite, start=default, direction=default, script=default, speed=default):
In the case of a straight bullet versus a curved bullet, I'd add two functions: add_bullet_straight and add_bullet_curved.
Overloading methods is tricky in Python. However, there could be usage of passing the dict, list or primitive variables.
I have tried something for my use cases, and this could help here to understand people to overload the methods.
Let's take your example:
A class overload method with call the methods from different class.
def add_bullet(sprite=None, start=None, headto=None, spead=None, acceleration=None):
Pass the arguments from the remote class:
add_bullet(sprite = 'test', start=Yes,headto={'lat':10.6666,'long':10.6666},accelaration=10.6}
Or
add_bullet(sprite = 'test', start=Yes, headto={'lat':10.6666,'long':10.6666},speed=['10','20,'30']}
So, handling is being achieved for list, Dictionary or primitive variables from method overloading.
Try it out for your code.
Plum supports it in a straightforward pythonic way. Copying an example from the README below.
from plum import dispatch
#dispatch
def f(x: str):
return "This is a string!"
#dispatch
def f(x: int):
return "This is an integer!"
>>> f("1")
'This is a string!'
>>> f(1)
'This is an integer!'
You can also try this code. We can try any number of arguments
# Finding the average of given number of arguments
def avg(*args): # args is the argument name we give
sum = 0
for i in args:
sum += i
average = sum/len(args) # Will find length of arguments we given
print("Avg: ", average)
# call function with different number of arguments
avg(1,2)
avg(5,6,4,7)
avg(11,23,54,111,76)

Python Is it ok that an attribute only exists in child/concrete classes [duplicate]

What's the best practice to define an abstract instance attribute, but not as a property?
I would like to write something like:
class AbstractFoo(metaclass=ABCMeta):
#property
#abstractmethod
def bar(self):
pass
class Foo(AbstractFoo):
def __init__(self):
self.bar = 3
Instead of:
class Foo(AbstractFoo):
def __init__(self):
self._bar = 3
#property
def bar(self):
return self._bar
#bar.setter
def setbar(self, bar):
self._bar = bar
#bar.deleter
def delbar(self):
del self._bar
Properties are handy, but for simple attribute requiring no computation they are an overkill. This is especially important for abstract classes which will be subclassed and implemented by the user (I don't want to force someone to use #property when he just could have written self.foo = foo in the __init__).
Abstract attributes in Python question proposes as only answer to use #property and #abstractmethod: it doesn't answer my question.
The ActiveState recipe for an abstract class attribute via AbstractAttribute may be the right way, but I am not sure. It also only works with class attributes and not instance attributes.
A possibly a bit better solution compared to the accepted answer:
from better_abc import ABCMeta, abstract_attribute # see below
class AbstractFoo(metaclass=ABCMeta):
#abstract_attribute
def bar(self):
pass
class Foo(AbstractFoo):
def __init__(self):
self.bar = 3
class BadFoo(AbstractFoo):
def __init__(self):
pass
It will behave like this:
Foo() # ok
BadFoo() # will raise: NotImplementedError: Can't instantiate abstract class BadFoo
# with abstract attributes: bar
This answer uses same approach as the accepted answer, but integrates well with built-in ABC and does not require boilerplate of check_bar() helpers.
Here is the better_abc.py content:
from abc import ABCMeta as NativeABCMeta
class DummyAttribute:
pass
def abstract_attribute(obj=None):
if obj is None:
obj = DummyAttribute()
obj.__is_abstract_attribute__ = True
return obj
class ABCMeta(NativeABCMeta):
def __call__(cls, *args, **kwargs):
instance = NativeABCMeta.__call__(cls, *args, **kwargs)
abstract_attributes = {
name
for name in dir(instance)
if getattr(getattr(instance, name), '__is_abstract_attribute__', False)
}
if abstract_attributes:
raise NotImplementedError(
"Can't instantiate abstract class {} with"
" abstract attributes: {}".format(
cls.__name__,
', '.join(abstract_attributes)
)
)
return instance
The nice thing is that you can do:
class AbstractFoo(metaclass=ABCMeta):
bar = abstract_attribute()
and it will work same as above.
Also one can use:
class ABC(ABCMeta):
pass
to define custom ABC helper. PS. I consider this code to be CC0.
This could be improved by using AST parser to raise earlier (on class declaration) by scanning the __init__ code, but it seems to be an overkill for now (unless someone is willing to implement).
2021: typing support
You can use:
from typing import cast, Any, Callable, TypeVar
R = TypeVar('R')
def abstract_attribute(obj: Callable[[Any], R] = None) -> R:
_obj = cast(Any, obj)
if obj is None:
_obj = DummyAttribute()
_obj.__is_abstract_attribute__ = True
return cast(R, _obj)
which will let mypy highlight some typing issues
class AbstractFooTyped(metaclass=ABCMeta):
#abstract_attribute
def bar(self) -> int:
pass
class FooTyped(AbstractFooTyped):
def __init__(self):
# skipping assignment (which is required!) to demonstrate
# that it works independent of when the assignment is made
pass
f_typed = FooTyped()
_ = f_typed.bar + 'test' # Mypy: Unsupported operand types for + ("int" and "str")
FooTyped.bar = 'test' # Mypy: Incompatible types in assignment (expression has type "str", variable has type "int")
FooTyped.bar + 'test' # Mypy: Unsupported operand types for + ("int" and "str")
and for the shorthand notation, as suggested by #SMiller in the comments:
class AbstractFooTypedShorthand(metaclass=ABCMeta):
bar: int = abstract_attribute()
AbstractFooTypedShorthand.bar += 'test' # Mypy: Unsupported operand types for + ("int" and "str")
Just because you define it as an abstractproperty on the abstract base class doesn't mean you have to make a property on the subclass.
e.g. you can:
In [1]: from abc import ABCMeta, abstractproperty
In [2]: class X(metaclass=ABCMeta):
...: #abstractproperty
...: def required(self):
...: raise NotImplementedError
...:
In [3]: class Y(X):
...: required = True
...:
In [4]: Y()
Out[4]: <__main__.Y at 0x10ae0d390>
If you want to initialise the value in __init__ you can do this:
In [5]: class Z(X):
...: required = None
...: def __init__(self, value):
...: self.required = value
...:
In [6]: Z(value=3)
Out[6]: <__main__.Z at 0x10ae15a20>
Since Python 3.3 abstractproperty is deprecated. So Python 3 users should use the following instead:
from abc import ABCMeta, abstractmethod
class X(metaclass=ABCMeta):
#property
#abstractmethod
def required(self):
raise NotImplementedError
If you really want to enforce that a subclass define a given attribute, you can use metaclasses:
class AbstractFooMeta(type):
def __call__(cls, *args, **kwargs):
"""Called when you call Foo(*args, **kwargs) """
obj = type.__call__(cls, *args, **kwargs)
obj.check_bar()
return obj
class AbstractFoo(object):
__metaclass__ = AbstractFooMeta
bar = None
def check_bar(self):
if self.bar is None:
raise NotImplementedError('Subclasses must define bar')
class GoodFoo(AbstractFoo):
def __init__(self):
self.bar = 3
class BadFoo(AbstractFoo):
def __init__(self):
pass
Basically the meta class redefine __call__ to make sure check_bar is called after the init on an instance.
GoodFoo()  # ok
BadFoo ()  # yield NotImplementedError
As Anentropic said, you don't have to implement an abstractproperty as another property.
However, one thing all answers seem to neglect is Python's member slots (the __slots__ class attribute). Users of your ABCs required to implement abstract properties could simply define them within __slots__ if all that's needed is a data attribute.
So with something like,
class AbstractFoo(abc.ABC):
__slots__ = ()
bar = abc.abstractproperty()
Users can define sub-classes simply like,
class Foo(AbstractFoo):
__slots__ = 'bar', # the only requirement
# define Foo as desired
def __init__(self):
self.bar = ...
Here, Foo.bar behaves like a regular instance attribute, which it is, just implemented differently. This is simple, efficient, and avoids the #property boilerplate that you described.
This works whether or not ABCs define __slots__ at their class' bodies. However, going with __slots__ all the way not only saves memory and provides faster attribute accesses but also gives a meaningful descriptor instead of having intermediates (e.g. bar = None or similar) in sub-classes.1
A few answers suggest doing the "abstract" attribute check after instantiation (i.e. at the meta-class __call__() method) but I find that not only wasteful but also potentially inefficient as the initialization step could be a time-consuming one.
In short, what's required for sub-classes of ABCs is to override the relevant descriptor (be it a property or a method), it doesn't matter how, and documenting to your users that it's possible to use __slots__ as implementation for abstract properties seems to me as the more adequate approach.
1 In any case, at the very least, ABCs should always define an empty __slots__ class attribute because otherwise sub-classes are forced to have __dict__ (dynamic attribute access) and __weakref__ (weak reference support) when instantiated. See the abc or collections.abc modules for examples of this being the case within the standard library.
The problem isn't what, but when:
from abc import ABCMeta, abstractmethod
class AbstractFoo(metaclass=ABCMeta):
#abstractmethod
def bar():
pass
class Foo(AbstractFoo):
bar = object()
isinstance(Foo(), AbstractFoo)
#>>> True
It doesn't matter that bar isn't a method! The problem is that __subclasshook__, the method of doing the check, is a classmethod, so only cares whether the class, not the instance, has the attribute.
I suggest you just don't force this, as it's a hard problem. The alternative is forcing them to predefine the attribute, but that just leaves around dummy attributes that just silence errors.
I've searched around for this for awhile but didn't see anything I like. As you probably know if you do:
class AbstractFoo(object):
#property
def bar(self):
raise NotImplementedError(
"Subclasses of AbstractFoo must set an instance attribute "
"self._bar in it's __init__ method")
class Foo(AbstractFoo):
def __init__(self):
self.bar = "bar"
f = Foo()
You get an AttributeError: can't set attribute which is annoying.
To get around this you can do:
class AbstractFoo(object):
#property
def bar(self):
try:
return self._bar
except AttributeError:
raise NotImplementedError(
"Subclasses of AbstractFoo must set an instance attribute "
"self._bar in it's __init__ method")
class OkFoo(AbstractFoo):
def __init__(self):
self._bar = 3
class BadFoo(AbstractFoo):
pass
a = OkFoo()
b = BadFoo()
print a.bar
print b.bar # raises a NotImplementedError
This avoids the AttributeError: can't set attribute but if you just leave off the abstract property all together:
class AbstractFoo(object):
pass
class Foo(AbstractFoo):
pass
f = Foo()
f.bar
You get an AttributeError: 'Foo' object has no attribute 'bar' which is arguably almost as good as the NotImplementedError. So really my solution is just trading one error message from another .. and you have to use self._bar rather than self.bar in the init.
Following https://docs.python.org/2/library/abc.html you could do something like this in Python 2.7:
from abc import ABCMeta, abstractproperty
class Test(object):
__metaclass__ = ABCMeta
#abstractproperty
def test(self): yield None
def get_test(self):
return self.test
class TestChild(Test):
test = None
def __init__(self, var):
self.test = var
a = TestChild('test')
print(a.get_test())

How to create a class share methods in memory and not replicate for each object in python3

is more than anything a doubt but, I want to create a class that put in memory methods a single time and then instances that believes it can share these methods without these have to be put in memory for each one of them.
Methods are "put in memory" only once. Methods are sequences of bytecode instructions and will be stored only once. However, properties (methods operate on) are not.
I think, you are confusing the difference of class properties and object properties. Use them as shown in the following examples:
class Foo:
def __init__(self):
self.object_prop = None
def set(self, val):
self.object_prop = val
def get(self):
return self.object_prop
Then you can use it like this:
a = Foo()
a.set(3)
print(a.get()) # prints 3
b = Foo()
b.set(4)
print(a.get()) # prints 3
And the class properties example looks like this:
class Foo:
class_prop = None
#classmethod
def set(cls, val):
cls.class_prop = val
#classmethod
def get(cls):
return cls.class_prop
a = Foo()
a.set(3)
print(a.get()) # prints 3
b = Foo()
b.set(4)
print(a.get()) # prints 4
Maybe this is, what you are looking for.
In the comments, you pointed out that you are looking for an implementation of singletons in python. In python, singletons are an anti-pattern and need to be avoided at all costs. However, a simple search on StackOverflow gives the following result:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Logger(metaclass=Singleton):
pass
With this implementation, all objects will have the same memory address:
>>> id(Logger())
140202032740616
>>> id(Logger())
140202032740616

Resources