Rename Methods on the Fly - python

We can rename class methods at class definition time with a metaclass. This question is not about that.
This is more of a thought experiment, so humour me a little please.
Say I wanted to write two decorators that are used like this:
class SomeClass(object):
#append_A
def some_method( self ):
pass
#append_B
def some_method( self ):
pass
Which would result in SomeClass having two methods: some_method_A and some_method_B
Is this possible and if so, can you point me in the right direction?
I've tried changing the frame's f_locals a few different ways, but the method name still persists.

No, it's not possible to change method names using decorator, as explained in the documentation:
The decorator syntax is merely syntactic sugar, the following two function definitions are semantically equivalent:
def f(...):
...
f = staticmethod(f)
#staticmethod
def f(...):
...
More syntax discussion goes here.
Update
I guess we could do something like leave the method alone in the decorator but also add a new method with an edited name in the scope it was defined (this case the class). The main thing is defining two methods with the same name then ending up with two differently named methods which are passed to the metaclass.
For this purpose you can use the class decorator:
def append_B(func):
func.suffix='_B'
return func
def appendable(class_obj):
for name in dir(class_obj):
if not name.startswith('_'):
attr = class_obj.__dict__[name] #getattr(class_obj, name)
suffix = getattr(attr, 'suffix', None)
if isinstance(suffix,str):
attr.suffix = None
setattr(class_obj,name+suffix, getattr(class_obj, name))
#delattr(class_obj,name)
return class_obj
The following usage allows you to define two names for the same method:
#appendable
class B(object):
#append_B
def some_method(s):
print 'B.some_method'
b=B()
b.some_method()
b.some_method_B()

Related

How can I refer to the currently being defined class? [duplicate]

For a recursive function we can do:
def f(i):
if i<0: return
print i
f(i-1)
f(10)
However is there a way to do the following thing?
class A:
# do something
some_func(A)
# ...
If I understand your question correctly, you should be able to reference class A within class A by putting the type annotation in quotes. This is called forward reference.
class A:
# do something
def some_func(self, a: 'A')
# ...
See ref below
https://github.com/python/mypy/issues/3661
https://www.youtube.com/watch?v=AJsrxBkV3kc
In Python you cannot reference the class in the class body, although in languages like Ruby you can do it.
In Python instead you can use a class decorator but that will be called once the class has initialized. Another way could be to use metaclass but it depends on what you are trying to achieve.
You can't with the specific syntax you're describing due to the time at which they are evaluated. The reason the example function given works is that the call to f(i-1) within the function body is because the name resolution of f is not performed until the function is actually called. At this point f exists within the scope of execution since the function has already been evaluated. In the case of the class example, the reference to the class name is looked up during while the class definition is still being evaluated. As such, it does not yet exist in the local scope.
Alternatively, the desired behavior can be accomplished using a metaclass like such:
class MetaA(type):
def __init__(cls):
some_func(cls)
class A(object):
__metaclass__=MetaA
# do something
# ...
Using this approach you can perform arbitrary operations on the class object at the time that the class is evaluated.
Maybe you could try calling __class__.
Right now I'm writing a code that calls a class method from within the same class.
It is working well so far.
I'm creating the class methods using something like:
#classmethod
def my_class_method(cls):
return None
And calling then by using:
x = __class__.my_class_method()
It seems most of the answers here are outdated. From python3.7:
from __future__ import annotations
Example:
$ cat rec.py
from __future__ import annotations
class MyList:
def __init__(self,e):
self.data = [e]
def add(self, e):
self.data.append(e)
return self
def score(self, other:MyList):
return len([e
for e in self.data
if e in other.data])
print(MyList(8).add(3).add(4).score(MyList(4).add(9).add(3)))
$ python3.7 rec.py
2
Nope. It works in a function because the function contents are executed at call-time. But the class contents are executed at define-time, at which point the class doesn't exist yet.
It's not normally a problem because you can hack further members into the class after defining it, so you can split up a class definition into multiple parts:
class A(object):
spam= 1
some_func(A)
A.eggs= 2
def _A_scramble(self):
self.spam=self.eggs= 0
A.scramble= _A_scramble
It is, however, pretty unusual to want to call a function on the class in the middle of its own definition. It's not clear what you're trying to do, but chances are you'd be better off with decorators (or the relatively new class decorators).
There isn't a way to do that within the class scope, not unless A was defined to be something else first (and then some_func(A) will do something entirely different from what you expect)
Unless you're doing some sort of stack inspection to add bits to the class, it seems odd why you'd want to do that. Why not just:
class A:
# do something
pass
some_func(A)
That is, run some_func on A after it's been made. Alternately, you could use a class decorator (syntax for it was added in 2.6) or metaclass if you wanted to modify class A somehow. Could you clarify your use case?
If you want to do just a little hacky thing do
class A(object):
...
some_func(A)
If you want to do something more sophisticated you can use a metaclass. A metaclass is responsible for manipulating the class object before it gets fully created. A template would be:
class AType(type):
def __new__(meta, name, bases, dct):
cls = super(AType, meta).__new__(meta, name, bases, dct)
some_func(cls)
return cls
class A(object):
__metaclass__ = AType
...
type is the default metaclass. Instances of metaclasses are classes so __new__ returns a modified instance of (in this case) A.
For more on metaclasses, see http://docs.python.org/reference/datamodel.html#customizing-class-creation.
If the goal is to call a function some_func with the class as an argument, one answer is to declare some_func as a class decorator. Note that the class decorator is called after the class is initialized. It will be passed the class that is being decorated as an argument.
def some_func(cls):
# Do something
print(f"The answer is {cls.x}")
return cls # Don't forget to return the class
#some_func
class A:
x = 1
If you want to pass additional arguments to some_func you have to return a function from the decorator:
def some_other_func(prefix, suffix):
def inner(cls):
print(f"{prefix} {cls.__name__} {suffix}")
return cls
return inner
#some_other_func("Hello", " and goodbye!")
class B:
x = 2
Class decorators can be composed, which results in them being called in the reverse order they are declared:
#some_func
#some_other_func("Hello", "and goodbye!")
class C:
x = 42
The result of which is:
# Hello C and goodbye!
# The answer is 42
What do you want to achieve? It's possible to access a class to tweak its definition using a metaclass, but it's not recommended.
Your code sample can be written simply as:
class A(object):
pass
some_func(A)
If you want to refer to the same object, just use 'self':
class A:
def some_func(self):
another_func(self)
If you want to create a new object of the same class, just do it:
class A:
def some_func(self):
foo = A()
If you want to have access to the metaclass class object (most likely not what you want), again, just do it:
class A:
def some_func(self):
another_func(A) # note that it reads A, not A()
Do remember that in Python, type hinting is just for auto-code completion therefore it helps IDE to infer types and warn user before runtime. In runtime, type hints almost never used(except in some cases) so you can do something like this:
from typing import Any, Optional, NewType
LinkListType = NewType("LinkList", object)
class LinkList:
value: Any
_next: LinkListType
def set_next(self, ll: LinkListType):
self._next = ll
if __name__ == '__main__':
r = LinkList()
r.value = 1
r.set_next(ll=LinkList())
print(r.value)
And as you can see IDE successfully infers it's type as LinkList:
Note: Since the next can be None, hinting this in the type would be better, I just didn't want to confuse OP.
class LinkList:
value: Any
next: Optional[LinkListType]
It's ok to reference the name of the class inside its body (like inside method definitions) if it's actually in scope... Which it will be if it's defined at top level. (In other cases probably not, due to Python scoping quirks!).
For on illustration of the scoping gotcha, try to instantiate Foo:
class Foo(object):
class Bar(object):
def __init__(self):
self.baz = Bar.baz
baz = 15
def __init__(self):
self.bar = Foo.Bar()
(It's going to complain about the global name 'Bar' not being defined.)
Also, something tells me you may want to look into class methods: docs on the classmethod function (to be used as a decorator), a relevant SO question. Edit: Ok, so this suggestion may not be appropriate at all... It's just that the first thing I thought about when reading your question was stuff like alternative constructors etc. If something simpler suits your needs, steer clear of #classmethod weirdness. :-)
Most code in the class will be inside method definitions, in which case you can simply use the name A.

Multiple ways to define a class method in Python?

In Dive Into Python, Mark Pilgrim says that:
When defining your class methods, you must explicitly list self as the first argument for each method
He then gives a few examples of this in code:
def clear(self): self.data.clear()
def copy(self):
if self.__class__ is UserDict:
return UserDict(self.data)
import copy
return copy.copy(self)
While going through some Python code online, I came across the #classmethod decorator. An example of that is:
class Logger:
#classmethod
def debug(msg):
print "DEBUG: " + msg
(Notice that there is no self parameter in the debug function)
Is there any difference in defining class methods using self as the first parameter and using the #classmethod decorator? If not, is one way of defining class methods more commonly used/preferred over another?
#classmethod isn't the same as defining an instance method. Functions defined with #classmethod receive the class as the first argument, as opposed to an instance method which receives a specific instance. See the Python docs here for more information.
self is not and will never will be implicit.
"self will not become implicit.
Having self be explicit is a good thing. It makes the code clear by removing ambiguity about how a variable resolves. It also makes the difference between functions and methods small."
http://www.python.org/dev/peps/pep-3099/

How to not accidentally override a method in python?

I know there are a bunch of similar questions out there. But my question is different.
I don't want to make a method which can't be overridden.
I want to protect my newly created class to not accidentally override something.
Using underscore as a prefix is pretty good, but soon I'll get a lot of methods with a lot of underscores. and somewhere in my inherited class, I will override the grand-ancestor's class method.
What I really want is something as simple as this:
class Cat(Mammal):
def walk(self):
if ancestor_has_function('walk'):
parent.walk();
do_something_here();
If any of Cat's ancestor (Either it is Mammal, Animal, or LifeForm) has "walk" method, then the parent method should be executed first.
Is that any possibility to do this in python?
EDIT:
For instance this is the resume of answers I considered as good. Hope this will help others:
class Animal(object):
pass
#def walk(self):
# print('animal walk')
class Mammal(Animal):
def walk(self):
if hasattr(super(Mammal, self), 'walk') and callable(super(Mammal,self).walk):
super(Mammal, self).walk()
print('mammal walk')
class Cat(Mammal):
def walk(self):
super(Cat, self).walk()
print('cat walk')
if __name__ == '__main__':
cat = Cat()
cat.walk()
And here is the output:
mammal walk
cat walk
Try to uncomment Animal's walk method, and you will have it work as well too.
Generally speaking, you'll probably want to provide at least a stub method in whichever superclass is the most generic:
class Mammal(object):
def walk(self):
pass
Then, extend it in subclasses by calling super():
class Cat(Mammal):
def walk(self):
super(Cat, self).walk() # or just super().walk(), in Python 3+
do_something_here()
Making the super() call conditional is not hard, but it's probably a bad idea: it's verbose, fragile, and only encourages bad practices. If you really, really have good reason to do it, you can just use hasattr() on the super object, like you would with any other object:
class Cat(Mammal):
def walk(self):
if hasattr(super(Cat, self), 'walk'):
super(Cat, self).walk()
do_something_here()
You would only want to do this in unusual situations, though, such as subclassing classes from a third-party library where you can't rely on certain methods being present, for some reason.
Yep. hasattr checks if there is an attribute with a specific name.
and callable checks if the specific attribute is callable.
class Mammal(object):
def walk(self):
print "walking"
class Cat(Mammal):
def walk(self):
if hasattr(Mammal,'walk') and callable(Mammal.walk):
Mammal.walk(self);
print "another walking!"
and now:
>>> my_cat = Cat()
>>> my_cat.walk()
walking
another walking!
Note that you can also use super to get your parent class like that:
if hasattr(super(Cat, self),'walk'):
You can use the dir() function to get all the names declared for some module or class. Methods declared in classes higher up in the hierarchy will also be included. Note, however, that this will also include attributes, so check with callable() first.
Also, calling the parent method looks a bit different in python, see the code below.
def walk(self):
if "walk" in dir(Mammal) and callable(Mammal.walk):
Mammal.walk(self)
# do something
you can keep your original method in a field
class MyClass:
def __method(self):
pass
def __init__(self):
self.method = __method
and than check for identity and call the saved method
import inspect
class SomeClass():
def __init__(self):
...
def somefunc(self):
....
def someOtherFunc(self):
....
allmembers = inspect.getmembers(SomeClass, predicate=inspect.ismethod)
getmembers returns a list of all methods define within the given class, it is a list of tuples that contains method names and definitions:
[('__init__', <unbound method SomeClass.__init__>),
('somefunc', <unbound method SomeClass.somefunc>),
('someOtherFunc', <unbound method SomeClass.someOtherFunc>)]
Since first elements of the tuple are strings, you can use string based methods to filter base methods like __init__
allmembers = filter(lambda x: not x.startswith('__'), [x[0] for x in inspect.getmembers(SomeClass, predicate=inspect.ismethod))])
[('somefunc', <unbound method SomeClass.somefunc>),
('someOtherFunc', <unbound method SomeClass.someOtherFunc>)]
You can get a list of all methods defined within the class and check if you have a similarly named method, Sincegetmembers returns you an unbound method instance, you can also reach that function easily.

Using 'property' as the name of a method in a python class

Is this possible in Python?
class MyClass(object):
#property
def property(self):
return self._property
That is, I want to have a property named 'property'. It actually runs fine, but Eclipse complains with a warning. I thought the built-in #property decorator lived in a different namespace than the methods and properties within my classes.
Is it possible to rename the built-in decorator within the scope of the relevant module, so I can use the name 'property' without receiving this warning? Maybe something like the following:
attr = property
class MyClass(object):
#attr
def property(self):
return self._property
I do this, but I still get the warning, since I created an alias for the global built-in #property decorator, but the name 'property' is still a valid way to refer to it.
Any ideas?
The problem with naming a property property is the following:
class Foo(object):
#property
def property(self):
return "ham"
#property
def other_property(self):
return "spam"
The second property can't be defined since you've shadowed the name property in the class definition.
You can get around this by "renaming" property as in your example, but if I were you, I wouldn't mess with the built-ins in this way. It makes your code harder to follow.
Decorators are ordinary functions, so they live in the same namespace as other functions. Indeed your property function is inside class Foo; but it turns out that that's where python first looks for decorator names, so there's a conflict.
You can see this from the fact that the following code compiles:
class Foo(object):
def decfun(x): return "ham"
#decfun
def second(self, y): pass

How to do Obj-C Categories in Python?

Obj-C (which I have not used for a long time) has something called categories to extend classes. Declaring a category with new methods and compiling it into your program, all instances of the class suddenly have the new methods.
Python has mixin possibilities, which I use, but mixins must be used from the bottom of the program: the class has to declare it itself.
Foreseen category use-case: Say you have a big class hierarchy that describe different ways of interacting with data, declaring polymorphic ways to get at different attributes. Now a category can help the consumer of these describing classes by implementing a convenient interface to access these methods in one place. (A category method could for example, try two different methods and return the first defined (non-None) return value.)
Any way to do this in Python?
Illustrative code
I hope this clarifies what I mean. The point is that the Category is like an aggregate interface, that the consumer of AppObj can change in its code.
class AppObj (object):
"""This is the top of a big hierarchy of subclasses that describe different data"""
def get_resource_name(self):
pass
def get_resource_location(self):
pass
# dreaming up class decorator syntax
#category(AppObj)
class AppObjCategory (object):
"""this is a category on AppObj, not a subclass"""
def get_resource(self):
name = self.get_resource_name()
if name:
return library.load_resource_name(name)
else:
return library.load_resource(self.get_resource_location())
Why not just add methods dynamically ?
>>> class Foo(object):
>>> pass
>>> def newmethod(instance):
>>> print 'Called:', instance
...
>>> Foo.newmethod = newmethod
>>> f = Foo()
>>> f.newmethod()
Called: <__main__.Foo object at 0xb7c54e0c>
I know Objective-C and this looks just like categories. The only drawback is that you can't do that to built-in or extension types.
I came up with this implementation of a class decorator. I'm using python2.5 so I haven't actually tested it with decorator syntax (which would be nice), and I'm not sure what it does is really correct. But it looks like this:
pycategories.py
"""
This module implements Obj-C-style categories for classes for Python
Copyright 2009 Ulrik Sverdrup <ulrik.sverdrup#gmail.com>
License: Public domain
"""
def Category(toclass, clobber=False):
"""Return a class decorator that implements the decorated class'
methods as a Category on the class #toclass
if #clobber is not allowed, AttributeError will be raised when
the decorated class already contains the same attribute.
"""
def decorator(cls):
skip = set(("__dict__", "__module__", "__weakref__", "__doc__"))
for attr in cls.__dict__:
if attr in toclass.__dict__:
if attr in skip:
continue
if not clobber:
raise AttributeError("Category cannot override %s" % attr)
setattr(toclass, attr, cls.__dict__[attr])
return cls
return decorator
Python's setattr function makes this easy.
# categories.py
class category(object):
def __init__(self, mainModule, override = True):
self.mainModule = mainModule
self.override = override
def __call__(self, function):
if self.override or function.__name__ not in dir(self.mainModule):
setattr(self.mainModule, function.__name__, function)
# categories_test.py
import this
from categories import category
#category(this)
def all():
print "all things are this"
this.all()
>>> all things are this

Categories