I know C++ and Java and I am unfamiliar with Pythonic programming. So maybe it is bad style what I am trying to do.
Consider fallowing example:
class foo:
def a():
__class__.b() # gives: this is foo
bar.b() # gives: this is bar
foo.b() # gives: this is foo
# b() I'd like to get "this is bar" automatically
def b():
print("this is foo")
class bar( foo ):
def b( ):
print("this is bar")
bar.a()
Notice, that I am not using self parameters as I am not trying to make instances of classes, as there is no need for my task. I am just trying to refer to a function in a way that the function could be overridden.
What you want is for a to be a classmethod.
class Foo(object):
#classmethod
def a(cls):
Foo.b() # gives: this is foo
Bar.b() # gives: this is bar
cls.b() # gives: this is bar
#staticmethod
def b():
print("this is foo")
class Bar(Foo):
#staticmethod
def b():
print("this is bar")
Bar.a()
I've edited your style to match the Python coding style. Use 4 spaces as your indent. Don't put extra spaces in between parenthesis. Capitalize & CamelCase class names.
A staticmethod is a method on a class that doesn't take any arguments and doesn't act on attributes of the class. A classmethod is a method on a class that gets the class automatically as an attribute.
Your use of inheritance was fine.
Quote from the Execution Model:
The scope of names defined in a class block is limited to the class
block; it does not extend to the code blocks of methods – this
includes generator expressions since they are implemented using a
function scope.
This mean that there is no name b in the scope of function a. You should refer to it via class or instance object.
Related
My case:
class BaseClass:
#staticmethod
def dummy_decorator(fnc):
def wrapper():
print('Im so dummy')
return wrapper
class InheritedClass(BaseClass):
def __init__(self):
pass
def anymethod(self):
print('hello world')
When I look at dir(), I see my staticmethod
>>> c = InheritedClass()
>>> dir(c)
['__doc__', '__init__', '__module__', 'anymethod', 'dummy_decorator']
Also, I can use my dummy operator as simple staticmethod inside new class.
But when I try to use it as decorator -- I get error
class InheritedClass(BaseClass):
def __init__(self):
pass
#dummy_decorator
def anymethod(self):
print('hello world')
>>> NameError: name 'dummy_decorator' is not defined
Why it works so?
I know, that if I change #dummy_decorator to #BaseClass.dummy_decorator -- everything will work, but why I can't use decorator without ref to parent class?
The reason why is baecause it is a static method, it belongs to the class as you have figured out when you put #BaseClass.dummy_decorator and it worked.
It is an attribute of the class so you can't just refer to it by dummy_decorator unless you move it out of the class or save it into the global namespace
To understand this properly, you need to understand how class definitions work. In a nutshell, everything inside a class block is executed just like regular Python code. Every name that has been created inside that class block (e.g. def or variable assignments) are then wrapped up at the end of the class block and become attributes of the new class object. It goes something like:
# START CAPTURE
def __init__(self):
pass
foo = 'bar'
# END CAPTURE
InheritedClass = # OBJECT WITH ATTRIBUTES "CAPTURED" ABOVE AND ADDITIONAL MAGIC
So, any code within the class block is just regular Python code. It hasn't "inherited" anything yet. That's the "additional magic" applied to the resulting class object at the end of the class block. And since there's no global "dummy_decorator" name defined, you can't call it by that name. It exists as "BaseClass.dummy_decoator", same as it would outside any class block.
From a famous example, I learned the difference between method, classmethod and staticmethod in a Python class.
Source:
What is the difference between #staticmethod and #classmethod in Python?
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
#classmethod
def class_foo(cls,x):
print "executing class_foo(%s,%s)"%(cls,x)
#staticmethod
def static_foo(x):
print "executing static_foo(%s)"%x
# My Guesses
def My_Question(self,x):
self.foo(x)
A.class_foo(x)
A.static_foo(x)
a=A()
Now I am wondering, how to call a method, #classmethod, and #staticmethod inside the class.
I put my guesses in the My_Question function above, please correct me if I am wrong with any of these.
Yes, your guesses will work. Note that it is also possible/normal to call staticmethods and classmethods outside the class:
class A():
...
A.class_foo()
A.static_foo()
Also note that inside regular instance methods, it's customary to call the staticmethods and class methods directly on the instance (self) rather than the class (A):
class A():
def instance_method(self):
self.class_foo()
self.static_foo()
This allow for inheritance to work as you might expect -- If I create a B subclass from A, if I call B.instance_method(), my class_foo function will get B instead of A as the cls argument -- And possibly, if I override static_foo on B to do something slightly different than A.static_foo, this will allow the overridden version to be called as well.
Some examples might make this more clear:
class A(object):
#staticmethod
def static():
print("Static, in A")
#staticmethod
def staticoverride():
print("Static, in A, overrideable")
#classmethod
def clsmethod(cls):
print("class, in A", cls)
#classmethod
def clsmethodoverrideable(cls):
print("class, in A, overridable", cls)
def instance_method(self):
self.static()
self.staticoverride()
self.clsmethod()
self.clsmethodoverride()
class B(A):
#classmethod
def clsmethodoverrideable(cls):
print("class, in B, overridable", cls)
#staticmethod
def staticoverride():
print("Static, in B, overrideable")
a = A()
b = B()
a.instance_method()
b.instance_method()
...
After you've run that, try it by changing all of the self. to A. inside instance_method. Rerun and compare. You'll see that all of the references to B have gone (even when you're calling b.instance_method()). This is why you want to use self rather than the class.
As #wim said, what you have is right. Here's the output when My_Question is called.
>>> a.My_Question("My_Answer=D")
executing foo(<__main__.A object at 0x0000015790FF4668>,My_Answer=D)
executing class_foo(<class '__main__.A'>,My_Answer=D)
executing static_foo(My_Answer=D)
Can someone explain why I'm getting the error:
global name 'helloWorld' is not defined
when executing the following:
class A:
def helloWorld():
print 'hello world'
class B(A):
def displayHelloWorld(self):
helloWorld()
class Main:
def main:
b = B()
b.displayHelloWorld()
I'm used to java where class B would obviously have a copy of class A's method "helloWorld" and thus this code would run fine when executing main. This however appears to think class B doesn't have any method called "helloWorld"
Missing the self before the helloWorld(). The self keyword means that this an instance function or variable. When class B inherits class A, all the functions in class A can now be accessed with the self.classAfunction() as if they were implemented in class B.
class A():
def helloWorld(self): # <= missing a self here too
print 'hello world'
class B(A):
def displayHelloWorld(self):
self.helloWorld()
class Main():
def main(self):
b = B()
b.displayHelloWorld()
You need to indicate that the method is from that class (self.):
class B(A):
def displayHelloWorld(self):
self.helloWorld()
Python differs in this from Java. You have to specify this explicitly in Python whereas Java accepts implicitly as well.
I don't know what is the version of python used in this example but it seems that syntax looks like python3. (except print statement which looks like python2.x)
Lets suppose that this is python3
I would say that helloWorld is class method of class A and It should be called as class attribute. As soon as this function is in class namespace It can be accessed outside this class only using owner class.
A.helloWorld()
or
B.helloWorld()
or
self.__class__.helloWorld()
You can't call it as bound method in this case because self argument will be passed and as soon as your function doesn't expect it it will fail.
there is possibility that helloWorld is method of A and self parameter is just missed
in this case this method can be called as follow:
self.helloWorld()
or
A.helloWorld(self)
I'm writing a method decorator and require access to the class defining the method that is currently decorated.
The issue seems with this is, that with Python 3 methods in a class are just functions unless the class is instantiated.
Is there any way around this? I don't really want to fiddle around with __qualname__...
In [29]: class A:
....: def B(self):
....: pass
....:
In [30]: A.B.__qualname__
Out[30]: 'A.B'
# This is what I want:
>>> get_class(A.B)
A
You can't, because at the time your decorator on a method is run, the class is yet to be created.
An example illustrates this a little better:
class Foo:
#spam
def bar(self): pass
When spam(bar) is invoked to produce a decorated function, we are inside the pseudo-function that Python runs to define the class body. Only when that pseudo-function is done executing, is the local namespace of that function turned into the class body and the actual class object itself is created.
That means that there is no Foo class object yet at the time spam() is run.
Instead, create a class decorator:
#spam
class Foo:
def bar(self): pass
Now spam() is passed the whole, complete Foo class giving you access to both the class and the methods.
If you need to mark specific methods on the class for decoration, you could use a marker decorator that sets attributes on the function:
def marker(func):
func._marked = True
return func
Use this decorator in the class body on methods that you want decorated, then use the class decorator to pick out those methods:
#spam
class Foo:
#marker
def bar(self): pass
def baz(self): pass
This is annoying:
class MyClass:
#staticmethod
def foo():
print "hi"
#staticmethod
def bar():
MyClass.foo()
Is there a way to make this work without naming MyClass in the call? i.e. so I can just say foo() on the last line?
There is no way to use foo and get what you want. There is no implicit class scope, so foo is either a local or a global, neither of which you want.
You might find classmethods more useful:
class MyClass:
#classmethod
def foo(cls):
print "hi"
#classmethod
def bar(cls):
cls.foo()
This way, at least you don't have to repeat the name of the class.
Not possible. It is a question of language design. Compare that to C++, where both this (the same as Python self; in Python you have to write self.var, in C++ you may write just var, not this->var) and own class are used by default in member functions, and you will probably see that sometimes that's good and sometimes that's annoying. The only thing possible is to get used to that feature.
You 'variable-ize' the class name. This will not remove, but shorten the name.
class MyClass:
#staticmethod
def foo():
print "hi"
#staticmethod
def bar():
c.foo()
c = MyClass
You can do something hacky by making a module level function foo and then adding it to the class namespace with staticmethod:
def foo():
print "hi"
class MyClass(object):
foo = staticmethod(foo)
#classmethod
def bar(cls):
return cls.foo()
def baz(self):
return foo()
c = MyClass()
c.bar()
c.baz()
MyClass.bar()
MyClass.foo()