Python: call methods on default object - python

Is it possible to call methods on a default object? To explain what I mean, here's an example:
There's Foo.py with a class:
class Foo:
def fooMethod():
print "doSomething"
fooObject = Foo()
And another pythonscript Bar.py:
from Foo import *
// what I can do now is:
fooObject.fooMethod()
// what I need is that this:
fooMethod()
// is automatically executed on fooObject if the method was not found in Bar.py
Is there any possibility to make this work? What I need is to set a "default"-object on which methods are executed if the method was not found.

This has been done in Python's random module. They use a simple and straight-forward solution:
class Foo:
def foo_method(self):
print "do something"
foo_object = Foo()
foo_method = foo_object.foo_method
It would also be possible to write some introspection code to automatically propagate all methods of Foo to the module namespace, but I recommend against doing so.

Related

Python: How to refer a class inside itself?

Trying to refer a class inside itself. For e.g.
class Test:
FOO_DICT = {1 : Test.bar} # NameError: name 'Test' is not defined
#staticmethod
def bar():
pass
Does this usage make sense? Any better alternatives?
Thanks!
If you want the dictionary to be in the class: define the function first and remove Test:
class Test:
#staticmethod
def bar():
pass
FOO_DICT = {1: bar}
You don't need to reference the class inside itself, using bar instead of Test.bar will work fine.
class Test:
#staticmethod
def bar():
pass
FOO_DICT = {1: bar}
# You can access this outside of the class by simply using Test.FOO_DICT
print(Test.FOO_DICT)
However, there are cases where you really need to use a class in itself.
For example
class Test:
#staticmethod
def bar():
pass
def test_with_other_of_same_instance(self, other: Test):
print(other.FOO_DICT)
FOO_DICT = {1: bar}
In this case,
I want to define a method that accepts an object of the same Test class.
I want to use python's type hinting to indicate that the expected argument is an instance of Test. This allows me get editor support and also so tools like pylance and mypy can notify me of possible errors if I passed a argument of wrong data type.
As at the time of this writing, I'll get a NameError: name 'Test' is not defined.
This is because by default I can't use a class within itself (It is possible later versions of python will change its default behavior, hence we won't be needing the solution below by that time).
But if you use Python versions from 3.7+ and you can't reference a class within itself, the simple solution came with PEP 563 - Postponed evaluation of annotations. It is implemented by adding a little line of code at the first line of the file
from __future__ import annotations
# other imports or code come afterwards
class Test:
#staticmethod
def bar():
pass
def test_with_other_of_same_instance(self, other: Test):
print(other.FOO_DICT)
FOO_DICT = {1: bar}
So you can use a class within itself in python by simply including that line at the beginning of the file.
Normally, if you use pylance or any similar tool, you get a warning or error display to show you that you imported something and didn't use it. But not in the case of annotations. You don't have to worry about any warning from your editor.
Note that this must occur at the beginning of the file otherwise you get a SyntaxError and versions earlier than 3.7 won't support this.
You could move FOO_DICT = {1 : Test.bar} outside of class like this:
class Test:
#staticmethod
def bar():
pass
Test.FOO_DICT = {1: Test.bar}

Only let function be called as a method in Python

Say I'm writing a module, MyPyLib, that uses another built-in module. From the built-in module, I import a class, Foo. I then define this function, bar:
def bar(self):
return self
This function is written to be a method of the Foo class and I can make it behave properly with setattr(Foo,'bar', bar). Then Foo.bar() will work as intended. However, anyone who imports MyPyLib can also call bar as its own function. Is there any way to limit this function so that Foo.bar() works, but bar(arg) doesn't?
Your code should not care about incorrect use, that's a problem for the caller. Python is a language for consenting adults; if someone wants to bend the rules and use bar with a different argument, that's their problem, not yours.
If you insist, your only option here is to explicitly test for the type of self:
def bar(self):
assert isinstance(self, Foo)
return self
as there is no way for bar to detect otherwise that it is being called as a bound method or used unbound.
An alternative (and more usual) approach is to derive a new class from class Foo and to define bar explicitly as a method of the new class:
class FooBar(Foo):
def bar(self):
return self
This way the intended usage of bar is much more clear.

In python how can I use/manipulate an object defined in a script from a function defined in an imported module?

This might be a terribly simple one, but I don't know what's the "right" answer. Assume that I have a script
import utils
bar = 1
utils.foo()
print bar
Furthermore, the module utils is:
def foo():
bar = bar+1
As given above, I ,obviously, get:
UnboundLocalError: local variable 'bar' referenced before assignment
How can I use bar inside foo()? In my specific case, I don't really want to alter foo, but I do need to be able to use it and its state inside foo().
One workaround would be to pass bar to foo():
def foo(bar):
return bar+1
And replace the third line in the script: bar = utils.foo(bar).
However, this feels like a cumbersome solution; in particular if bar is a complex object.
I am interested in a best-practice approach the case described above.
Why don't you want to alter foo? If you import a module, you want to use its functionality. If the foo function is without parameters, then bar or other variables in it are used in the module utils itself. If you want to use a function with values that are not inside the module, then:
def foo(bar):
return bar+1
is totally acceptable.
EDIT:
// When you create class foo1, just set bar in the constructor.
class foo1:
def init(self, bar):
self.bar = bar
Image this situation:
import someModule
# now you want to use a function of this module
foo()
Maybe then there would be an error like: bar is not defined or whatever --> modules are not loosely coupled. Either make the function foo as you proposed with parameters (totally acceptable) or set the bar value via a constructor or setBar method.
I am interested in a best-practice approach the case described above
As you describe, bar is an argument to foo, and the best practice way to pass an argument to a function is to pass it as an argument to the function.
in utils.py:
def foo(bar):
return bar+1
And in your other script:
import utils
bar = 1
bar = utils.foo(bar)
print bar
This is the best practice approach. It follows the correct semantics. It is also testable:
import unittest
import utils
class MyTest(unittest.TestCase):
def setUp(self):
self.bar = 1
def test_bar(self):
self.assertEquals(2, utils.foo(self.bar))

calling class/static method from class variable in python

I'm trying to make a ImageLoader class handle the loading and processing of image resources like this:
class ImageLoader:
TileTable = __loadTileTable('image path', some other variable)
#staticmethod
def _loadTileTable(arg1, arg2):
blah blah
however, on compile i get: NameError: name '_loadTileTable' is not defined
If i replace the second line with TileTable = ImageLoader.__loadTileTable('image path', some other variable) then i get NameError: name 'ImageLoader' is not defined
As i'm going from C# to Python, static classes with static methods is what i'd use to implement this. However, i'm open to how I'd do this in general in python (that is, call static library functions that are only grouped together by their functionality).
UPDATE:
After reading both answers, I'm getting a picture that what i'm trying to do probably isn't right.
How would I go about imlementing ImageLoader so that I can do this:
Assuming that tile table returned an array
module1.py
aTile = ImageLoader.TileTable[1]
module2.py
anotherTile = ImageLoader.TileTable[2]
ideally, i'd populate TileTable just once.
Update:
Thanks for all the answers, I found my last answer to populating TileTable just once in the python modules doco
"A module can contain executable
statements as well as function
definitions. These statements are
intended to initialize the module.
They are executed only the first time
the module is imported somewhere"
As for static class, i'm going to forgo classes and just make a module level variable.
Answering just the updated question, what you would do in Python is make TileTable a variable called tile_table in a module called imageloader. There is no reason at all to put any of this inside a class.
So then you get:
module1.py
import imageloader
aTile = imageloader.tile_table[1]
module2.py
import imageloader
anotherTile = imageloader.tile_table[2]
and imageload.py looks something like:
def _loadTileTable(arg1, arg2):
pass # blah blah
tile_table = _loadTileTable('image path', other_var)
Think of a Python module as a singleton instance in other languages (which in fact it is) and you'll be able to reconcile this with any OO preconceptions you inherited from other languages.
In Python, the code in the class block is first executed, then the resultant namespace is passed to the class initializer. The code you wrote could have also been written as:
TileTable = _loadTileTable(arg1, arg2)
#staticmethod
def _loadTileTable(arg1, arg2):
pass # blah blah
ImageLoader = type('ImageLoader', (), {'TileTable': TileTable, '_loadTileTable': _loadTileTable})
del TileTable
del _loadTileTable
As you can see, the call of _loadTileTable appears before the definition of it. In your example, within the class definition, the call to _loadTileTable must come after the definition of _loadTileTable.
One possible fix is to simply re-arrange the class definition.
class ImageLoader:
def _loadTileTable(arg1, arg2):
pass # blah, blah
TileTable = _loadTileTable('image path', other_var)
Note that I removed the 'staticmethod', because at the point where _loadTileTable is called, it's being called as a function and not a method. If you really want it to be available after class initialization, you can define it as a static method after the fact.
class ImageLoader:
def _loadTileTable(arg1, arg2):
pass # blah, blah
TileTable = _loadTileTable('image path', other_var)
_loadTileTable = staticmethod(_loadTileTable)
Class-level variables which get updated are a bad, bad thing. Our default expectation is that object instances are stateful and classes are stateless.
In this case, we're trying to "magically" initialize a collection as a class variable, which is a toweringly bad idea. A collection is simply an object with simple instance-level attributes.
The magical Tile Table should not be a concealed, static part of the ImageLoader. There is no possible reason for that. It should be an argument to the ImageLoader if you want to avoid loading it more than once.
Separating these promotes testability. It's not arbitrary. It's how unit testing gets done.
What you want is this.
class ImageLoader( object ):
def __init__( self, theTileTable ):
self.tile_table= theTileTable
class TileTable( object ):
def __init__( self, path, some_other_arg ):
self.tileTable= self._loadTileTable( path, some_other_arg )
def _loadTileTable(arg1, arg2):
blah blah
No static anything. Independent units. More easily testable. No weird dependencies. No magic.
Is there a design reason you're using a static method? If so, because you're not overloading the class initialization, you'll need to declare the variable after the method definition.
But, if you do this, you'lll get a new error:
NameError: name 'arg1' is not defined
The reason for this is because you're executing the method within the class before the class is even instantiated, therefore you never have a chance to pass the arguments to the method.
So, the proper way to do this is to overload the __init__() method so that assignment to TileTable only happens when the class is constructed:
class ImageLoader(object):
def __init__(self, arg1, arg2):
self.TileTable = self._loadTileTable(arg1, arg2)
#staticmethod
def _loadTileTable(arg1, arg2):
print arg1, arg2
This gives you the ability to call ImageLoader._loadTileTable() without having an instance, but then it also allows you to create the TileTable instance variable upon creating an instance.
Using a Class method
In response to my comment about the possible need for a classmethod, here is an example that covers this:
class ImageLoader:
#classmethod
def _loadTileTable(cls, arg1, arg2):
return arg1, arg2
# We're creating the class variable outside of the class definition. If you're doing
# this in a module, no one will ever notice.
ImageLoader.TileTable = ImageLoader._loadTileTable('foo', 'bar')
There might be a better way to do this, I don't know. But I do think that this covers what you are looking for:
>>> i = ImageLoader()
>>> i
<__main__.ImageLoader instance at 0x100488f80>
>>> ImageLoader.TileTable
('foo', 'bar')
>>> i.TileTable
('foo', 'bar')
There you have an instance i that has access to the class variable, but ImageLoader.TileTable is still available from the class object without the need for an instance.

Python - how can I override the functionality of a class before it's imported by a different module?

I have a class that's being imported in module_x for instantiation, but first I want to override one of the class's methods to include a specific feature dynamically (inside some middleware that runs before module_x is loaded.
Neither AndiDog's nor Andrew's answer answer your question completely. But they have given the most important tools to be able to solve your problem (+1 to both). I will be using one of their suggestions in my answer:
You will need 3 files:
File 1: myClass.py
class C:
def func(self):
#do something
File 2: importer.py
from myClass import *
def changeFunc():
A = C()
A.func = lambda : "I like pi"
return A
if __name__ == "importer":
A = changeFunc()
File 3: module_x.py
from importer import *
print A.func()
The output of module_x would print "I like pi"
Hope this helps
You should know that each class type (like C in class C: ...) is an object, so you can simply overwrite the class methods. As long as instances don't overwrite their own methods (won't happen too often because that's not really useful for single inntances), each instance uses the methods as inherited from its class type. This way, you can even replace a method after an instance has been created.
For example:
class C:
def m(self):
print "original"
c1 = C()
c1.m() # prints "original"
def replacement(self):
print "replaced!"
C.m = replacement
c1.m() # prints "replaced!"
C().m() # prints "replaced!"
Since every python class is actually a dictionary (not only objects!)
You can easily override class methods by associate them with new function.
class A:
def f(self):
return 5
a = A()
a.f() #5
A.f = lambda self: 10
a.f() #10
You should use it with care. In most cases decorators & proper OO-design will work for you and if you forced to override class method, maybe, you make something wrong.

Categories

Resources