How do I refer to static class variable in Python? - python

I have a 'static' class
class A:
a = 1
#staticmethod
def doStuff():
foo(A.a)
Now I need a derived class
class B(A):
a = 2
that basically does
#staticmethod
def doStuff():
foo(B.a)
If A would not be a pseudo static class, I could just derive B from A and
foo(self.a)
would do what I want. Is there a way to avoid copying doStuff() into class B and replace foo(A.a) with foo(B.a)? Something along the line of referring to the class in a 'self' way and having class A s doStuff look like
def doStuff():
foo(class_self.a)
?

I assume you mean class instead of def in your code.
The answer is not to use a staticmethod, but a classmethod. This would behave exactly as you want.
class A:
a = 1
#classmethod
def doStuff(cls):
foo(cls.a)
class B(A):
a = 2

Related

How to override in multiple classes without code duplication (Python)

I am having a parent class A with few classes inheriting from it (B,C,...).
I have some function is_class_A that is implemented in A, and I want to override it in B and C in the same way.
Let say:
class A:
def is_class_A():
print("We are in class A")
class B(A):
def is_class_A():
print("Nope")
class C(A):
def is_class_A():
print("Nope")
Take in mind both functions that implement in class A and in the others, are long, and more complicate.
2 solutions I came in my mind to avoid the duplication in B, C implementation:
Using in class C:
def is_class_A():
return B.is_class_A()
I am not sure how this will be functional, because an object of C is not an object of B. And I don't pass here any self, so I don't see how this will work, maybe something similar can?
Next solution is using another heritage:
class C(B)
This won't work always, since not always possible (if they have different attributes) and might not fit the design purpose.
My best attempt so far is to use another class:
class BC(A):
def is_class_A():
print("Nope")
class B(BC):
pass
class C(BC):
pass
What do you think? Some more ideas? Maybe something more technical that won't involve with the program design?
Thanks.
One option is to define the alternate method once at the global scope, then do direct class attribute assignment.
class A:
def is_class_A(self):
print("We are in class A")
def alt_is_class_A(self):
print("Nope")
class B(A):
is_class_A = alt_is_class_A
class C(A):
is_class_A = alt_is_class_A
class D(A):
pass # No override
The assignment could also be handled by a decorator:
def mod_it(cls):
cls.is_class_A = alt_is_class_A
#mod_it
class B(A):
pass
#mod_it
class C(A):
pass
# No override
class D(A):
pass
or via A.__init_subclass__:
class A:
def is_class_A(self):
print("We are in class A")
def __init_subclass__(cls, is_class_A=None):
super().__init_subclass__()
if is_class_A is not None:
cls.is_class_A = is_class_A
def alt_is_class_A(self):
print("Nope")
class B(A, is_class_A=alt_is_class_A):
pass
class C(A, is_class_A=alt_is_class_A):
pass
# No override
class D(A):
pass

How to access class variable in decorator function

Is it possible to create a decorator function without argument that is able to access class variables. I found similar questions but they always refer to instance variables and not class variables and the variables are generally only accessed when the decorated method is called.
I want to reference the class variable at class definition not after instantiation.
Other solutions such as creating a Meta class come to mind, but I only want to use one class and a decorator without argument.
I am able to implement the required functionality without the use of decorators the following way with the desired results.
class B:
b=3
resetFuns=[]
def __init__(self,x):
self.x=x
self.y=x+self.b
def foo(self):
self.y=self.x+self.b
resetFuns.append(foo)
def reset(self):
for f in self.resetFuns:
f(self)
test=B(4)
print(test.y)
B.b=9
print(test.y)
test.reset()
print(test.y)
7
7
13
But I want to use a decorator similar to this.
class A:
b=3
resetFuns=[] ##class variable I want to access
def __init__(self,x):
self.x=x
self.y=x+self.b
def resetDecorator(func):
resetFuns.append(func) ##can't reference resetFuns like this
return func
#resetDecorator
def foo(self):
self.y=self.x+self.b
def reset(self):
for f in resetFuns:
f(self)
Something like:
def resetDecoratorCreator(resetFuns):
def resetDecorator(func):
resetFuns.append(func)
return func
return resetDecorator
class B:
b=3
resetFuns=[]
resetDecorator = resetDecoratorCreator(resetFuns)
def __init__(self,x):
self.x=x
self.y=x+self.b
#resetDecorator
def foo(self):
self.y=self.x+self.b
def reset(self):
for f in self.resetFuns:
f(self)
will get you what you're looking for.

Importing class variable python

I have two python classes, one uses the other's variable
class A:
class A(object):
variable = None
#classmethod
def init_variable(cls):
cls.variable = something
class B:
variable = __import__('module').A.variable
class B(object):
#staticmethod
def method():
return variable
I simplified my problem as much as possible. So my question is why I still have B.method() returning NoneType even if I update A.variable class variable with something using init_variable
I changed your code a bit so that it'd actually do what you want:
your_package/klass_A.py
class A(object):
variable = None
#classmethod
def init_variable(cls, something):
cls.variable = something
your_package/klass_B.py
from your_package.klass_A import A
class B(object):
#staticmethod
def method():
return A.variable
Now, you can actually update A.variable and use the updated variable in B as well. For example this:
print B.method()
A.init_variable('123')
print B.method()
returns:
None
123

Refer to own class in a static method

Is there a shorthand for referring to its own class in a static method?
Say I have this piece of code:
class SuperLongClassName(object):
#staticmethod
def sayHi():
print 'Hi'
#staticmethod
def speak():
SuperLongClassName.sayHi() # Is there a shorthand?
Yes, use #classmethod instead of #staticmethod. The whole point of #staticmethod is to remove the extra class parameter if you don't need it.
class SuperLongClassName(object):
#classmethod
def sayHi(cls):
print 'Hi'
#classmethod
def speak(cls):
cls.sayHi()
You probably want a classmethod. It works like a staticmethod, but takes the class as an implicit first argument.
class Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass(object):
#classmethod
def foo(cls):
print cls.__name__
Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass.foo() # prints Claaa...
Warning:
class Subclaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass(
Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass):
pass
Subclaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass.foo() # prints Subclaaa...
Alternatively, define a shorter alias for your class at module level:
class Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass2(object):
#staticmethod
def foo():
return _cls2
_cls2 = Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass2
# prints True
print (Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass2 is
Claaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaass2.foo())

Making a class method recognize which class context it's running in

I need to refactor existing code by collapsing a method that's copy-and-pasted between various classed that inherit from one another into a single method.
So I produced the following code:
class A(object):
def rec(self):
return 1
class B(A):
def rec(self):
return self.rec_gen(B)
def rec_gen(self, rec_class):
return super(rec_class, self).rec() + 1
class C(B):
def rec(self):
return self.rec_gen(C)
if __name__=='__main__':
b = B(); c = C()
print c.rec()
print b.rec()
And the output:
3
2
What still bothers me is that in the 'rec' method I need to tell 'rec_gen' the context of the class in which it's running. Is there a way for 'rec_gen' to figure it out by itself in runtime?
This capability has been added to Python 3 - see PEP 3135. In a nutshell:
class B(A):
def rec(self):
return super().rec() + 1
I think you've created the convoluted rec()/rec_gen() setup because you couldn't automatically find the class, but in case you want that anyway the following should work:
class A(object):
def rec(self):
return 1
class B(A):
def rec(self):
# __class__ is a cell that is only created if super() is in the method
super()
return self.rec_gen(__class__)
def rec_gen(self, rec_class):
return super(rec_class, self).rec() + 1
class C(B):
def rec(self):
# __class__ is a cell that is only created if super() is in the method
super()
return self.rec_gen(__class__)
The simplest solution in Python 2 is to use a private member to hold the super object:
class B(A):
def __init__(self):
self.__super = super(B)
def rec(self):
return self.__super.rec() + 1
But that still suffers from the need to specify the actual class in one place, and if you happen to have two identically-named classes in the class hierarchy (e.g. from different modules) this method will break.
There were a couple of us who made recipes for automatic resolution for Python 2 prior to the existence of PEP 3135 - my method is at self.super on ActiveState. Basically, it allows the following:
class B(A, autosuper):
def rec(self):
return self.super().rec() + 1
or in the case that you're calling a parent method with the same name (the most common case):
class B(A, autosuper):
def rec(self):
return self.super() + 1
Caveats to this method:
It's quite slow. I have a version sitting around somewhere that does bytecode manipulation to improve the speed a lot.
It's not consistent with PEP 3135 (although it was a proposal for the Python 3 super at one stage).
It's quite complex.
It's a mix-in base class.
I don't know if the above would enable you to meet your requirements. With a small change to the recipe though you could find out what class you're in and pass that to rec_gen() - basically extract the class-finding code out of _getSuper() into its own method.
An alternative solution for python 2.x would be to use a metaclass to automatically define the rec method in all your subclasses:
class RecGen(type):
def __new__(cls, name, bases, dct):
new_cls = super(RecGen, cls).__new__(cls, name, bases, dct)
if bases != (object,):
def rec(self):
return super(new_cls, self).rec() + 1
new_cls.rec = rec
return new_cls
class A(object):
__metaclass__ = RecGen
def rec(self):
return 1
class B(A):
pass
class C(B):
pass
Note that if you're just trying to get something like the number of parent classes, it would be easier to use self.__class__.__mro__ directly:
class A(object):
def rec(self):
return len(self.__class__.__mro__)-1
class B(A):
pass
class C(B):
pass
I'm not sure exactly what you're trying to achieve, but if it is just to have a method that returns a different constant value for each class then use class attributes to store the value. It isn't clear at all from your example that you need to go anywhere near super().
class A(object):
REC = 1
def rec(self):
return self.REC
class B(A):
REC = 2
class C(B):
REC = 3
if __name__=='__main__':
b = B(); c = C()
print c.rec()
print b.rec()

Categories

Resources