I have a class with a static method which is called multiple times by other methods. For example:
class A:
def __init__(self):
return
#staticmethod
def one():
return 1
def two(self):
return 2 * A.one()
def three(self):
return 3 * A.one()
Method one is a utility function that belongs inside the class but isn't logically an attribute of the class or the class instance.
If the name of the class were to be changed from A to B, do I have to explicitly change every call to method one from A.one() to B.one()? Is there a better way of doing this?
I pondered this question once upon a time and, while I agree that using a refactoring utility is probably the best way to go, as far as I can tell it is technically possible to achieve this behaviour in two ways:
Declare the method a classmethod.
Use the __class__ attribute. Leads to rather messy code, and may well be deemed unsafe or inefficient for reasons I am not aware of(?).
class A:
def __init__(self):
return
#staticmethod
def one():
return 1
#classmethod
def two(cls):
return 2 * cls.one()
def three(self):
return 3 * self.__class__.one()
a = A()
print(a.two())
print(a.three())
Related
How do I use the function in the class below in the other class without using global?
Code:
class one:
class one_one:
def add(x):
return x+1
class one_two:
ans = one.one_one.add(1)
It certainly is an unusual design, but it will work if you remember to distinguish between classes and instances of classes (objects). In your example you are attempting to call add in the class one_one which is an instance method without first instantiating an object of that class type. The example below shows one way to achieve what you are trying to do by instantiating the objects before calling their methods.
Example:
class one:
class one_one:
def add(self, x):
return x+1
class one_two:
def add(self):
a_one_one = one.one_one()
ans = a_one_one.add(1)
return ans
a_one_two = one.one_two()
print(a_one_two.add())
Output:
2
This question is specific for python 3. Suppose I have a class hierarchy like this
class Base():
def calculate():
return 0
class Derived1(Base):
def calculate():
# some calculation
class Derived2(Base):
def calculate():
# some calculation
Now, what I want to do is make a class that defines a generic way to inherit from the Derived classes, and then overrides calculate. In other words, something in the spirit of C++ templates, to avoid copying over the subclasses code, but specify a generic way of subclassing, and then be able to define the subclasses as one liners, like shown below:
# pseudocode
class GenericDerived5(someGenericBase):
def calculate():
return super().calculate() + 5
class GenericDerived6(someGenericBase):
def calculate():
return super().calculate() + 5
class Derived5_1 = GenericDerived5(Derived1)
class Derived6_1 = GenericDerived6(Derived2)
(the calculation is not literally like this, just illustrating the combinatorial nature of the inheritance structure)
How would this code look like, and what are the relevant tools from python3 that I need? I've heard of metaclasses, but not very familiar.
class definition inside a factory-function body
The most straightforward way to go there is really straightforward - but can feel a bit awkward:
def derived_5_factory(Base):
class GenericDerived5(Base):
def calculate(self):
return super().calculate() + 5
return GenericDerived5
def derived_6_factory(Base):
class GenericDerived6(Base):
def calculate(self):
return super().calculate() + 6
return GenericDerived6
Derived5_1 = derived_5_factory(Derived1)
Derived6_2 = derived_6_factory(Derived2)
The inconvenient part is that your classes that need generic bases
have to be defined inside function bodies. That way, Python re-executes
the class statement itself, with a different Base, taking advantage
that in Python classes are first class objects.
This code have the inconveniences that (1) the class bodies must be inside functions, and (2) it can be the wrong approach at all:
Multiple inheritance
If you can have an extra inheritance level - that is the only difference for your example, this is the "correct" way to go. Actually, apart from having the former "GenericDerived" classes explicitly in their inheritance chain, they will behave exactly as intended:
class Base():
def calculate():
return 0
class Derived1(Base):
def calculate(self):
return 1
class Derived2(Base):
def calculate(self):
return 2
# mix-in bases:
class MixinDerived5(Base):
def calculate(self):
return super().calculate() + 5
class MixinDerived6(Base):
def calculate(self):
return super().calculate() + 6
Derived5_1 = type("Derived5_1", (MixinDerived5, Derived1), {})
Derived6_2 = type("Derived6_2", (MixinDerived6, Derived2), {})
Here, instead of using the class statement, a dynamic class is created with the type call, using both the class that needs a dybamic base and that dynamic base as its bases parameter. That is it - Derived5_1 is a fully working Python class with both Bases in its inheritance chain
Note that Python's super() will do exactly what common sense would expect it to do, "rerouting" itself through the extra intermediary "derived" classes before reaching "Base". So, this is what I get on the interactive console after pasting the code above:
In [6]: Derived5_1().calculate()
Out[6]: 6
In [7]: Derived6_2().calculate()
Out[7]: 8
A mix-in class, roughly speaking, is a class that isn't intended to be instantiated directly or act as a standalone base class (other than for other, more specialized mix-in classes), but to provide a small subset of functionality that another class can inherit.
In this case, your GenericDerived classes are perfect examples of mix-ins: you aren't creating instances of GenericDerived, but you can inherit from them to add a calculate method to your own class.
class Calculator:
def calculate(self):
return 9
class Calculator1(Calculator):
def calculate(self):
return super().calculate() + 5
class Calculator2(Calculator):
def calculate(self):
return super().calculate() + 10
class Base(Calculator):
...
Note that the Base and Calculator hierarchies are independent of each other. Base provides, in addition to whatever else it does, basic calculate functionality. A subclass of Base can use calculate that it inherits from Base (via Calculator), or it can inherit from a subclass of Calculator as well.
class Derived1(Base):
...
class Derived2(Base, Calculator1):
...
class Derived3(Base, Calculator2):
...
I have a class where I have multiple methods. I want to use one of the methods as a decorator for other methods. For this I am using following syntax:
#self.action
def execute(self,req):
where action is other method in my class. But it doesn't work and throws exception as
name 'self' is not defined
You cannot use a method of the class while defining it; there is no self within the class nor is the class 'baked' yet to even access any class.
You can treat methods as functions to use as a decorator:
class SomeClass():
def action(func):
# decorate
return wrapper
#action
def execute(self, req):
# something
If action is defined on a base class, then you'd have to refer to the name via the base class:
class Base():
#staticmethod
def action(func):
# decorate
return wrapper
class Derived(Base):
#Base.action
def execute(self, req):
# something
For Python 2, you'd have to make action a static method here, as otherwise you get an unbound method that'll complain you cannot call it without an instance as the first argument. In Python 3, you can leave off the #staticmethod decorator there, at least for the purposes of the decorator.
But note that action cannot then be used as a method directly; perhaps it should not be part of the class at all at that point. It is not part of the end-user API here, presumably the decorator is not used by consumers of the instances of these classes.
Just beware that both the decorator and the decorated function are unbound methods, so you can only access the self (or cls for classmethods) in the inner scope of the decorator, and must manually bind the decorated method to the instance bound in the inner decorator.
class A:
x = 5
y = 6
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
#decorate
def func(self):
return self.y
A().func() # 30!!
Still trying to wrap my head around how decorators could be inherited and overridden.
Beware that for the decorator to work it can't be bound to an instance. That is: there is no way to make this work
a = A()
#a.decorate
def func(*args):
return 1
Despite this pattern is much more common than the asked here.
At this point the question raises: is it a method at all or just code that you happen to hide in a class?
The only way to prevent the decorator being wrongfully bound is to declare it as a staticmethod, but then it must be in a previous super class because to be used it must be bound to the static class reference which would not be yet defined, just as the self.
class A:
x = 1
#staticmethod
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
class B(A):
#A.decorate
def func(self):
return 1
class C():
x = 2
#B.decorate
def func(self):
return 1
a = A()
class D():
x = 3
#a.decorate
def func(self):
return 1
B().func() # 1
C().func() # 2
D().func() # 3
But as you can see, there is no way for the decorator to use the state of its own class. class A from this last example just happens to be a mixin with a default x variable and an "unrelated" static decorator.
So, again, is it a method?
To overcome all of this, you can bind the staticmethod in your same class to an arbitrary type. Namely, the builtin type will do.
class A:
x = 1
#staticmethod
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
#decorate.__get__(type)
def func(self):
return 1
class B:
x = 2
#A.decorate
def func(self):
return 1
class C:
x = 3
#(A().decorate) # Only for Python 3.9+, see PEP-614
def func(self):
return 1
A().func() # 1
B().func() # 2
C().func() # 3
But this features too much magic for my taste. And still not a method for my gut.
In python "self" is passed to instance methods as an argument (the first), "self" is just a convention is possible to call it "foobarbaz" (of course it would be silly)… the point is that, from the outside "self" is not defined (because its scope is the method)… you can't decorate class methods with other class methods, instead you have to write a separate class!
Class Bar inherits from Foo:
class Foo(object):
def foo_meth_1(self):
return 'foometh1'
def foo_meth_2(self):
return 'foometh2'
class Bar(Foo):
def bar_meth(self):
return 'bar_meth'
Is there a way of turning all methods inherited from Foo private?
class Bar(Foo):
def bar_meth(self):
return 'bar_meth'
def __foo_meth_1(self):
return 'foometh1'
def __foo_meth_2(self):
return 'foometh2'
Python doesn't have privates, only obfuscated method names. But I suppose you could iterate over the methods of the superclass when creating the instance, removing them from yourself and creating new obfuscatingly named method names for those functions. setattr and getattr could be useful if you use a function to create obfuscated names.
With that said, it's a pretty cthuhlu-oid thing to do. You mention the intent is to keep the namespace cleaner, but this is more like mixing ammonia and chlorine. If the method needs to be hidden, hide it in the superclass. The don't create instances of the superclass -- instead create a specific class that wraps the hidden methods in public ones, which you could name the same thing but strip the leading whitespace.
Assuming I understand your intent correctly, I would suggest doing something like this:
class BaseFoo(object):
def __init__(self):
raise NotImplementedError('No instances of BaseFoo please.')
def _foo(self):
return 'Foo.'
def _bar(self):
return 'Bar.'
class HiddenFoo(BaseFoo):
def __init__(self): pass
class PublicFoo(BaseFoo):
def __init__(self): pass
foo = BaseFoo._foo
bar = BaseFoo._bar
def try_foobar(instance):
print 'Trying ' + instance.__class__.__name__
try:
print 'foo: ' + instance.foo
print 'bar: ' + instance.bar
except AttributeError, e:
print e
foo_1 = HiddenFoo()
foo_2 = PublicFoo()
try_foobar(foo_1)
try_foobar(foo_2)
And if PublicFoo.foo would do something more than BaseFoo.foo, you would write a wrapper that does whatever is needed, and then calls foo from the superclass.
This is only possible with Pyhtons's metaclasses. But this is quite sophisticated and I am not sure if it is worth the effort. For details have a look here
Why would you like to do so?
Since foo() and __foo() are completely different methods with no link between them, Python is unable to understand what you want to do. So you have to explain to it step by step, meaning (like sapth said) to remove the old methods and add new ones.
This is an Object Oriented Design flaw and a better approach would be through delegation:
class Basic:
def meth_1(self):
return 'meth1'
def meth_2(self):
return 'meth2'
class Foo(Basic):
# Nothing to do here
pass
class Bar:
def __init__(self):
self.dg = Basic()
def bar_meth(self):
return 'bar_meth ' + self.__meth_1()
def __meth_1(self):
return self.dg.meth_1()
def __meth_2(self):
return self.dg.meth_2()
While Foo inherits the Basic class because he wants the public methods from him, Bar will only delegate the job to Basic because he doesn't want to integrate Basic's interface into its own interface.
You can use metaclasses, but Boo will no longer be an actual subclass of Foo, unless you want Foo's methods to be both 'private' and 'public' in instances of Bar (you cannot selectively inherit names or delattr members inherited from parent classes). Here is a very contrived example:
from inspect import getmembers, isfunction
class TurnPrivateMetaclass(type):
def __new__(cls, name, bases, d):
private = {'__%s' % i:j for i,j in getmembers(bases[0]) if isfunction(j)}
d.update(private)
return type.__new__(cls, name, (), d)
class Foo:
def foo_meth_1(self): return 'foometh1'
def foo_meth_2(self): return 'foometh2'
class Bar(Foo, metaclass=TurnPrivateMetaclass):
def bar_meth(self): return 'bar_meth'
b = Bar()
assert b.__foo_meth_1() == 'foometh1'
assert b.__foo_meth_2() == 'foometh2'
assert b.bar_meth() == 'bar_meth
If you wanted to get attribute access working, you could create a new Foo base class in __new__ with all renamed methods removed.
I can do:
class T(object):
i = 5
# then use the value somewhere in a function
def p(self):
print id(i), T.i
.. but, if I happen to subclass T ..
class N(T):
pass
.. then N.i will in fact be T.i. I found a way to deal with this:
class T(object):
i = 5
def p(self):
print self.__class__.i
.. is this correct and sure to work? Or can it produce unexpected behavior in some situations (which I am unaware of)?
self.__class__.i is correct and sure to work (although i is a poor naming choice).
if the method from which you access i does not use self, you can make it a class method, in which case the first parameter will be the class and not the instance:
class T(object):
i = 5
#classmethod
def p(cls):
print cls.i
To read the attribute, you can also use self.i safely too. But to change its value, using self.i = value will change the attribute of the instance, masking the class attribute for that instance.
Uh... did you know you can refer to class attributes from instances?
class T(object):
i = 5
def p(self):
print(id(self.i), self.i)
Class methods aside, I just thought of an interesting idea. Why not use a property that accesses the underlying class instance?
class T(object):
_i = 5
#property
def i(self):
return self.__class__._i
#i.setter(self, value)
self.__class__._i = value
Of course this wouldn't prevent users from utilizing an instance's _i seperate from the class's _i.