Defer variable initialization until evaluation - python

I need a way to defer the initialization of a global variable until the firs access to it, the overall idea is expressed in the following Python pseudocode:
FOO = bar
FOO.some_method_on_bar() # Init bar: bar = Bar(); bar.some_method_on_bar()
FOO.some_method_on_bar() # Use cached bar: bar.some_method_on_bar()
So far I'm thinking of somehow telling Python to call a special class method every time its instance is evaluated, but I can't seem to google it up:
class LazyGetter:
def __init__(self, get_value) -> None:
self.get_value = get_value
def __class__instance__access__(self):
return self.get_value()
FOO = LazyGetter(get_value=lambda: Bar())
FOO # = LazyGetter.__class__instance__access__()
FOO.some_method_on_bar() # = LazyGetter.__class__instance__access__().some_method_on_bar()
So, basically I need to know if there's something equivalent to the madeup __class__instance__access__ method.

If you have to defer initialization, you may be doing too much in the __init__ method. But if you don't control that code, then you seem to be needing something like a proxy class, so you can do:
proxied_bar = Proxy(Bar)
...
proxied_bar.some_bar_method() # this would initialize Bar, if it isn't yet initialized, and then call the some_bar_method
One way to do so, see: Python proxy class
In that answer an instantiated object is proxied (rather than the class), so you have to make some modifications if you want to defer the __init__ call.

Since Python 3.7, one can define a module __getattr__ method to programmatically provide "global" attributes. Earlier and more generally, one can define a custom module type to provide such a method.
Assuming that Bar() is needed to initialise the global FOO, the following __getattr__ at module scope can be used.
# can type-annotate to "hint" that FOO will exist at some point
FOO: Bar
# called if module.<item> fails
def __getattr__(item: str):
if item == "FOO":
global FOO # add FOO to global scope
FOO = Bar()
return FOO
raise AttributeError(f"module {__name__!r} has no attribute {item!r}")
This makes FOO available programmatically when accessed as an attribute, i.e. as module.FOO or an import. It is only available in the global scope after the first such access.
If the access to FOO is expected to happen inside the module first, it is easier to provide a "getter" function instead.
def get_FOO() -> Bar:
global _FOO
try:
return _FOO
except NameError:
_FOO = Bar()
return _FOO

You might want to consider just having an actual global variable and accessing it with global <variable> but I can't say if that fits the use-case. It should work fine if you're just looking for some caching logic.
You might be able to do this with metaclasses which is a way of modifying a class when it's instantiated. Whether this is useful depends on what you're trying to achieve.

If you control the class code, you can use __getattribute__ to delay initialization until the first time you access an attribute.
class Bar:
def __init__(self, *args):
self._args = args
def __getattribute__(self, name):
args = super().__getattribute__('_args')
if args is not None:
# Initialize the object here.
self.data = args[0]
self.args = None
return super().__getattribute__(name)
def some_method_on_bar(self):
return self.data

Related

Can I assign a member function to a local variable in a python class

I have a class;
class Foo:
bar = fooFunc
def fooFunc():
return True
The linter complains: fooFunc is not defined. What could I be missing. Thanks
This seems logical: the code gets executed sequentially. If you want to use fooFunc, you have to define it first! Simply try
class Foo:
def fooFunc():
pass
bar = fooFunc
Also, note that a function defined in a class by default will be a method, so it should accept at least self. If you just want to put it there for namespacing reasons, you should make it a staticmethod instead.

Is it possible to raise Exception if function is not called

For some given class in python like:
class Foo:
def __init__(self, ...):
...
pass
def not_raising_1(self, ...):
...
pass
def not_raising_2(self, ...):
...
pass
is it possible to enforce that the user has to call not_raising_1() or not_raising_2() after creating an object of type Foo. So I'm thinking of a behavior:
foo = Foo(...) # will raise a Exception saying you need to call not_raising_1 or not_raising_1
foo = Foo(...).not_raising_1(...) # will NOT raise a Excpetion
foo = Foo(...).not_raising_2(...) # will NOT raise a Excpetion
I know that a pragmatic solution would obviously be to put what ever should happen in not_raising_1() or not_raising_2() with some parameter in the constructor of Foo. But I'm here not asking for a pragmatic solution but am just curios if someone can think of some creative solution to get the described behavior.
First, for the record: if the two methods must be called before the object is ready to be used, that means that calling them is part of the initialization of the object, and so they should be called by __init__ itself:
class Foo:
def __init__(self, ...):
...
self.not_raising_1()
self.not_raising_2()
def not_raising_1(self, ...):
...
def not_raising_2(self, ...):
...
But, moving on to the question as asked...
The problem is not well defined.
Unless you call the methods inside __init__ itself, it is trivially true that neither method has been called the instant __init__ exits.
Further, once __init__ exits, the class Foo has no visibility into what happens outside its own definition. You need some sort of explicit state that maintains what happens after Foo.__init__ exits. Foo.not_raising_1 could examine that state to determine if anything else happened before it was called.
But that raises another problem: who will update that state? Every single bit of code would have to cooperate with Foo. Is this illegal?
x = Foo()
y = 3
x.not_raising_1()
Then how are you going to make Python update your state when it executes y = 3? The hooks just aren't there.
And finally, who is going to raise the exception if x.not_raising_1 is never called?
Refine the problem.
Rather than ask if the functions are never called, you can ensure they are called inside a with statement using an appropriately defined context manager. This context manager can ensure that not_raising_1 and not_raising_2 are called before the with statement completes, as well as ensure that they are only used inside a with statement. You can't enforce that the object is used as a context manager, but you can ensure that it is only used in a with statement.
class Foo:
def __init__(self, ...):
...
self._in_with_statement = False
self._r1_called = False
self._r2_called = False
def not_raising_1(self, ...):
self._r1_called = True
if not self._in_with_statement
raise RuntimeException("Foo instance must be used with context manager")
def not_raising_2(self, ...):
self._r2_called = True
if not self._in_with_statement
raise RuntimeException("Foo instance must be used with context manager")
def something_else(self):
if not self._r1_called or not self._r2_called:
raise RuntimeException("Failed to call not_raising_1 and/or not_raising_2")
...
def __enter__(self):
self._in_with_statement = True
def __exit__(self):
self._in_with_statement = False
if not self._r1_called or not self._r2_called:
raise RuntimeException("Failed to call not_raising_1 and/or not_raising_2")
self._r1_called = False
self._r2_called = False
Here, __init__ sets the condition that neither method has yet been called, nor are we yet executing in a with statement. The instance itself acts as the external state that monitors how the instance is used.
The two required methods require themselves to be executed inside a with statement (by checking if __enter__ has been called).
Every other method can check if the required methods have been called.
The __enter__ method simply marks the object as now being in a with statement, allowing the required methods to be called.
The __exit_ method ensures that the required methods were eventually called, and resets the state of the object as being outside a context manger.
I think this is as strong a guarantee as you can enforce, short of a class that uses the inspect module to examine the script's source code looking for violations.
You could use a classmethod like this:
class Foo:
def __init__(self, flag=True):
if flag:
raise CustomError()
#classmethod
def not_raising_1(cls):
return cls(flag=False)
Thus foo = Foo() or foo = Foo(...).not_raising_1(...) would still raise the exception, but foo = Foo.not_raising_1(...) would work.
It's not possible. You could use a workaround as that one suggested by Ajay Signh Rana or chepner but I would, personally, not recommend it as it is hard to grasp when reading the code.
Your goal should be to increase readability and usability of the class for yourself and other programmers that uses this class. Use well-known patterns and concepts whenever possible and if applicable.
Reading your question, I understand that the object is not ready to use until one of the other methods is invoked. You could consider Julian Fock's answer and use a class method.
Or use any of the other Creational Design Patterns:
https://refactoring.guru/design-patterns/creational-patterns
Depending on the reason why you want to achieve this behaviour, you could consider to implement the Builder pattern:
https://refactoring.guru/design-patterns/builder/python/example
https://stackoverflow.com/a/26193004/42659
Builder pattern equivalent in Python
A third alternative would be, as you mention yourself, that you pass some parameters along when invoking the constructor and call, depending on the parameter, either of the other methods within the constructor.
Which approach is usable and applicable for your situation depends on your needs and bigger picture than the example in your Question. You should choose the approach that suits your needs best and is most readable.
I did get your question but as others suggested it cannot be done. But yeah you wann raise an exception and it should be raised if the function isn't call then you must create another function that checks if the previous functions were called or not and if not you can raise the exception.
I would approach this problem by creating a variable that changes it's value based on the funciton calls and if the functions haven't been called we can determine that as well.
Try:
class SomeError(Exception):
pass
class Foo:
def __init__(self, ...):
self.flag = False # set the flag to false for each object initially
...
pass
def not_raising_1(self, ...):
self.flag = True # set it to true once the function has been called
...
pass
def not_raising_2(self, ...):
self.flag = True # repeat for this on too
...
pass
def raise_exception(self):
if(not self.flag):
raise SomeError
obj1 = Foo()
obj1.not_raising_1()
obj1.raise_exception() # won't do anything
obj2 = Foo()
obj2.raise_exception() # would raise exception as either of the two functions weren't called
As others have suggested, it's not something that you should consider in actual code. But Just as an excercise, I tried doing something similar:
class NoError(Exception):
pass
class Foo:
def __init__(self):
pass
def not_raising_1(self):
raise NoError()
def not_raising_2(self):
raise NoError()
How to use:
try:
Foo()
raise Exception('please use either not_raising_1 or not_raising_2')
except NoError:
print('No error')
# actual code

Mocking a Python object without method calls

Imagine a class like so:
class Foo():
def method_1(self):
bar = Bar()
bazz = Bazz(bar)
return bazz.method_2()
For unit testing, how can we mock the Bar object when we never call any methods on it, we're just passing it as a parameter to the Bazz constructor? (Yes, this is not ideal, but this pattern can be found in a top-level class wiring together different objects via dependency injection).
You do call the Bar object, when you execute: bar = Bar(), so you can easily mock it:
mock_bar = mocker.MagicMock(name='Bar')
mocker.patch('foo.Bar', new=mock_bar)
# mock_foo.return_value = the new mocked object

Do class/static variables have access to static methods?

Forgive me if this question is obvious, but from what I've read on Python's OOP tutorials none of them mention how to have a static variable store a static method. In my code I tried:
class Features:
a_static_variable = 1
a_static_variable_that_references_a_static_function = Features.func1
#staticmethod
def func1(blah):
print(blah)
When trying to run this I received:
NameError: name 'Features' is not defined
Is it possible for a class method to reference a static method in its own class? If so, how do I do this. I tried replacing Features with nothing and self but as I expected those made no sense as well.
This is simply a case of func1 not being defined yet.
It should work if you reorder:
class Features:
a_static_variable = 1
#staticmethod
def func1(blah):
print(blah)
a_static_variable_that_references_a_static_function = func1
Yes, just define the function first:
class Features:
#staticmethod
def func1(blah):
print(blah)
a_static_variable = 1
a_static_variable_that_references_a_static_function = func1
Features.a_static_variable_that_references_a_static_function('test')
Your code has two errors (explained in the other answers). This example may help you understand what's going on.
class Example:
class_variable = 'class_variable'
#staticmethod
def static_method():
print('static_method')
class_method = static_method
print(locals())
def instance_method(self):
print(instance_method)
print(locals())
When this code is run, without instantiating a member of this class, the output is:
creating the class:
{'class_variable': 'class_variable',
'__module__': '__main__',
'static_method': <staticmethod object at 0x0135E5F0>,
'class_method': <staticmethod object at 0x0135E5F0>
}
So, while creating the class, a scope is created in which all of the names in that dictionary are accessible.
Now let's look at what happens when we do this:
example = Example()
example.instance_method()
Nothing happens when you instantiate an object, but calling instance_method will print the local variable(s) accessible to that scope.
instance_method
{'self': <__main__.Example instance at 0x01810210>}
Now, you are probably used to creating instance methods that reference class variables.
def other_instance_method(self):
print(Example.class_variable)
Here, Example is not present in the local scope. In order to find it, the global scope needs to be searched (i.e. globals). Note that instead of explicitly referencing Example, we could access the the class variable from the self object itself.
def other_instance_method(self):
print(self.class_variable)
You can do some testing yourself by printing locals() and globals() from various places to get a grip on how the scope changes.

In python, how to store 'constants' for functions only once?

Some function need 'constant' values (ie. not designed to be redefined later) that are not to be parametrized. While default arguments are stored only once for each function, some are just not very meaningful to be put as parameters (ie. to be part of the signature). For (a not very useful) example:
def foo(bar):
my_map = {"rab": barType, "oof": fooType}
return my_map.get(bar,defaultType)()
It wasted CPU time and RAM space to re-define such a constant for each call. Some other ways are to store such constants as module level globals or make the function a callable class, but there may be other ways, maybe?
When doing the module level global way, I prefix my (meant as a) constant variable with a "_" to show that it is there not for anyone's interest. Still I feel the module namespace slightly "polluted", not to speak of the shame of using something as discouraged as globals at all:
_my_map = {"rab": barType, "oof": fooType}
def foo(bar):
return _my_map.get(bar,defaultType)()
Or the transform it into a class way. I make the __call__ a classmethod, to avoid the need of creating instances:
class foo:
my_map = {"rab": barType, "oof": fooType}
#classmethod
def __call__(cls,bar):
return cls.my_map.get(bar,defaultType)()
Are these solutions pythonic enough?
Are there other ways to do this?
Is it even ok as a practice to use such 'constants'?
Note these objects in my examples are not necessarily actual constants, but used (and could be thought) as such by their purpose.
Set it as an attribute on the function:
def foo(bar):
return foo.my_map.get(bar, defaultType)()
foo.my_map = {"rab": barType, "oof": fooType}
A callable class or a closure is not simple enough IMO.
IMHO, there is nothing wrong with module level constants.
Note that according to PEP 8, constants should be all upper case, like this:
_MY_MAP = {"rab": barType, "oof": fooType}
def foo(bar):
return _MY_MAP.get(bar,defaultType)()
The regular expression module in the standard library uses this style and many established third-party libraries do as well. If you are not convinced, just go to your site-packages directory and grep:
egrep "^_?[A-Z]+ =" *
You could also use closures:
def make_foo():
my_map = {"rab": barType, "oof": fooType}
def foo(bar):
return my_map.get(bar,defaultType)()
return foo
foo = make_foo()
To make something that is as self-contained as possible. You could create a function object (aka functor) class and give it a __call__() method or a classmethod (but probably not both):
class bazType(object): pass
class barType(object): pass
class fooType(object): pass
class Foo(object):
_DEFAULT_TYPE = bazType
_MY_MAP = {"rab": barType, "oof": fooType}
def __call__(self, bar):
return self._MY_MAP.get(bar, self._DEFAULT_TYPE)()
#classmethod
def foo(cls, bar):
return cls._MY_MAP.get(bar, cls._DEFAULT_TYPE)()
# using classmethod
print Foo.foo("rab")
# using __call__ method
foo = Foo()
print foo("baz")
# alternative way to use classmethod
foo = Foo.foo
print foo("oof")
Yet another alternative would be to define a staticmethod, which I won't illustrate because it's so similar to the other two -- but you get the idea I hope.

Categories