I am using a mixin to separate a range of functionality to a different class. This Mixin is only supposed to be mixable with the only child class:
class Mixin:
def complex_operation(self):
return self.foo.capitalize()
class A(Mixin):
def __init__(self):
self.foo = 'foo'
in my method Mixin.complex_operation
PyCharm gives warning 'Unresolved Attribute Reference foo'.
Am I using the mixin pattern correctly? Is there a better way? (I would like to have type hints and autocompletion in my mixins, and I would like to have multiple mixins.)
Declare the necessary fields in the Mixin like:
class Mixin:
foo:str
def complex_operation(self):
return self.foo.capitalize()
This way the mixin actually declares the fields a class must have to be able to use this mixin. Type hint will create warnings if extending class will put incompatible type into declared field.
edit: Replaced foo = None with foo:str as suggested by @valex
I see few options.
1) Type annotations (i think this is cleanest solution):
class Mixin:
foo: str
def complex_operation(self):
return self.foo.capitalize()
2) Default None
(@ikamen option):
class Mixin:
foo = None
def complex_operation(self):
return self.foo.capitalize()
3) Suppress unresolved reference error for class or for specific line (i think this is more dirty way than first two):
# noinspection PyUnresolvedReferences
class Mixin:
def complex_operation(self):
return self.foo.capitalize()
class Mixin:
def complex_operation(self):
# noinspection PyUnresolvedReferences
return self.foo.capitalize()
So just to compiling my thoughts from the comments for everyone else:
The problem is keeping the two classes intrinsically connected while separating functionality. Here are my solutions:
1) Make a module
Have another file, say mixin.py
, that has complex_operation
as a function. Instead of accepting self
as a parameter, have it take a string:
# mixin.py
def complex_operation (foo: str) -> str: return foo.capitalize()
# main.py
from ai import complex_operation
class A:
def __init__(self): self.foo = "foo"
print (complex_operation (A().foo))
2) Make a class to accept another class as a parameter
In Mixin
's __init__
function, add a parameter to accept an A
, and then use that in its methods:
# mixin.py
class Mixin:
def __init__(self, a: A): self.a = a
def complex_operation(self): return self.a.foo.capitalize()
# main.py
from mixin import Mixin
class A:
def __init__(self): self.foo = "foo"
print (Mixin (A()).complex_operation())