Python class method also instance method - python-3.x

I have a class that in principle carries all the information about it in its class body. When instantiated, it receives additional information that together with the class attributes forms a regular instance. My problem now lies in the fact that I need to implement a method which should be called as class method when it is called from a class object but should be called as regular instance method when called from an instance:
e.g. something like
class MyClass(object):
attribs = 1, 2, 3
def myMethod(self, args):
if isclass(self):
"do class stuff"
else:
"do instance stuff"
MyClass.myMethod(2) #should now be called as a class method, e.g. I would normally do #classmethod
MyClass().myMethod(2) #should now be called as instance method
Of course I could declare it as staticmethod and pass either the instance or the class object explicitly, but that seems rather unpythonic and also user unfriendly.

If the methods are to behave differently, you could simply change which one is exposed by that name at initialization time:
class MyCrazyClass:
#classmethod
def magicmeth(cls):
print("I'm a class")
def _magicmeth(self):
print("I'm an instance")
def __init__(self):
self.magicmeth = self._magicmeth

You can define a decorator that works like a regular method when called on an instance, or class method when called on a class. This requires a descriptor:
from functools import partial
class anymethod:
"""Transform a method into both a regular and class method"""
def __init__(self, call):
self.__wrapped__ = call
def __get__(self, instance, owner):
if instance is None: # called on class
return partial(self.__wrapped__, owner)
else: # called on instance
return partial(self.__wrapped__, instance)
class Foo:
#anymethod
def bar(first):
print(first)
Foo.bar() # <class '__main__.Foo'>
Foo().bar() # <__main__.Foo object at 0x106f86610>
Note that this behaviour will not be obvious to most programmers. Only use it if you really need it.

Related

Is there a way to use __getattr__ as Python classmethod

getattr works pretty well with instance of class:
class Person:
def __getattr__(self, name):
print(name)
p = Person()
p.john
Output:
john
but it does not work as classmethod:
class Person:
#classmethod
def __getattr__(cls, name):
print(name)
Person.john
Output:
AttributeError: type object 'Person' has no attribute 'john'
Is there a way to use getattr for class directly ?
__getattr__, like most special methods, is only looked up on the class of the instance (bypassing the instance itself). Since you're trying to call it on the class itself, it has to be defined on the class that class Person is implementing. By default that's type (the common root for all class types).
If you really need to do this (I suspect an XY problem) you can do this with a metaclass (the class of the class itself):
class PersonMeta(type):
def __getattr__(cls, name):
print(cls, name)
class Person(metaclass=PersonMeta):
def __getattr__(self, name):
return getattr(type(self), name) # Delegate to metaclass implementation
Person.john
Person().john
Try it online!
Note that you need to implement a delegating version on the class itself to ensure it delegates back to the metaclass's implementation (assuming you want to be able to have it function on instances of the class, not just on the class itself). The metaclass itself could dynamically attach such a method to the class at construction time (in __prepare__ or __new__) if all instances of the metaclass's classes should exhibit this delegation behavior.

How to use parent class to enforce subclasses to set value to an attribute?

I want the Parent class to have a checking mechanism to ensure all its subclasses to set an actual value to the attribute name. I found something here.
class Parent(object):
#name = None
def __init__(self):
if self.name == None:
raise NotImplementedError('Subclasses must define name')
class Child1(Parent):
pass
class Child2(Parent):
name = 'test'
class Child3(Parent):
def __init__(self):
self.name = 'test'
class Child4(Parent):
def __init__(self):
pass
#obj1 = Child1() # Expected output: NotImplementedError: Subclasses must define bar
obj2 = Child2()
obj3 = Child3()
obj4 = Child4() # I want the NotImplementedError is raised here as well, but it doesn't
The problem is as long as there is an __init__ method in the subclass, it overwrites the Parent class and the raise NotImplementedError is no longer in effect.
My current working solution is:
class Child5(Parent):
def __init__(self):
self.name = 'test'
super().__init__()
obj5 = Child5()
which seems to work, but I wonder if it's a proper implementation, or if it may have some hidden pitfalls, and also if I should learn to use/implement #abstractproperty instead of this solution?
Here, you need to understand when you parent class constructor gets called. Note that while creating child class objects, if child class has a constructor it is called by default. It is up to us whether we want to call parent class constructor as well and this shall be done by us. However if child class doesn't have a constructor, then the base class constructor is called.
So with your Child1(), parent constructor is called by default so it raises the exception.
In your Child2() as well parent constructor is called. However do note here that name variable is static and can even be accessed as Child2.name. And thus no exception is raised.
Your Child3 class has a constructor has a constructor thus parent constructor is never called and thus check for presence of name is actually never made. So you do need to add following line to to child constructor.
super().__init__()
This call shall be made after declaring name if constructor defines name. And this is what you have done in your Child5 class.
For exactly the same reason as above, exception was not captured in Child4. Following will check this condition in Child4:
class Child4(Parent):
def __init__(self):
super().__init__()
You can check when constructor is being called, by simply adding a unique print statement(such as print(1), print(2), and so on) in each constructor (preferably at the beginning).

Forwarding methods to a wrapped class

I'd like to attach some extra functionality (logging more or less) to methods of another class, but with the caveat that I can't subclass them, since I do not have control over the instantiation of the original class, but I can forward an object with the same duck typing. In other words, I'd like to prepend some code to a few methods while forwarding everything else to the original class instance.
An example of what I'm trying to accomplish would be something like the following:
class A(object):
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, name):
return getattr(self._wrapped, name)
class B(object):
def foo(self):
print("foo")
#classmethod
def bar():
print("bar")
b = B()
a = A(b)
a.foo() # prints "foo"
a.bar() # Fails (tries to pass the self parameter to bar())
Except that the method above fails for class methods, so it won't do it in my case. Is there a way to forward calls like this in a way that also works with class methods and static methods?

Find owner class of a method in Python

I'm writing decorators, and part of what I need to do is discern whether a function is a function or a method. Is there a way I can find what class a given method is a part of?
e.g. If I was to run this code, what could I write in getOwner to make exampleFunc print something like <class '__main__'.Example>?
class Example:
def method(self):
print("I'm a method")
def exampleFunc(func):
owner = getOwner(func)
print(owner)
test = Example()
exampleFunc(test.method)
If all you need to do is figure out of the thing behaving like a function is a method or a function, that is one purpose of the types module.
import types
def is_method(f):
return type(f) == types.MethodType
In the event that the function-like object is a method, you can find its parent class as follows.
Update Patched for Python3 compatibility.
def method_parent(f):
return f.__self__
If you have a reference to the classes defined in your scope, you'd need to check for each one:
def exampleFunc(f):
class_list = [...]
return any(f in vars(c).values() for c in class_List)
This will return True if function f is an instance method. However, if you wish to return the actual class name:
def exampleFunc(f):
class_list = [...]
for c in class_list:
if f in vars(c).values():
return c.__name__
return 'global function' if 'lambda' not in f.__name__ else 'lambda'
Note that this does not work for __dunder__ methods, and methods that your class inherits. For example,
class A:
def f1(self): pass
class B(A):
def f2(self): pass
print(vars(B))
mappingproxy({'__doc__': None,
'__module__': '__main__',
'f2': <function __main__.B.f2>})
Note that f1 is not a part of B's mappingproxy.

Can I derive from classmethod in Python?

I have a special statemachine implemented in Python, which uses class methods as state representation.
class EntityBlock(Block):
def __init__(self, name):
self._name = name
#classmethod
def stateKeyword1(cls, parserState : ParserState):
pass
#classmethod
def stateWhitespace1(cls, parserState : ParserState):
token = parserState.Token
if isinstance(token, StringToken):
if (token <= "generate"):
parserState.NewToken = GenerateKeyword(token)
parserState.NewBlock = cls(....)
else:
raise TokenParserException("....", token)
raise TokenParserException("....", token)
#classmethod
def stateDelimiter(cls, parserState : ParserState):
pass
Visit GitHub for full source code off pyVHDLParser.
When I debug my parser FSM, I get the statenames printed as:
State: <bound method Package.stateParse of <class 'pyVHDLParser.DocumentModel.Sequential.Package.Package'>>
I would like to get better reports, so I would like to overwrite the default behavior of __repr__ of each bound method object.
Yes, I could write a metaclass or apply a second decorator, but I was questioning myself:
Is it possible to derive from classmethod and have only one decorator called e.g. state?
According to PyCharm's builtins.py (a collection of dummy code for Python's builtins), classmethod is a class-based decorator.
Yes, you can write your own class that derives from classmethod if you want. It's a bit complicated though. You'll need to implement the descriptor protocol (overriding classmethod's implementation of __get__) so that it returns an instance of another custom class that behaves like a bound method object. Unfortunately, you can't inherit from Python's builtin bound method type (I'm not sure why not).
Probably the best approach then is to wrap one of the normal method objects in an instance of a custom class. I'm not sure how much of the method API you need to replicate though, so that might get a bit complicated. (Do you need your states to be comparable to one another? Do they need to be hashable? Picklable?)
Anyway, here's a bare bones implementation that does the minimum amount necessary to get a working method (plus the new repr):
class MethodWrapper:
def __init__(self, name, method):
self.name = name if name is not None else repr(method)
self.method = method
def __call__(self, *args, **kwargs):
return self.method(*args, **kwargs)
def __repr__(self):
return self.name
class State(classmethod):
def __init__(self, func):
self.name = None
super().__init__(func)
def __set_name__(self, owner, name):
self.name = "{}.{}".format(owner.__name__, name)
def __get__(self, owner, instance):
method = super().__get__(owner, instance)
return MethodWrapper(self.name, method)
And a quick demo of it in action:
>>> class Foo:
#State
def foo(cls):
print(cls)
>>> Foo.foo
Foo.foo
>>> Foo.foo()
<class '__main__.Foo'>
>>> f = Foo()
>>> f.foo()
<class '__main__.Foo'>
Note that the __set_name__ method used by the State descriptor is only called by Python 3.6. Without that new feature, it would be much more difficult for the descriptor to learn its own name (you might need to make a decorator factory that takes the name as an argument).

Resources