Why doesn`t this work:
class X:
var1 = 1
def __enter__(self): pass
def __exit__(self, type, value, traceback): pass
with X() as z:
print z.var1
I get:
print z.var1
AttributeError: 'NoneType' object has no attribute 'var1'
Change the definition of X to
class X(object):
var1 = 1
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
pass
with assigns the return value of the __enter__() method to the name after as. Your __enter__() returned None, which was assigned to z.
I also changed the class to a new-style class (which is not critical to make it work).
See the docs for context managers:
__enter__( ) Enter the runtime context and return either this object or
another object related to the runtime
context. The value returned by this
method is bound to the identifier in
the as clause of with statements using
this context manager. An example of a
context manager that returns itself is
a file object. File objects return
themselves from __enter__() to allow
open() to be used as the context
expression in a with statement.
An example of a context manager that
returns a related object is the one
returned by
decimal.Context.get_manager(). These
managers set the active decimal
context to a copy of the original
decimal context and then return the
copy. This allows changes to be made
to the current decimal context in the
body of the with statement without
affecting code outside the with
statement.
Your __enter__ method doesn't return anything, which is the same as returning None.
The function you've defined between 'with' and 'as' must have and only have one return value. 'with' will pass the value to its built-in method __enter__().
A class-type object in Python will not return any value if not defined when you called it.
Similarly, if you called a class-type object with its method that returns nothing, it will also throw out exception.
You can't write like this:
with open('file.txt').readlines() as lines:
This generated two return values, and it's even not allowed to pass to one variable in Python.
But this is good to use:
with open('file.txt') as f:
lines = f.readlines()
Related
What is static method and how can we explain the below code ?
#staticmethod
def get_model(**kwargs):
try:
return Model.objects.get(**kwargs)
except Model.DoesNotExist:
return
In short and maybe oversimplified: staticmethod doesn't require object of a class to run. This also means that you don't need self argument.
About the code:
This method is attempting to return single (.get()) instance of a Model that match with parameters specified in kwargs.
example:
kwargs = {"id":5, "is_alive": True}
Model.objects.get(**kwargs)
#is the same as
Model.objects.get(id=5, is_alive=True)
This can raise Model.DoesNotExists error if there is no instances of Model matching with paramaters so try/except is used.
If Model.DoesNotExists error is raised then method return None.
A staticmethod is a function not bound to an object, but is encapsulated within it ( typically to reduce outer namespace clutter, or eliminate any need to import it). It doesn't have the first self argument that a normal object method does.
I was learning Python by using Python Crash Course and came upon this String and Method thing: It only said that the dot(.) after name in name.title() tells Python to make the title() method act on the variable name.
Not always, you can create a method dynamically:
from types import MethodType
def fn(x):
return x.var
class A:
def __init__(self):
self.var = 20
obj = A()
method_ = MethodType(fn, obj)
print(method_)
print(method_())
output :
<bound method fn of <__main__.A object at 0x000001C5E3F01FD0>>
20
A method is an instance of type MethodType and also it has an object bound to it, when method gets called, it's first parameter will always get filled with that object. Here fn() function's first parameter (x) will be filled with obj object.
The above answer is precise but i wanted to add to it.
Actually methods are functions that take objects as arguments and then return values based on that and as python is an Object Oriented Language therefore everything in python is an object.
When you call name.title():
then, python search for the title() method for the name object.And as all methods are designated to take the object as an argument:
`def title(self):
...+
`
This is what a method definition look like inside a class and the self argument here stands for the object calling the method.
And we do not have to specify it explicitly it is recognised by the python interpreter.
As in your case: name.title() the object calling the method title() is the name variable therefore here self is assigned the value of name that is the function call name.title() is equivalent to title(name) but the former is the correct syntax of calling the method whereas the latter one is for comprehesion purpose.
If you run title(name) it surely gonna raise an error.
But, as the title() method belongs to the str class you can always call str.title(name).
Hope i didn't confuse you instead of making it clearer...Happy coding..:)
i meet this code today, and it seems confusing
class ClassOne:
def __init__(self,some_object):
self.not_important_attribute=some_object
class ClassTwo:
def __init__(self,some_object):
self.tmp=ClassOne(some_object)
def __getattr__(self,attr):
return getattr(self.tmp,attr)
a=ClassTwo('not_important_string')
print(getattr(a,'undefined_attribute',3))
When we use getattr at the last line we trigger the __getattr__ method in the SubClass , then delegate to the getattr(self.tmp,attr) function which will raise an exception if the attribute is undefined and no default value was given. But how the value 3 at the last line still go through all the process, and eventually return to getattr(a,'undefined_attribute',3) function ?. Because we didn't have a slot for the default value when we delegate getattr(self.tmp,attr), how is that possible ?
In your case
getattr(self.tmp,attr)
raises AttributeError and if getattr has third argument(default value) then it return default value instead of raising AttributeError
Step by step why 3 value is shown:
the super class has has an atribute not_important_attribute and it is set when the constructor is called
class ClassOne:
def __init__(self,some_object):
self.not_important_attribute=some_object
Here, in the ClassTwo contructor, you create an instance of ClassOne and save it into tmp variable. Meaning that when you overrides __getattr__ you will be asking for the value of attribute of ClassOne
print(getattr(a,'not_important_attribute',3))
not_important_string # founds the method
print(getattr(a,'any',3))
3 #doesn't found method, returns default
That is the same of directly do:
b = ClassOne("not_important_string")
print(getattr(b,'not_important_attribute',3))
not_important_string # founds the method
print(getattr(b,'any',3))
3 # doesn't found method, returns default
When calling getattr(a,'undefined_attribute',3) you are calling the standard python getattr function and pass it a default value. This actually wraps your custom getattr in ClassTwo. We can see that by modifying getattr al little bit.
def __getattr__(self, attr, *args, **kwargs):
print(args) # -> empty
print(kwargs) # -> empty
return getattr(self.tmp, attr)
You can actually go around that wrapping and call getattr from ClassTwo directly, by using print(a.__getattr__('undefined_attribute', 3)). This method would raise an Exception.
So essentially getattr(a,'undefined_attribute',3) is the standard python method that internally calls the custom getattr from ClassTwo.
class ClassTwo:
...
def __getattr__(self,attr):
return getattr(self.tmp,attr)
getattr(a,'undefined_attribute',3) method is a wrapper to call __getattribute__ and if __getattribute__ fails, it will call __getattr__. It is implemented with handling of exception AttributeError. In your case, getattr(a,'undefined_attribute',3) calls ClassTwo.__getattr__ above.
It seems you think when it reaches return getattr(self.tmp,attr), it will throw errors or return some kind of errors and break and stop at that point complete. However, in python, program will pass exception up the call stack. Along the upstream of the call stack, if that exception gets handle, it will exit/complete normally. In this case, AttributeError get passed back along the call stack to getattr(a,'undefined_attribute',3). this getattr has default value for AttributeError so it returns 3 and exits normally.
I am writing a class for a neural network and I want to give it some form of customization, so that you can choose different cost functions and regularizations. For this I want to set them as default parameters in the __init__() method.
But when I pass MyClass.static_method in my example, the Interpreter then tells me that MyClass is not (yet) defined. Why is this and is there a nicer workaround than mine?
You can of course just set the static method as a default parameter, but then other problems arise. For example, if I want to access the functions name (which I actually want), I cannot use __name__ rightaway. I know how to do it another way, by accessing static_method.__func__.__name__. But this seems clumsy and as you get a staticmethod object, seems like its not intended to be used this way.
class MyClass:
#staticmethod
def static_method():
do_something()
def __init__(self, func=MyClass.static_method, func2=static_method):
self.name = func.__name__ #Does not work
self.name2 = func2.__func__.__name__ #Should work
I did expect for the MyClass.static_method to work, but the class does not seem to exist then. So, one last time, why?
The reason you're having problems with your static method usage as a default argument is due to a combination of two issues.
The first issue is that the default argument needs to be well defined when the def statement is run, not only when the function is called. That's because the default argument gets built into the function object, rather than being recalculated each time the function runs (this is the same reason why a mutable default argument like an empty list is often an error). Anyway, this is why you can't use MyClass.static_method as the default argument, since MyClass isn't defined yet when the function is being defined (the class object is only made after all its contents have been created).
The next issue is that a staticmethod object doesn't have all the same attributes and methods as a regular function. Normally this doesn't matter, as when you access it through a class object (e.g. MyClass.static_method once MyClass exists) or through an instance (e.g. self.static_method), it will be callable and have a __name__. But that's because you get the underlying function in those situations, rather than the staticmethod object itself. The staticmethod object itself is a descriptor, but not a callable.
So neither of these functions will work correctly:
class MyClass:
#staticmethod
def static_method():
pass
def foo(self, func=MyClass.static_method): # won't work because MyClass doesn't exist yet
pass
def bar(self, func=static_method): # this declaration will work (if you comment out foo)
name = func.__name__ # but this doesn't work when the bar() is called
func() # nor this, as func is the staticmethod object
What does work would be to use the actual function underlying the staticmethod object as the default:
def baz(self, func=static_method.__func__): # this works!
name = func.__name__
func()
This also works when you pass in some other function (or bound method), unlike the version of your code that used name = func.__func__.__name__.
DEFAULT = object()
class MyClass:
#staticmethod
def static_method():
do_something()
def __init__(self, func=DEFAULT, func2=DEFAULT):
self.name = self.static_method.__name__ if func is DEFAULT else func.__name__
self.name2 = self.static_method.__func__.__name__ if func2 is DEFAULT else func2.__func__.__name__
I guess??
From Learning Python:
The basic format of the with statement looks like this, with an
optional part in square brackets here:
with expression [as variable]:
with-block
The expression here is assumed to return an object that supports the
context management protocol (more on this protocol in a moment).
This object may also return a value that will be assigned to the name variable if the optional as clause is present.
Note that the variable is not necessarily assigned the result of
the expression; the result of the expression is the object that
supports the context protocol, and the variable may be assigned
something else intended to be used inside the statement.
expression is evaluated to a context manager object.
What is assigned to variable? The quote only says that it is not a context manager object.
Does the assignment to variable call some method of a context manager class to produce the actual value assigned to variable?
Thanks.
Whatever is returned from __enter__. From the documentation on the __enter__ method of context managers:
contextmanager.__enter__()
Enter the runtime context and return either this object or another object related to the runtime context. The value returned by this method is bound to the identifier in the as clause of with statements using this context manager.
(Emphasis mine)
The result of calling __enter__ could very well be a context manager, nothing in the specification forbids this. It could of course be another object related to the runtime context, as the docs state.
Objects that return themselves from __enter__ can be used again and again as context managers. file objects, for example:
with open('test_file') as f1: # file.__enter__ returns self
with f1 as f2: # use it again, get __self__ back
print("Super context managing")
with f2 as f3, f1 as f4: # getting weird.
print("This can go on since f1.__enter__ returns f1")
print("f1.__exit__ has been called here, though :)")
print("f1 closed: {}".format(f1.closed))
Not that the previous made much sense but just to make the point clear.
Your object can function as a context manager if it provides both __enter__ and __exit__. The object returned by __enter__ is bound to the object you specify in the as part of the with statement:
In [1]: class Foo:
...: def __enter__(self):
...: return 'hello'
...: def __exit__(self, *args):
...: pass
...:
In [2]: with Foo() as a:
...: print(a)
...:
hello