Why changing object itself through class object doesn't work? - python-3.x

class Cat:
def func(self):
self = None
a = Cat()
print(a)
a.func()
print(a)
I thought I would get None with second print function, but I got same object addresses for both prints. Why can't I modify object with class method?

In the class method, self is an argument that becomes part of the local scope. Assigning to any local scope variable only changes the local scope. If you were to assign to an attribute of self such as
self.foo = “Bar”
Then you would modify the object itself.
Furthermore, the object is referenced by a in the calling (global) scope and that reference would prevent destruction of the object.
Put another way, self and a both refer to the same object and assigning self=None only removes one of those references.

Related

finding the caller object given its name only

I want to find the caller callable from within the called object, without explcitely forwarding the caller to the called as an object.
My current code looks something like this:
class Boo:
#classmethod
def foo(cls, aa, b2=2):
_ret = aa + b2
autolog(fn=Boo.foo, values={"input": locals(), "output": _ret}, message="This is what it should look like")
autolog_nameless(values={"input": locals(), "output": _ret}, message="This would be convenient")
return _ret
and yields
DEBUG | Boo.foo with aa=3.14159, b2=2 yields 5.14159. Message: This is what it should look like
DEBUG | cls=<class '__main__.Boo'>, aa=3.14159, b2=2, _ret=5.14159 yields 5.14159. Message: This would be convenient
The method autolog gets the locals() and the caller method fn, and parses them using the signature of the caller. This works nice and provides the desired output, but requires passing the caller as an object - something I'd like to avoid as I'm refractoring to include this feature and have about 1000 places to modify.
What I'd like to achieve is: pass locals() only; get the name of the caller within autolog_nameless, using inspect.stack()[1][3] or rather inspect.currentframe().f_back.f_code.co_name (latter has much less overhead), and using this - an possibly the information in locals() - find the caller object to inspect it for its signature.
The method autolog_nameless gets cls, actually the class as part of locals() (or would get self if the caller was a simple method), but I can't really do anything with it.
I'd think all the information required is given, but I just can't find a solution. Any help is greatly appreciated.
As it turns out it's quite simple: listing the methods of the class object found in locals() and searching by name should do the trick.
Code, without error checking:
# getting all methods of the class
methods = inspect.getmembers(locals()['cls'], predicate=inspect.ismethod)
# finding the callers name; won't work within the list comprehension for scope issues
_name = inspect.currentframe().f_back.f_code.co_name
# methods is a list of tuples, each tuple holds the name and the method object
fn = [x for x in methods if x[0] == _name][0][1]
and fn is the caller object to check the signature.
Note, locals()['cls'] works here as in the example we have a classmethod, but this is just the object that the called method belongs to.

Python Qt inheritance between Classes - AttributeError: type object 'Ui_QMainWindow' has no attribute [duplicate]

Declaring a variable in a class (outside of a function): all class functions can access it (basically a public variable)
Declaring a variable inside a function inside a class: only that function can access it (it's in that function's scope)
Declaring a variable with self.(variable name) inside a function inside a class: all class functions can access it (how is this different from global (variable name)?)
And since there is no private/protected, everything is public, so everything accessible from inside a class is accessible from outside the class.
Are there any other nuances I should know, or have I pretty much got it?
Since the listing in your question is not 100% clear, I've decided to explain it with a simple example. It also includes some things like __something variables you did not mention in your list.
class Test:
a = None
b = None
def __init__(self, a):
print self.a
self.a = a
self._x = 123
self.__y = 123
b = 'meow'
At the beginning, a and b are only variables defined for the class itself - accessible via Test.a and Test.b and not specific to any instance.
When creating an instance of that class (which results in __init__ being executed):
print self.a doesn't find an instance variable and thus returns the class variable
self.a = a: a new instance variable a is created. This shadows the class variable so self.a will now reference the instance variable; to access the class variable you now have to use Test.a
The assignment to self._x creates a new instance variable. It's considered "not part of the public API" (aka protected) but technically it has no different behaviour.
The assignment to self.__y creates a new instance variable named _Test__y, i.e. its name is mangled so unless you use the mangled name it cannot be accessed from outside the class. This could be used for "private" variables.
The assignment to b creates a local variable. It is not available from anywhere but the __init__ function as it's not saved in the instance, class or global scope.
Declaring a variable at the top level of the class is like declaring a static or class variable. Qualifying it with self is declaring an instance variable. Class variables can be modified by referring to them by class name (e.g. Class.x = 5) and all instances will inherit these changes. Instance variables are private to an instance and can only be modified by that instance.
You can achieve some level of access control using underscores. See private variables in the Python tutorial. By convention, variables starting with one underscore, e.g. _foo are non-public parts of an API, and names starting with two underscores e.g. __foo will have it's name mangled to be _classname__foo.
Although answered, let me add some comments to your questions:
Declaring a variable in a class (outside of a function) : all class functions can access it (basically a public variable)
This is like a static variable and can be called using the class name. These variables are available to all functions, any functions can modify it and print it.
Declaring a variable inside a function inside a class : only that function can access it (it's in that function's scope):
If the variable is declared without self then it is accessible within that function only, like a local variable. However, if it was declared using self like self.var= 'somevalue', then it is accessible via any object but not via the class name.
Declaring a variable with self.(variable name) inside a function inside a class : all class functions can access it (how is this different from global (variable name)?)
See answer in the above part.
And since there is no private / protected, everything is public, so everything accessible from inside a class is accessible from outside the class
Yes, but we can use single underscore to tell the world this variable is private, but technically that actually doesn't make it private.
we can use the scope in this for as :
case 1: In the Class
class test:
def __init__(self, a):
self.__elements = a
def change_a(self): self.__elements = 5
case 2 : Outside class
t = test(5)
This will access by as object._classname__privatevaribalename
print(t._test__elements)
this will print the change value of a

How to set coc-pyright to not warn for unused self parameter in a method?

I'm using the coc-pyright extension of CoC in neovim.
There are cases where we have an instance method in a class that doesn't need to access self variables. For example, I may have some variables in __init__ method which do not need to be accessed anywhere else in the class. As a toy example, consider,
class Example:
def __init__(self, some_var):
self.another_var = self.process_var(some_var)
def process_var(self, some_var):
return some_var*2
Now, here pyright warns me that self is not accessed. Is there a way to set Pyright to not give a warning in such cases?
P.S. The variable being passed is an instance-specific variable. So self would be required to make it an instance variable, right?
So you're passing some_var to the method instead of using it as an instance variable, meaning you don't actually need self. You are using process_var as a static method, as it is being passed all of the data it needs. You can use the static method decorator and remove self like so:
class Example:
def __init__(self, some_var):
self.another_var = self.process_var(some_var)
#staticmethod
def process_var(some_var):
return some_var*2
If you were to instead use the instance variable it would look like this
class Example:
def __init__(self, some_var):
self.some_var = some_var
self.another_var = self.process_var()
def process_var(self):
return self.some_var*2
The static method approach is much cleaner here as by using instance variables you need to be aware of what the current state of some_var is before you call process_var, otherwise the results will vary.
You can set reportUnusedVariable to false in your pyrightconfig.json file, but I wouldn't recommend this as pyright is giving you valuable information about how to restructure your code.

how to access class' attribute instead of objects

suppose you have
class c:
pass
print(c.__call__)
output: <method-wrapper '__call__' of type object at 0x0000023378F28DC8>
my problem is I cannot get the same output if __call__ is defined
like so:
class c:
__call__ = lambda self: None
print(c.__call__)
output: <function c.<lambda> at 0x000002337A069B70>
and neither type.__getattribute__(c, '__call__') works
to conclude, I want first output in both examples
is it possible (I guess through some metaprogramming)
This is the same issue you could have with a class variable and an instance variable with the same name:
class Test:
var = 1 # class variable
def __init__(self):
self.var = 2 # instance variable with the same name
t = Test()
print(t.var) # prints 2, the instance variable, not the class variable
print(Test.var) # prints 1, the class variable
In your first exmaple, the __call__ method is defined in the metaclass, type. You're accessing it though an instance of type, the class c. If you define a class variable in c, it's essentially an instance variable in the metaclass perspective, so you can't see the version defined in the metaclass any more.
As in my class variable code above, the best way to get the __call__ method from the metaclass is to name it directly directly: type.__call__. If you think you might have some other metaclass, you could call type on the class, to get the metaclass without naming it: type(c).__call__.
Note that the type.__call__ method gets run in different situations than a __call__ method defined in a normal class. The interpreter runs type.__call__ when you call the class, e.g. c(), while c.__call__ gets run when you call an instance:
obj = c() # this is type.__call__
obj() # this is where c.__call__ runs

Object deletes reference to self

Does Python interpreter gracefully handles cases where an object instance deletes the last reference to itself?
Consider the following (admittedly useless) module:
all_instances = []
class A(object):
def __init__(self):
global all_instances
all_instances.append(self)
def delete_me(self):
global all_instances
self.context = "I'm still here"
all_instances.remove(self)
print self.context
and now the usage:
import the_module
a = the_module.A()
the_deletion_func = a.delete_me
del a
the_deletion_func()
This would still print I'm still here, but is there a race condition with Python's garbage collector which is about to collect the object instance?Does the reference to the object's function save the day?Does the interpreter keep references to the object whose code it is currently executing until it finishes?
No, there isn't any such race condition. You are clearing the reference, so the ref count drops to 1 and the object will be cleaned up once you delete the method reference.
The the_deletion_func reference points to a method, which points to the instance (as well as the class), so there is still a reference there.
Currently executing methods have a local variable self, which is a reference to the instance as well, but mostly it's the method wrapper that provides that reference.

Resources