Check if string is part of object variables - python-3.x

I want to pass a string to a method/class function which resolves the correct attribute to modify. I'm pretty sure i've done this before, but I seem to have forgotten how to.
class A:
def __init__(self):
self.word = B.getWord()
self.phrase = "Some default string"
def set_dynamically(self, attribute, value):
self[attribute] = value
This would let me do something like A.set_dynamically('word', C.getWord())
I've tried searching for a question and answer for this but I'm having a hard time defining what this is called, so I didn't really find anything.

Python objects have a built-in method called __setattr__(self, name, value) that does this. You can invoke this method by calling setattr() with an object as the argument:
A = A()
setattr(A, 'word', C.getWord())
There's no reason to do this when you could just do something like A.word = C.getWord() (which, in fact, resolves down to calling __setattr__() the same way as the built-in setattr() function does), but if the property you're setting is named dynamically, then this is how you get around that limitation.
If you want to customize the behavior of how your class acts when you try to call setattr() on it (or when you try to set an attribute normally), you can override the __setattr__(self, name, value) method in much the same way as you're overriding __init__(). Be careful if you do this, because it's really easy to accidentally produce an infinite recursion error - to avoid this you can use object.__setattr__(self, name_value) inside your overridden __setattr__(self, name, value).

Just wanted to add my own solution as well. I created a mapping object;
def _mapper(self, attr, object):
m = { "funcA" : object.funcA,
"funcB" : object.funcB,
... : ...,
}
return m.get(attr)
def call_specific_func_(self, attr):
--do stuff--
for a in some-list:
attr = a.get_attr()
retvals = self._mapper(attr, a)
-- etc --

Related

Vs Code + Python : What means VS (Pylance) autocomplete suggestion for get_success_url()

When I define `get_success_url' in my views, if I accept Pylance Autocomplete suggestion, I got this :
def get_success_url(self) -> str:
return super().get_success_url()
Didn't find anywhere how to use this.
By my side, I'm use to do :
def get_success_url(self, **kwargs):
return reverse_lazy('name_space:url_name', kwargs={'pk': foo})
How to (can I) use pylance's suggestion to achieve the same result as my method
The autocomplete version isn't actually doing anything.
Sometimes when you are overriding a function, you want to use the same function of the parent class plus something extra, eg, if you override save() you might set another property and then do a normal save, which you do by calling super().save().
def save(self, *args, **kwargs):
self.status = Model.SAVED
return super().save()
However, you don't always have to call super() if your function is doing the job on its own. In this case with the autocomplete, if all you do is return super().get_success_url() there's no point in overriding the function as you haven't done anything different to an parent function. Your existing get_success_url() performs a purpose and replaces any super() version, so you don't need to call super() in it.
Autocomplete is just a suggestion, it's not saying you need to be doing something a certain way.

Usage of __setattr__ to rewrite whole method of library class issue: missing 1 required positional argument: 'self'

I've got some imported packages with tricky structure
and need to call some method that bases on lots of other methods
with non-default parameters, which are not class attributes themself like pipeline in sklearn.
Minimal example of this module structure:
class Library_class:
def __init__(
self,
defined_class_options,
):
self.defined_class_options = defined_class_options
def method1( self , default_non_class_arg = 12 ):
assert self.defined_class_options==3
return default_non_class_arg
def method2( self, image ):
return image/ self.method1()
Default usage:
class_instance = Library_class( 3 )
class_instance.method2( 36 )
> 3.0
I need to set default_non_class_arg to 6 for example.
I've tried multiple approaches:
Analogous to https://stackoverflow.com/a/35634198/7607734
class_instance.method2( 36 ,
method1__default_non_class_arg=3 )
TypeError: method2() got an unexpected keyword argument 'method1__default_non_class_arg'
It don't work probably because class definitely don't have set_params
With setattr on redefined function
class_instance.__setattr__('method1',Library_class.new_method1)
class_instance.method2( 36 )
TypeError: new_method1() missing 1 required positional argument: 'self'
Both your snippets and question are quite messy, almost to the point of being unreadable.
Anyway, if you wantt to replace method1 with another function, say new_method1 in an specific instance, just do that. Your call to .__setattr__ does that, but it is not needed at all, (and if it was, due to you not having the method to be replaced name at code writting time, and needed it as a parameter, it is more correct to call the built-in setattr, not the instance method: `setattr(class_instance, "method1", new_method1").
Ordinarily, if you know, at code writting time you have to replace "method1" in an instance, the assigment operator will do it:
class_instance.method1 = new_method1
What went wrong in your examle is that if you assign a method to an instance, instead of a class, you are bypassing the mechanism that Python uses to insert the self attribute into it - so your new_method1 needs a different signature. (and this is exactly what the error message "TypeError: new_method1() missing 1 required positional argument: 'self'" is saying):
class MyClass:
...
def method1(self, param1=36):
...
...
def new_method1(param1=6): # <-- written outside of any class body, sans self
...
my_instance = MyClass()
my_instance.method1 = new_method1
this will work.
new_method1 could be written in a class body as well, and could be replaced just the same, but you would have to write it without the self parameter the same, and then it would not work straight as a normal method.
OR, you can, at assigment time, insert the self argument yourself - the functools.partial call is a convenient way to do that:
class MyClass:
...
def method1(self, param1=36):
...
def new_method1(self, param1=6):
...
...
my_instance = MyClass()
from functools import partial
MyClass.method1 = partial(MyClass.new_method1, my_instance)
Now, this should answer what you are asking, but it would not be honest of me to end the answer without saying this is not a good design. The best thing there is to pull your parameter from another place, it might be from an instance attribute, instead of replacing the method entirely just to change it.
Since for normal attributes, Python will read the class attribute if no instance attribute exists, it will happen naturally, and all you have to do is to set the new default value in your instance.
class MyClass:
default_param_1 = 36 # Class attribute. Valid for every instance unless overriden
...
def method1(self, param1=None):
if param1 is None:
param1 = self.default_param_1 #Automatically fetched from the class if not set on the instance
...
...
my_instance = MyClass()
my_instance.default_param_1 = 6
...

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 use a variable "holding" a string value as list name?

One of the parameter the I want to pass to a Class init is a variable with a string value. this string value is a name of a list. The init should use this string value to append the class object to that list. what I'm doing wrong?
I've tried using the locals() and globals() but it ended with "TypeError: unhashable type: 'list'". tried also vars() with no use as well.
refList = []
cmpList = []
class Part(object):
def __init__(self, origin, name, type, listName):
self.origin = origin
self.name = name
self.type = type
partListName = locals()[listName]
partListName.append(self)
#... some file parsing..
part1 = Part((str(origin), str(name) ,str(type), 'refList')
# ... some other file parsing ...
part2 = Part((str(origin), str(name) ,str(type), 'cmpList')
Welcome to SO Ram! I think you should rethink your code because this is not a good approach to do it always. It is better for example pass directly the list or something related.
However your issue with your code is that you should use the globals() function. I really recommend you see the next post in order to get more knowledge about how/when use this useful functionality of Python3.
Also, you must declarate your variables with global keywoard because you are going to reference this variables from your Part class.
global refList = []
global cmpList = []
Said all this, your critical code line should look like:
partListName = globals()[listName]

python property referring to property/attribute of member attribute?

I'm wondering if I have:
class A(object):
def __init__(self):
self.attribute = 1
self._member = 2
def _get_member(self):
return self._member
def _set_member(self, member):
self._member = member
member = property(_get_member, _set_member)
class B(object):
def __init__(self):
self._member = A()
def _get_a_member(self):
return self._member.member
def _set_a_member(self, member):
self._member.member = member
member = property(_get_a_member, _set_a_member)
Can I somehow avoid to write get/setters for A.member, and simply refer to the attribute or property of the A object?
Where the get/setters do logic, its of course needed, but if I simply wan't to expose the member/attributes of a member attribute, then writing get/setters seems like overhead.
I think even if I could write the get/setters inline that would help?
I find the question a bit unclear, however I try to explain some context.
Where the get/setters do logic, its of course needed, but if I simply wan't to expose the member/attributes of a member attribute
If there is no logic in getter/setters, then there is no need to define the attribute as a property, but the attribute can be used directly (in any context).
So
class A(object):
def __init__(self):
self.attribute = 1
self.member = 2
class B(object):
def __init__(self):
self.member = A()
B().member.member # returns 2
B().member.member = 10
In some languages, it's considered good practice to abstract instance properties with getter/setter methods, That's not necessarily the case in Python.
Python properties are useful when you'd need more control over the attribute, for example:
when there is logic (validation, etc.)
to define a readonly attribute (so only providing a getter without a setter)
Update (after the comment)
properties are not necessarily a tool to "hide" some internal implementation. Hiding in Python is a bit different than say in Java, due to very dynamic nature of Python language. It's always possible to introspect and even change objects on the fly, you can add new attributes (even methods) to objects on runtime:
b = B()
b.foo = 4 # define a new attribute on runtime
b.foo # returns 4
So Python developers rely more on conventions to hint their intentions of abstractions.
About the polymorphic members, I think it's most natural for Python classes to just share an interface, that's what's meant by Duck typing. So as long as your next implementation of A supports the same interface (provides the same methods for callers), it should not be any issue to change its implementation.
So this is what I came up with - use a method to generate the properties, with the assumption that the obj has an attribute of _member:
def generate_cls_a_property(name):
"""Small helper method for generating a 'dumb' property for the A object"""
def getter(obj):
return getattr(obj._member, name)
def setter(obj, new_value):
setattr(obj._member, name, new_value)
return property(getter, setter)
This allows me to add properties like so:
class B(object):
def __init__(self):
self._member = A()
member = generate_cls_a_property('member') # generates a dumb/pass-through property
I'll accept my own, unless someone tops it within a week.. :)

Resources