Define a static instance of the class within a class in Python - python

I'm having the following basic problem in Python.
I want to create a constant static instance of a class within the class itself, to be used in methods of the class.
class MyClass(object):
def __init__(self, i : int):
self.i_c = i
newinstance = MyClass(0)
def method(self):
if self == newinstance:
return 'blaba'
else:
return self.i_c
Of course in this example, i could define the instance separately in the module containing my class, but then I could not use it in the methods of the class.
I don't know if it's feasible and I just don't know the right syntax, or if I cannot do this.
Edit: Based on the comments below one workaround is the following
class MyClass(object):
def __init__(self, i : int):
self.i_c = i
MyClass.newinstance = MyClass(0)
def func(thing):
if thing == MyClass.newinstance:
return 'blaba'
else:
return thing.i_c
This works, but func is now not a method of the class MyClass. This is not really problematic in my case, but I guess I can probably define func as a method of MyClass, I just don't really know how.
Ok, I got it, finally thanks to the comments below. This works
class MyClass(object):
def __init__(self, i : int):
self.i_c = i
def method(self):
if self == MyClass.newinstance:
return 'blaba'
else:
return self.i_c
MyClass.newinstance = MyClass(0)

Related

Calling class methods from class body

I have the code something like:
class ClassPrintable:
#classmethod
def print_class(cls):
print(cls)
I would like to be able to derive classes from this, and furthermore call the class methods inline from the class body, eg.
class MyClass(ClassPrintable):
print_class()
Unfortunately this doesn't work, however this does:
class MyClass(ClassPrintable):
ClassPrintable.print_class()
Unfortunately, of course, it prints the class for ClassPrintable rather than MyClass
The obvious solution, doesn't work, eg.
class MyClass(ClassPrintable):
MyClass.print_class()
Python complains it can't find MyClass! with a NameError: name 'MyClass' is not defined
How can I access MyClass's class method from within the body of its definition? I would prefer not to use dynanic metaprogramming but I will if I have to.
You cannot invoke anything on the class before it exists which is only after the class definition (note that method bodies aren't evaluated at class definition time). In Python >= 3.6, you can do the following, using the __init_subclass__ hook:
class ClassPrintable:
#classmethod
def print_class(cls):
print(cls)
#classmethod
def __init_subclass__(cls):
cls.print_class()
class MyClass(ClassPrintable):
pass
Alright I figured it out with small amount of metaprogramming. Whoever thought of __init_subclass__ is a genius. If anyone can see anything drastically wrong with this let me know.
import copy
class Model:
def __init__(self, name, default):
self.model_name = name
self.model_default = default
self.observers = []
class Models():
model_dictionary = {}
def __init_subclass__(cls, models=[]):
setattr(cls, "model_dictionary", {})
for model in models:
cls.model_dictionary[model[0]] = Model(model[0], model[1])
for c in cls.__bases__:
cls.add_base_models(c)
#classmethod
def add_base_models(cls, base):
if hasattr(base, "model_dictionary"):
for model in base.model_dictionary.values():
cls.model_dictionary[model.model_name] = copy.copy(base.model_dictionary[model.model_name])
for c in base.__bases__:
cls.add_base_models(c)
#classmethod
def listen(cls, name, closure):
cls.model_dictionary[name].observers.append(closure)
def __init__(self):
for model in self.model_dictionary.values():
super().__setattr__(model.model_name, model.model_default)
def __setattr__(self, name, value):
if name in self.__class__.model_dictionary.keys():
orig_value = getattr(self, name)
if value != orig_value:
for observer in self.model_dictionary[name].observers:
observer(self, value)
super().__setattr__(name, value)
else:
super().__setattr__(name, value)
Sample use of the code:
class Mouse(Models, models=[("x", 100), ("y", 200), ("visible", True)]):
pass
class SpecialMouse(Mouse, models=[("anger_level", "hostile")]):
pass
mouse = SpecialMouse()
mouse.listen("anger_level", lambda mouse, value : print(value))
mouse.anger_level = "cold!"
mouse.anger_level = "warm"
mouse.anger_level = "warm"
mouse.anger_level = "furious"
Prints out:
cold!
warm
furious

What is the pythonic way to overload class variables(properties)?

Hello!
I need each child class to has own set of constants. I've found a "proper" way with properties and overloading setter methods, but:
I need to define constructor in child classes (which I don't need) and assign values in constructor;
Every instance of class will have copy of this constants in memory (senseless resource consumption);
It looks weird when you define setter, getter and property at all just to use it as constant.
I've done something like this:
class BaseClass:
def get_a(self):
raise NotImplementedError("Oooops")
def get_b(self):
raise NotImplementedError("Oooops")
class FirstClass(BaseClass):
def get_a(self):
return "a"
def get_b(self):
return "b"
class SecondClass(BaseClass)
def get_a(self):
return "A"
def get_b(self):
return "B"
class SomeClass:
def some_method(self, class_param):
return "{}-{}".format(class_param.get_a, class_param.get_b)
This method also doesn't solve problems of method with properties (except last), just more compact. There's other way, which I find not good:
class BaseClass:
pass
class FirstClass(BaseClass):
A_CONST = "a"
B_CONST = "b"
class SecondClass(BaseClass)
A_CONST = "A"
B_CONST = "B"
class SomeClass:
def some_method(self, class_param):
return "{}-{}".format(class_param.A_CONST, class_param.B_CONST)
In fact, it solve all problems and pretty compact, BUT it violates rule of inheritance (isn't it?).
Question:
What is the proper way to do this?
P.S. Provided code is simplified example, base class contains methods which I use in child class, please don't write me that base class is useless here.
If you want your base class to indicate that it needs to be subclassed with certain attributes, you can make it an abstract base class.
from abc import ABC, abstractmethod
class Base(ABC):
#property
#abstractmethod
def a(self):
raise NotImplementedError
#property
#abstractmethod
def b(self):
raise NotImplementedError
You will then not be allowed to instantiate Base or its subclasses unless they override the abstract methods. You can do either
class First(Base):
a = 1
b = 2
to assign class attributes with those names, or
class Second(Base):
#Base.a.getter
def a(self):
return 3
#Base.b.getter
def b(self):
return 4
The benefit of the second approach is that it will raise an error if you try to assign to the property
Second().a = 5 # AttributeError
your second version looks fine to me… each language has their own conventions around what a "class" or "object" means, and this looks reasonably "Pythonic"
one minor comment about the first version, is that Python doesn't care about "overloading", you don't need to include:
class BaseClass:
def get_a(self):
raise NotImplementedError("Oooops")
at all, i.e. it's fine to have:
class BaseClass:
pass
as well in your first version.
another potentially useful tool here is the property decorator, e.g:
class FirstClass(BaseClass):
#property
def a(self):
return "a"
print(FirstClass().a)
would output "a"
If the key_name : [A_CONST, B_CONST] remains same for child classes, super() will take care of all your concerns (1., 2., 3.).
A 'pythonic' solution would include, to remove duplication's, of any, setter and getter in child classes and let BaseClass() handle these common-tasks.
class BaseClass(object):
def __init__(self, a, b):
self._a_const = a
self._b_const = b
#property
def A_CONST(self):
return self._a_const
#property
def B_CONST(self):
return self._b_const
class FirstClass(BaseClass):
def __init__(self, _aconst, _bconst):
# Let Base class object hold my constants but FirstClass Constructor
# is setting the value. Look SecondClass
super(FirstClass, self).__init__(_aconst, _bconst)
class SecondClass(BaseClass):
def __init__(self, _aconst, _bconst):
# Magic happens here
super(SecondClass, self).__init__(_aconst, _bconst)
class SomeClass():
def some_method(self, class_param):
return "{}-{}".format(class_param.A_CONST, class_param.B_CONST)
firstobj = FirstClass("a", "b")
secondobj = SecondClass("A", "B")
print(SomeClass().some_method(firstobj))
print(SomeClass().some_method(secondobj))

Python : use a class methods as static , when its implemented as instance methods

I have a big class which has a lot of functions and attributes.
the instances are created from data in a remote database.
the process of creating each instance is very long and heavy.
In performance sake ive created a bunch class from this heavy class.
so accessing the attributed is easy and works great .
the problem is how to use the methods from that class.
ex :
class clsA():
def __init__(self,obj):
self.attrA=obj.attrA
def someFunc(self):
print self
class bunchClsA(bunch):
def __getattr__(self, attr):
# this is the problem:
try:
#try and return a func
func = clsA.attr
return func
except:
# return simple attribute
return self.attr
Clearly this dosent work , Is there a way i could access the instance function staticly and override the "self" var ?
Found out a nice solution to the problem :
from bunch import Bunch
import types
#Original class:
class A():
y=6
def __init__(self,num):
self.x=num
def funcA(self):
print self.x
#class that wraps A using Bunch(thats what i needed .. u can use another):
class B(Bunch):
def __init__(self, data, cls):
self._cls = cls # notice, not an instance just the class it self
super(B, self).__init__(data)
def __getattr__(self, attr):
# Handles normal Bunch, dict attributes
if attr in self.keys():
return self[attr]
else:
res = getattr(self._cls, attr)
if isinstance(res, types.MethodType):
# returns the class func with self overriden
return types.MethodType(res.im_func, self, type(self))
else:
# returns class attributes like y
return res
data = {'x': 3}
ins_b = B(data, A)
print ins_b.funcA() # returns 3
print ins_b.y # returns 6
And this solves my issue, its a hack and if you have the privileges, redesign the code.

Python: Using properties of an outer class

I have some code that looks like this:
class Log(object):
#property
def log(self):
return self.log
class ExampleClass2(ExampleClass, Log):
class ExampleClass3(object):
#property
def log_value(self):
self.log.info('Hi!')
However I'm getting an error,
'ExampleClass3' object has not attribute 'log'
I'm guessing I need to add an __init__() method to DEF, and I've tried using
super(ExampleClass2.ExampleClass3, self).__init__()
but I'm still having problems accessing log. Any suggestions?
I believe to get your desired behavior, you need need to pass in an instance of ExampleClass2 when you create an instance of ExampleClass3.
class OuterClass:
def __init__(self, value):
self.value = value
class InnerClass:
def __init__(self, instance):
self.instance = instance
def inner_print_value(self):
print self.instance.value
def outer_print_value(self):
printer = OuterClass.InnerClass(self)
printer.inner_print_value()
OuterClass('Hi').outer_print_value() # 'Hi'
As noted in the comments, there is rarely a reason for this kind of structure. It would be easier to create InnerClass outside of the definition of OuterClass.
class OuterClass:
def __init__(self, value):
self.value = value
def outer_print_value(self):
printer = InnerClass(self)
printer.inner_print_value()
class InnerClass:
def __init__(self, instance):
self.instance = instance
def inner_print_value(self):
print self.instance.value
It seems like you're expecting the value of self to be augmented when creating an inner-class, but this is not the case. To do this, you'd want to use inheritance, and that doesn't require nested classes either.

Python decorator parametrized by instance attribute?

I am trying to define a python decorator (my_decorator) for a class method (f), shown below in a simplified scenario. my_decorator is parametrized by param, which depends on the class attribute (in this case level).
class my_decorator:
def __init__(self, param):
self.param = param
def __call__(self, f):
def f_decorated(instance, c):
print("decorated with param = %d" % self.param)
return f(c)
return f_decorated
class A:
def __init__(self, level):
self.level = level
#my_decorator(param=self.level) # Here is the problematic line!
def f(x):
return x
if __name__ == "__main__":
a = A(level=2)
a.f(1) # name "self" is not defined
The above code does not work, and I get a "self" is not defined error. So my question is, is there any way to achieve the goal of context-parametrized decorator?
BTW, the use case is: I am trying to achieve persistent memoization technique (described at
memoize to disk - python - persistent memoization)
The file where the cache persists to depends on the class A, specifically 'level'. For instance, I would like to persist to the file cache_%d.txt % self.level .
Chen,
Decorator are executed during the compiled time or during the import as the class body is executed during import. So, if you execute your snippet without creating an instance of that class also will throw error.
And more over that parameter self.level inside decorator doesn't make much sense to me as its an instance variable so you can directly use inside the function f(x):
Here is some more details:
Python decorator function called at compile time
As the error says, self doesn't exist at that point. That should be clear to you: self only exists as a parameter to a method, and you're not even in a method at that time. Decorators, like all class-level code are evaluated at define time.
I'm not totally sure what you want to achieve, but you could use a string along with getattr:
class my_decorator:
def __init__(self, param_name):
self.param_name = param_name
def __call__(self, f):
def f_decorated(instance, c):
param = getattr(instance, self.param_name)
print("decorated with param = %d" % param)
return f(c)
...
class A:
def __init__(self, level):
self.level = level
#my_decorator(param_name='level')
def f(x):
return x
self is a variable as any. It's only defined inside of methods, the decorator is outside. If you need attributes of a object inside an decorator, you have the possibility to access it by string-name:
class my_decorator:
def __init__(self, param):
self.param = param
def __call__(self, f):
def f_decorated(instance, c):
print("decorated with param = %d" % getattr(instance, self.param))
return f(instance, c)
return f_decorated
class A:
def __init__(self, level):
self.level = level
#my_decorator(param='level') # Here is the problematic line!
def f(self, x):
return x
if __name__ == "__main__":
a = A(level=2)
a.f(1) # name "self" is not defined

Categories