Methods defined outside class which itself is subsequently imported - python

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)

Related

Why can't I invoke a static method inside the class body?

class StaticClass(object):
words = []
StaticClass.init()
#staticmethod
def init(file_name):
...
words.append('word')
...
#staticmethod
def fun():
print('fun')
test = StaticClass()
The error message is:
StaticClass.init()
NameError: name 'StaticClass' is not defined
Why can't I call the static function inside the class?
I want to use a class to do this and also want users to be able to do:
StaticClass.fun()
How to achieve the effect?
Why can't I call the static function inside the class?
As said in the comments, class bodies are executed in Python. It is like a zero-argument function that automatically runs once; then invokes type, passing it the class name, bases and a dict of class attributes from the local variables of that function; and only then assigns the result from type (i.e., a class object) to the name.
You can even put logic and other statements in there:
import random
# a class that sometimes fails to exist when you import the module.
class spam:
if __name__ != '__main__':
1 / random.randrange(3)
else:
print("thank you for running this as the main script.")
def __init__(self):
# etc.
As such, names have to be in scope. At the time that this code is running - because it runs immediately and automatically, rather than being delayed like a function - there isn't a StaticClass until after this code has completed. Consequently, the code inside can't reference the class itself.
To solve this, simply move the call to the end:
class StaticClass(object):
words = []
#staticmethod
def init(file_name):
...
words.append('word')
...
#staticmethod
def fun():
print('fun')
StaticClass.init()
By the time the body of the StaticClass class is being executed there is no reference to StaticClass, it doesn't exist yet. The body of the class is executed inside a namespace which is a dictionary. After that a new instance of type type which is here named StaticClass is created using that populated dictionary and added to the global namespaces. That's what class keyword roughly does in simple form.
Actually I don't know why you want this to work. Others already suggested best ways to deal with it but here is workaround if you want to call staticmethod as an initializer function when the class is being created and call it inside the class:
class StaticClass(object):
words = []
#staticmethod
def init(file_name, words=words):
words.append(file_name)
init.__get__(init)('word')
#staticmethod
def fun():
print('fun')
test = StaticClass()
StaticClass.fun()
print(StaticClass.words)
output:
fun
['word']
Yes it's really a mess, I just want to make it work to say why it didn't work before. You need to call init.__get__ because staticmethods are not callable. (I'm in Python 3.9.7) This way you init executed when the class is created. Also words is not accessible because the scope of the class is not enclosed the scope of the body of init, so I use it's reference as default parameter.

staticmethod decorator seems pointless

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.

Proper way to define function in a class that does not use self value

I am new to opp programming.I wanted to know what to do with a function that is inside the class but does not use self value
For example
class example:
def __init__(self,n):
self.number=n
def get_t(self,t):
return t*t
def main(self):
b=1
k=self.get_t(b)
From the example the function get_t has nothing to do with self value.
So I wanted to know where to place the function get_t or may be how to restructure the class.
Thank you for your consideration
What you're looking for are static methods. To declare a method static do it like this
#staticmethod
def foo():
pass
Nothing. Just let it be, Python won't complain about it and there's nothing fundamentally wrong about methods that doesn't use its instance. If your linter complains about it, you can shut up that warning. These kind of helper functions are often intended to be private methods that aren't intended to be used externally, you may want to prefix the name with underscore to indicate that.
Convert it into a free function. Python is an OOP language, but it's also a mixed paradigm language, unlike Java, for example, you can actually create a function outside of a class declaration. Pythonic code does not necessarily means putting everything into classes, and often a free function is perfectly suitable place for functions that doesn't involve a particular object instance.
def get_t(t):
return t*t
class example:
def main(self):
b=1
k=self.get_t(b)
If you want to be able to call it from the class by doing Example.get_t(blah) without having to have an instance, then you can either use the staticmethod or classmethod decorator. I suggest using classmethod which can do everything that staticmethod can do while the reverse isn't true and it's easier to make classmethod work correctly when you need to override it in a multi inheritance situation. staticmethod has a very tiny performance advantage, but you're microoptimizing if that's your concern.
class example:
#classmethod
def get_t(cls, t):
return t*t
def main(self):
b=1
k=self.get_t(b)
If get_t() is only being called from one method, you can put it as an inner function of that method:
class example:
def main(self):
def get_t(t):
return t * t
b=1
k=self.get_t(b)
With regards to naming, get_xxx is usually a code smell in python. The get_ prefix indicates that the method is likely a getter, and pythonic code usually don't use getters/setters, because the language supports property. What you have on here though, isn't actually a getter but rather a computation method, so it shouldn't be prefixed with get_. A better name might be calculate_t(t) or square(t).
Case 1: If self is there:-
class example:
def get_t(self,t):
return t*t
Then You can not access get_t function directly from class example like example.get_t(t=2) ,it will give you error. But you can access now by creating an object of class like q = example() and then q.get_t(t=2) , it will give you your desired result.
Case 2 : If self is not there:-
class example:
def get_t(t):
return t*t
Now You can directly access get_t function by class example like example.get_t(t=2) ,it will give you your desired result. But now you cannot use get_t function by creating object like q = example() then q.get_t(t=2) it will give you error.
Conclusion :- It all depends on your use case. But when you struck in this type of ambiguity use #staticmethod like given below:-
class example:
#staticmethod
def get_t(t):
return t*t
I hope it may help you.

How to override a method used by a 3rd party library

This would be the layout
some_function.py
def some_function():
print("some_function")
some_library.py
from some_function import some_function
class A:
def xxx(self):
some_function()
main.py
from some_library import A
from some_function import some_function
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
some_function = new_some_function
a = A()
a.xxx()
In the class A, the method xxx, calls some_function, so is it possible to override it with something else, without re-implementing the entire class?
I think you are looking for monkey patching (means changing classes/modules dynamically while running). This way you don't need to overwrite the class A and use inheritance as suggested by other comments - you said you don't want that, so try this solution:
import some_class # import like this or will not work (cos of namespaces)
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
# Import and use like this, other ways of import will not work.
# Because other way imports method to your namespace and then change it in your namespace,
# but you need to change it in the original namespace
some_class.some_function = new_some_function
That way replace the original method and even other classes will use it then. Be careful, if the original method is a class/instance method, you need to create new function with proper params, like this:
def new_some_function(self):
# for instance methods, you may add other args, but 'self' is important
def new_some_function(cls):
# for class methods, you may add other args, but 'cls' is important
You provide very little information about your use case here. As one of the comments points out, this might be a case for inheritance. If you are in a testing context, you may not want to use inheritance though, but you might rather want to use a mock-object.
Here is the inheritance version:
from some_library import A
def new_some_function():
print("new_some_function")
class B(A):
def xxx(self):
new_some_function()
if __name__ == '__main__':
a = B()
a.xxx()
Note, how class B derives from class A through the class B(A) statement. This way, class B inherits all functionality from A and the definition of class B only consists of the parts where B differs from A. In your example, that is the fact that the xxx method should call new_some_function instead of some_function.
Here is the mock version:
from unittest import mock
from some_library import A
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
with mock.patch('some_library.some_function') as mock_some_function:
mock_some_function.side_effect = new_some_function
a = A()
a.xxx()
As mentioned above this approach is mostly useful if you are in a testing context and if some_function does something costly and/or unpredictable. In order to test code that involves a call to some_function, you may temporarily want to replace some_function by something else, that is cheap to call and behaves in a predictable way. In fact, for this scenario, replacing some_function by new_some_function might even be more than what is actually needed. Maybe, you just want an empty hull that can be called and that always returns the same value (instead of the side_effect line, you can specify a constant .return_value in the above code example). One of the key functionalities of mock objects is that you can later check if that function has been called. If testing is your use case, I would very much recommend looking at the documentation of the python mock module.
Note that the example uses the mock.patch context manager. This means that within the managed context (i.e. the block inside the with-statement) some_library.some_function is replaced by a mock object, but once you leave the managed context, the original functionality is put back in place.
You may just create another class and override the method you need.
Just as an example:
class myInt(int):
def __pow__(self, x):
return 0
a = myInt(10)
a+10 # 20
a**2 # 0
In this case a is an int and has access to all the method of the int class, but will use the __pow__ method I've defined.
What you need is inheritance, You can subclass a class and with super method you can inherit all the parent class functions. If you want to override parent class functions, you just need to provide a different implementation by the same name in child class.
from some_library import A
from some_function import some_function
def new_some_function():
print("new_some_function")
class B(A):
def __init__(*args, **kwargs):
super().__init__(self)
pass
def xxx(self):
new_some_function()
if __name__ == '__main__':
a = B()
a.xxx()
Output:
new_some_function
you syntax may differ depending upon the python version.
In python3
class B(A):
def __init__(self):
super().__init__()
In Python 2,
class B(A):
def __init__(self):
super(ChildB, self).__init__()

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.

Categories