How do I find out which class I am initialising a decorator in? It makes sense that I wouldn't be able to find this out as the decorator is not yet bound to the class, but is there a way of getting round this?
class A(object):
def dec(f):
# I am in class 'A'
def func(cls):
f(cls)
return func
#dec
def test(self):
pass
I need to know which class I am (indicated by the commented line).
I don't think this is possible. At the very moment when you define test, the class doesn't exist yet.
When Python encounters
class A(object):
it creates a new namespace in which it runs all code that it finds in the class definition (including the definition of test() and the call to the decorator), and when it's done, it creates a new class object and puts everything into this class that was left in the namespace after the code was executed.
So when the decorator is called, it doesn't know anything yet. At this moment, test is just a function.
I don't get the question.
>>> class A(object):
def dec(f):
def func(cls):
print cls
return func
#dec
def test(self):
pass
>>> a=A()
>>> a.test()
<__main__.A object at 0x00C56330>
>>>
The argument (cls) is the class, A.
As Nadia pointed out you will need to be more specific. Python does not allow this kind of things, which means that what you are trying to do is probably something wrong.
In the meantime, here is my contribution: a little story about a sailor and a frog. (use a constructor after the class initialization)
class Cruise(object):
def arewelostyet(self):
print 'Young sailor: I think I am lost, help me :s'
instance = Cruise()
instance.arewelostyet()
def whereami(lostfunc):
"""
decorator
"""
def decorated(*args, **kwargs):
lostfunc(*args, **kwargs)
print 'Frog: Crôak! thou art sailing in class', lostfunc.im_class.__name__
# don't forget to write name and doc
decorated.func_name = lostfunc.func_name
decorated.func_doc = lostfunc.func_name
return decorated
print '[i]A frog pops out of nowhere[/i]'
# decorate the method:
Cruise.arewelostyet = whereami(Cruise.arewelostyet)
instance.arewelostyet()
Related
For better encapsulation, I want to decorate instance methods with methods inside the same class.
class SomeClass(object):
#staticmethod
def some_decorator(func):
def wrapped(self):
print 'hello'
return func(self)
return wrapped
#some_decorator
def do(self):
print 'world'
x = SomeClass()
x.do()
However, this piece of code raises TypeError: 'staticmethod' object is not callable
Now I make a workaround by defining a class and overload its new method to simulate a function, but it's eventually a class, not a function.
So can I access my functions inside the class scope?
Just get rid of that #staticmethod line. You want some_decorator to behave like a plain function, not like some kind of method.
The decorator is called when the class definition is being executed, before the class object itself exists. The normal method definitions inside a class are actually just plain old functions, they become methods dynamically each time they are called as attributes of the class instance (which turns them into bound methods). But while the class object itself is being built you can treat them as plain functions.
class SomeClass(object):
def some_decorator(func):
def wrapped(self):
print 'hello'
return func(self)
return wrapped
#some_decorator
def do(self):
print 'world'
x = SomeClass()
x.do()
output
hello
world
BTW, you have an error in your decorator: it's returning wrapped() instead of wrapped.
As chepner mentions in the comments we can delete some_decorator so that it doesn't take up space in the class object after we've finished using it in the class definition. (If we accidentally try to call it we'll get an error). We could do del SomeClass.some_decorator after the class definition, but it's also perfectly valid to put a del statement inside the class definition:
class SomeClass(object):
def some_decorator(func):
def wrapped(self):
print 'hello'
return func(self)
return wrapped
#some_decorator
def do(self):
print 'world'
del some_decorator
Python 3 doesn't allow you to reference a class inside its body (except in methods):
class A:
static_attribute = A()
def __init__(self):
...
This raises a NameError in the second line because 'A' is not defined.
Alternatives
I have quickly found one workaround:
class A:
#property
#classmethod
def static_property(cls):
return A()
def __init__(self):
...
Although this isn't exactly the same since it returns a different instance every time (you could prevent this by saving the instance to a static variable the first time).
Are there simpler and/or more elegant alternatives?
EDIT:
I have moved the question about the reasons for this restriction to a separate question
The expression A() can't be run until the class A has been defined. In your first block of code, the definition of A is not complete at the point you are trying to execute A().
Here is a simpler alternative:
class A:
def __init__(self):
...
A.static_attribute = A()
When you define a class, Python immediately executes the code within the definition. Note that's different than defining a function where Python compiles the code, but doesn't execute it.
That's why this will create an error:
class MyClass(object):
a = 1 / 0
But this won't:
def my_func():
a = 1 / 0
In the body of A's class definition, A is not yet defined, so you can't reference it until after it's been defined.
There are several ways you can accomplish what you're asking, but it's not clear to me why this would be useful in the first place, so if you can provide more details about your use case, it'll be easier to recommend which path to go down.
The simplest would be what khelwood posted:
class A(object):
pass
A.static_attribute = A()
Because this is modifying class creation, using a metaclass could be appropriate:
class MetaA(type):
def __new__(mcs, name, bases, attrs):
cls = super(MetaA, mcs).__new__(mcs, name, bases, attrs)
cls.static_attribute = cls()
return cls
class A(object):
__metaclass__ = MetaA
Or you could use descriptors to have the instance lazily created or if you wanted to customize access to it further:
class MyDescriptor(object):
def __get__(self, instance, owner):
owner.static_attribute = owner()
return owner.static_attribute
class A(object):
static_attribute = MyDescriptor()
Using the property decorator is a viable approach, but it would need to be done something like this:
class A:
_static_attribute = None
#property
def static_attribute(self):
if A._static_attribute is None:
A._static_attribute = A()
return A._static_attribute
def __init__(self):
pass
a = A()
print(a.static_attribute) # -> <__main__.A object at 0x004859D0>
b = A()
print(b.static_attribute) # -> <__main__.A object at 0x004859D0>
You can use a class decorator:
def set_static_attribute(cls):
cls.static_attribute = cls()
return cls
#set_static_attribute
class A:
pass
Now:
>>>> A.static_attribute
<__main__.A at 0x10713a0f0>
Applying the decorator on top of the class makes it more explicit than setting static_attribute after a potentially long class definition. The applied decorator "belongs" to the class definition. So if you move the class around in your source code you will more likely move it along than an extra setting of the attribute outside the class.
I want to define a class AorB, such that all A's are AorB's, and all B's are AorB's, and these are all the AorB's. Of course, A and B should be subclasses of AorB. The problem is in AorB.__init__, when I can't convince self it should be something else. I can define an AorB factory, but I'd rather have AorB constructor if possible.
class AorB:
def __init__(self,par):
if par: self=A(par) #!
else: self=B() #!
#staticmethod
def from_par(par):
if par: return A(par)
else: return B()
class A(AorB):
def __init__(self,par):
self.par=par
class B(AorB):
def __init__(self):
pass
print(
AorB.from_par(5),
AorB.from_par(0),
AorB(5),
AorB(0),
sep="\n")
I know assignment to self doesn't work here, but I just wanted to show intention. As I said, factory (from_par) works fine, I just want to call it as AorB, not as AorB.from_par.
PS. I know, __init__ is probably too late, type of self is already determined. Feel free to use metaclasses in your answer. It's time I learn something useful about them. :-)
You can't, not with __init__. Once __init__ is being called, the instance is already created.
You want a factory function instead:
class AorB: pass
class A(AorB):
def __init__(self,par):
self.par=par
class B(AorB):
def __init__(self):
pass
def AorB(par):
return A(par) if par else B()
From an API point of view, there is no difference; AorB is a callable that produces either an A() or a B() instance.
The other possible route involves defining a __new__ function instead; this is the class constructor:
class AorB:
def __new__(cls, par=None):
if cls is not AorB: return super().__new__(cls)
return super().__new__(A) if par else super().__new__(B)
class A(AorB):
def __init__(self, par):
self.par = par
class B(AorB):
def __init__(self, par=None):
pass
Which is just a more involved factory function, really. Note that the __new__ method returns the result of super().__new__ of one of the subclasses based on par, so both A and B will be passed a par parameter, wether they want one or not.
The if cls is not AorB line is needed to allow instantiating A() or B() directly; you can omit that line if that is not a requirement and only the AorB factory class is used.
Consider the following code:
class AClass():
def defaultMethod(self):
return 1
def __init__(self, methodToUse = defaultMethod):
print (methodToUse(self))
if __name__== "__main__":
AClass()
In this case one cannot move the defaultMethod below the __init__ method, if I do, it causes "NameError: name 'defaultMethod' is not defined"
This means that I need to define this method before the __init__ or else Python does not know about it. This again, means that I no longer have __init__ as the first method, which leaves me to wonder whether it is usual to place the __init__ method at the end of a class or in the beginning.
What do you mean, "I need to define this method before the init or else Python does not know about it" ?
>>> class A(object):
... def __init__(self):
... self.foo()
... def foo(self):
... print '42'
...
>>> A()
42
I usually place __ init__() before other instance methods, but after class methods/property/attributes.
I think you're doing things a little peculiarly. You should still put __init__ high up if not the first method. Readability is key and __init__ exposes what you expect the main instance fields to be.
Here are three alternatives. My preference is for the first as it documents the default method and will require the least modification to your code. The last works, but could be confusing for anyone having to maintain your code.
class A(object):
def __init__(self, method="foo"):
if callable(method):
method(self)
else:
getattr(self, method)()
def foo(self):
print "something"
class B(object):
def __init__(self, method = None):
if method is None:
self.defaultMethod()
else:
method(self)
def defaultMethod(self):
print "foo"
def _defaultMethod(self):
print self.x
class C(object):
def __init__(self, method = _defaultMethod):
self.x = "bleh"
method(self)
def anotherMethod(self):
print "doing something else"
def defaultMethodProxy(self):
_defaultMethod(self)
__init__ is most commonly placed at the beginning of a class since they are the first thing run when the class is instantiated. Since your situation requires it to exist further down in the class, it would be nice to other devs to leave a note in the comments for the class.
I prefer init at the beginning and I would actually not write the class that way, but rather something like this:
class AClass():
def __init__(self, methodToUse = 'defaultMethod'):
print getattr(self, methodToUse)()
def defaultMethod(self):
return 1
if __name__== "__main__":
AClass()
The problem is that at compile time (when the default arguments are created), there is no function defaultMethod, but if you use it inside __init__, then the method is there.
how does one go about accessing a decorator from a base class in a child?
I assumed (wrongly) that the ffg. would work:
class baseclass(object):
def __init__(self):
print 'hey this is the base'
def _deco(func):
def wrapper(*arg):
res = func(*arg)
print 'I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling'
return res
return wrapper
#_deco
def basefunc(self):
print 'I\'m a base function'
This class works fine, but then I create a child class inheriting from this:
class otherclass(baseclass):
def __init__(self):
super(otherclass, self).__init__()
print 'other class'
#_deco
def meh(self):
print 'I\'m a function'
This won't even import properly, let alone run. #_deco is undefined. Trying baseclass._deco throws an unbound method _deco() error, which isn't really surprising.
Any idea how to do this, I'd really like to encapsulate the decorator in the class, but I'm not married to the idea and I'd need to call it in the base & the child class.
class baseclass(object):
def __init__(self):
print 'hey this is the base'
def _deco(func):
def wrapper(*arg):
res = func(*arg)
print 'I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling'
return res
return wrapper
#_deco
def basefunc(self):
print 'I\'m a base function'
#_deco
def basefunc2(self):
print "I'm another base function"
#no more uses of _deco in this class
_deco = staticmethod(_deco)
# this is the key. it must be executed after all of the uses of _deco in
# the base class. this way _deco is some sort weird internal function that
# can be called from within the class namespace while said namespace is being
# created and a proper static method for subclasses or external callers.
class otherclass(baseclass):
def __init__(self):
super(otherclass, self).__init__()
print 'other class'
#baseclass._deco
def meh(self):
print 'I\'m a function'
There is also python3-specific way to use that decorator in child class without mentioning parent, exactly as OP suggested. It requires decorator to be implemented in parent's metaclass (nice explanation of metaclases can be found here), using its __prepare__() method.
aaronasterling's answer is valid and preferred way how to solve that, I am posting this only as an interesting example to help others understand the basics of language. Use metaclasses only when there is no other way to achive what you need!
class metaclass(type):
#classmethod
def __prepare__(metacls, name, bases):
def _deco(func):
def wrapper(*arg):
res = func(*arg)
print('I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling')
return res
return wrapper
return {"_deco": _deco}
class baseclass(metaclass=metaclass):
def __init__(self):
print('hey this is the base')
#_deco
def basefunc(self):
print('I\'m a base function')
class otherclass(baseclass):
def __init__(self):
super(otherclass, self).__init__()
print('other class')
#_deco
def meh(self):
print('I\'m a function')
The sample code works well in python3:
>>> obj = otherclass()
hey this is the base
other class
>>> obj.meh()
I'm a function
I'm a decorator. This is fabulous, but that colour, so last season sweetiedarling
Important notes about __prepare__() method:
If present, it runs before the object body is executed
Its return value is used as local namespace for the class body at the begining of its evaluation (this way, decorator can be availabe from child's body without using parent's namespace)
It should be implemented as classmethod() and should return mapping object (i.e. dict)
If not present, empty mapping is used as initial local namespace.