I was reading about the #staticmethod in Python when I came across tge following code:
class MyClass:
my_var = 0
#staticmethod
def static_method():
MyClass.my_var += 1
I just don't understand exactly why you can write a code like this... Doesn't it defeat the purpose of this method to be static?
I get it that there's also the fact that the first parameter won't be a class/instance reference, but... Still weird to call this decorator like that if I still can access class variables, no?
And if I can access class variables, why everywhere I read about it says that I cannot, even though I just clearly did with the code above? Is it just because I'm doing it wrong?
The idea that a static method can't modify class state is based on the idea that the static method doesn't receive a reference to the class as an argument like a class method does. However, in this case, a reference to the class is provided as a hard-coded value.
One reason for defining a static method rather than a class method is to guarantee that you modify the attribute of a specific class, rather than a possible subclass.
class A:
my_var = 0
#classmethod
def foo(cls):
cls.my_var += 1
#staticmethod
def bar():
A.my_var += 1
class B(A):
my_var = 0
A call to B.foo will modify B.my_var, not A.my_var. A call to B.bar will modify A.my_var.
Related
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.
I want to pass a method foo of an instance of a class A to another function run_function. The method foo will use instance variables of its class A.
Here is a minimal example, in which the instance variable of A is simply self.a_var, and foo just prints that variable.
class A:
def __init__(self,a_var):
self.a_var=a_var
def foo(self):
print(self.a_var)
class B:
def __init__(self, A):
self.A=A
# EDIT (comment to compile)
self.A.do_something()
def run_function(self):
self.A.foo()
def run_function_2(self, bar):
bar()
myA = A(42)
myA.foo()
# Current implementation
myB=B(myA)
myB.run_function()
# Better(?) implementation
myB.run_function_2(myA.foo)
At the moment I pass the instance myA of class A to the instance of B and explicitly call self.A.foo(). This forces the name of the function of Ato be foo. Which is stupid.
The better (?) implementation passes the function of the instance to run_function2. This works, but I am not sure if this is "safe".
Question:
Are there any loopholes that I don't see at the moment?
The important part is, that the method foo, that is passed, needs to access instance variables of the (its) class instance. So, will foo that is called inside run_function_2 always have access to all instance variables of myA?
Is there a better way to implement this?
EDIT: I forgot to add, that class B will always have an instance of A, since it has to do_something with that instance. Maybe that will change something(?). Sorry!
For your second implementation, have you considered the following:
>>> myAa = A(42)
>>> myAb = A(43)
>>> myB = B(myAb)
>>> myB.run_function_2(myAa.foo)
42
This might not be what you want. How about using getattr() and just passing in the desired method name:
>>> class C:
... def __init__(self, A):
... self.A = A
... def run_fct(self, bar):
... fct = getattr(self.A, bar)
... fct()
...
>>> myC = C(myAa)
>>> myC.run_fct('foo')
42
To answer your questions:
Any function executed in the context of an object instance will have access to the instance variables.
There may be a better way to implement this, you could try defining an interface for class A and other classes that might be like it. The you know that the function will always be called foo(). If not, I'd question why it is you need to have some object call an arbitrary method on another object. If you can give more concrete examples about what you're trying to do it would help.
The main difference between run_function and run_function_2 is that the former calls foo on the object that was given to the B() constructor. run_function_2 is independent of what object is saved as self.A; it just calls the function/method you give it. For example
class A:
def __init__(self,a_var):
self.a_var=a_var
def foo(self):
print(self.a_var)
class B:
def __init__(self, A):
self.A=A
def run_function(self):
self.A.foo()
def run_function_2(self, bar):
bar()
myA = A(42)
myB = B(myA)
myA2 = A(3.14)
myB.run_function()
myB.run_function_2(myA.foo)
myB.run_function_2(myA2.foo)
Output
42
42
3.14
Are there any loopholes that I don't see at the moment?
These two ways of calling methods are fine. Though I agree that function_run_2 is more convenient since it doesn't fix the method name, it makes you ask... what's the purpose of giving an A object to the B constructor in the first place if it's never used?
The important part is, that the method foo, that is passed, needs to access instance variables of the (its) class instance. So, will foo that is called inside run_function_2 always have access to all instance variables of myA?
Yes. run_function_2 arguments requires a function. In this case, you pass myA.foo, an object myA's method defined in class A. When you call foo inside run_function_2, you are only dealing with attributes variables of the instance myA; this is the idea of encapsulation in classes.
Is there a better way to implement this?
Answering also your question on safety, it's perfectly safe. Functions and methods are objects in Python, and they can be passed around like values. You're basically leaning on the idea of function currying or partial functions. See How do I pass a method as a parameter in Python. These two ways are fine.
I have two very basic object oriented question
1) Can we modify a class variable with member function?
For example
class test:
'''test class'''
idd=0
def __init__(self,mark,subject):
self.markk=mark
self.subjectt=subject
def display(self):
print "the display is",self.markk,self.subjectt;
stud1=test(30,'maths')
stud2=test(40,'english')
when i tried to modify class variable idd using the object stud1.idd=9;, the variable didnt modified. test.idd=9 modified the variable.
Can someone explain me why it is not possible to modify a class vars from a object?
2) Also in the above snippet, when I added a keyword global with the class var idd like
class test:
'''test class'''
global idd;
idd=0;
print test.idd
it threw error like name class test don't have attribute idd.
But when I commented out the global idd, it displayed value.
So is global keyword not supported in class?
can someone help me to get some idea on these two question as this is my basic step to object oriented concept..
I think that you're not understanding that python looks up values by looking at a "chain" of objects1. When you do value = self.foo, python will first look for foo on the instance. Then it will look on the class. Then it will look on the super-classes (in their "Method Resolution Order").
When you write:
self.foo = 'bar'
Python simply puts a foo on the instance. So now subsequent lookups on that instance will give you 'bar' even if foo is also defined on the class. Also note that since foo gets put on the instance, no changes are visible on the class.
If you want to update the class in a particular method, you might be able to use a classmethod:
class Foo(object):
idd = 0
#classmethod
def increment_idd(cls):
cls.idd += 1
f = Foo()
f.increment_idd()
print(Foo.idd)
print(f.idd)
This doesn't work if you need access to self however. In that case, you'll need to get a reference to the class from the instance:
class Foo(object):
idd = 0
def increment_idd(self):
cls = type(self)
cls.idd += 1
f = Foo()
f.increment_idd()
print(Foo.idd)
print(f.idd)
1If you know javascript, it's actually not too much different than javascript's prototypical inheritance
As long as it is a public variable you should be able to.
Is it OK to define functions outside a particular class, use them in the class, and then import that class elsewhere and use it?
Are there any risks associated with doing that, rather than making all functions methods of the class?
I'm writing this code in python 2.7
For example, make a class like this:
def func(a):
return a
class MyClass():
def class_func(self, thing):
return func(thing)
Then import MyClass into another python script and use its class_func method.
Doing this is okay, and in fact a language feature of python. Functions have access to names of the scope they are defined in, regardless of where they are called from.
For example, you can also do something like this:
factor = 2
def multiply(num):
return num*factor
See this post for some background information.
The "risk" associated with this is that the outside name is explicitly not under your control. It can be freely modified by other parts of your program, without the implication being clear.
Consider this example:
def func(a):
return a
class MyClass(object): # note: you should inherit from object in py2.X!
def class_func(self, thing):
return func(thing)
myinstance = MyClass()
foo = myinstance.class_func(1)
def func(a):
return str(a)
bar = myinstance.class_func(1)
Here, foo and bar will be different, namely the integer 1 and the string "1".
Usually, making this possible is the entire point of using such a structure, however.
It's ok, but if func uses only in MyClass it can be helpful to make it staticmethod and place inside MyClass near class_func:
class MyClass(object):
#staticmethod
def _func(a):
return a
def class_func(self, thing):
return type(self)._func(thing)
If I define a class a and a method blike this: (In Python2.7)
class a:
def b():
print("hello")
I can call this method neither by
a.b()
nor:
a_instance = a(); a_instance.b()
My questions are:
(1) Is there a way to call b?
(2) Is there any situation that this usage is meanful?
(3) I think b is neither a static method nor a instance method. Is b a class method? If not, what should be named to b?
or classmethod decorator which takes class object as first instance.
Is there a way to call b?
Yes you could either make it a static method or an instance method and call it accordingly. Below i make it a static method so you can call it on any instance or directly on the class object a
class a:
#classmethod
def b(cls):
print("hello")
a.b() #'hello'
Is there any situation that this usage is meanful?
What usage? static methods? yes there is, and it depends on your architecture. classmethods can be used as factory functions? returning new instances of classes.
I think b is neither a static method nor a instance method. Is b a class method? If not, what should be named to b?
i, too, don't think it is either. I believe it is just a function defined inside of a class body
I was confused about defining a function inside of a class and asked a similar question here
b is a static method. Just add the #staticmethod decorator.
class a:
#staticmethod
def b():
print("hello")
Also, you shouldn't really do this, but if you wanted to call b() without changing the class, you could do a().b.__func__().
Just in case this isn't obvious:
class a:
def b(self): # a normal "instance method" -- note "self"
print("hello")
aa = a() # an instance
aa.b() # call with no parameters
Here, b has no parameters because self is implied when called on an instance of the class.