i created much instances of a class. Then I want to find one instance by its name. But I get the error message TypeError: get() missing 1 required positional argument: 'value'.
class Test(object):
def __init__(self, value):
self.value = value
def get(self, value):
if self.value == value:
return self
else:
return None
test_obj = Test('foobar')
print(test_obj.value)
instance = Test.get('foobar')
if instance:
print(instance.value)
Re-reading your question again, I think all of us have missed the point so far. You wanted to check all instances of the class Test to see if an instance has the value 'foobar' (in this case, test_obj. Referencing this answer, you can modify your code like so:
class Test(object):
# class attribute to keep track of class instances
instances = []
def __init__(self, value):
self.value = value
Test.instances.append(self)
# class method to access the get method without any instance
#classmethod
def get(cls, value):
return [inst for inst in cls.instances if inst.value == value]
You can then create multiple tests:
test1 = Test(1)
test2 = Test(2)
test3 = Test(3)
instance = Test.get(3)
# [<__main__.Test object at 0x03F29CD0>]
instance[0].value
# 3
It makes sense for me to return a list of instances instead of one single instance. If you however is only interested in the first match, you can modify the return statement accordingly.
Original answer:
instance = Test.get('foobar') is the problem. You're referencing Test by its class, not its instance. So naturally the instance method .get(self, value) is looking for the first argument self for the instance.
Usually if you already have an instance (e.g. Test().get('foobar')) then the instance is passed into the instance method as self by default.
You could still call the instance method, but you just need to explicitly pass the instance in:
Test.get(test, 'foobar')
The get method belongs to the instance, not the class. A class does not know its instances (you could do some dirty tricks to let the class know, but don't). What you need is a list of instances.
One way you could do it
override the equality operator
create a list of the instances
So, something like
class Test:
def __eq__(self, value):
return self.value == value
test_list = [Test(5), Test(2), Test(3)]
position = test_list.index(2)
The "get" method of your class is not a class method therefore you have to call it on the instance:
test.get("foobar")
However if you modify the method to a classmethod than it won't be able to access the instance attributes only the class atributes will be visible.
For a quick solution I think you should store all of the instances in a datastructure (for example in a list) and you can create a function which will loop through the instances and returns the correct one.
Related
I think a code sample will better speak for itself:
class SomeClass:
example = create_get_method()
Yes, that's all – ideally.
In that case, create_get_method would add a get_example() to SomeClass in a way that it can be accessed via an instance of SomeClass:
obj = SomeClass()
obj.get_example() <- returns the value of self.example
(Of course, the idea is to implement a complex version of get_contact, that's why I want to do that in a non-repetitive way, and this is a simplified version that represents well the issue.)
I don't know if that's possible, because it require to have access to the property name (example) and the class (SomeClass) since these can not be guessed in advance (that function will be used on many and various classes).
I know it's something possible, because that's kind of what SQLAlchemy does with their relationship() function on a class:
class Model(BaseModel):
id = ...
contact_id = db.Integer(db.ForeignKey..)
contact = relationship('contact') <-- This !
How can this be done?
Objects bound to class-level variables can have a __set_name__ method that will be called immediately after the class object has been created. It will be called with two arguments, the class object, and the name of the variable the object is saved as in the class.
You could use this to create your extra getter method, though I'm not sure why exactly you want to (you could make the object a descriptor instead, which would probably be better than adding a separate getter function to the parent class).
class create_get_method:
def __set_name__(self, owner, name):
def getter(self):
return getattr(self, name)
getter_name = f"get_{name}"
getter.__name__ = getter_name
setattr(owner, getter_name, getter)
# you might also want a __get__ method here to give a default value (like None)
Here's how that would work:
>>> class Test:
... example = create_get_method()
...
>>> t = Test()
>>> print(t.get_example())
<__main__.create_get_method at 0x000001E0B4D41400>
>>> t.example = "foo"
>>> print(t.get_example())
foo
You could change the value returned by default (in the first print call), so that the create_get_method object isn't as exposed. Just add a __get__ method to the create_get_method class.
You can do this with a custom non-data descriptor, like a property, except that you don't need a __set__ method:
class ComplicatedDescriptor:
def __init__(self, name):
self.name = name
def __get__(self, owner, type):
# Here, `owner` is the instance of `SomeClass` that contains this descriptor
# Use `owner` to do some complicated stuff, like DB lookup or whatever
name = f'_{self.name}'
# These two lines for demo only
value = owner.__dict__.get(name, 0)
value += 1
setattr(owner, name, value)
return value
Now you can have any number of classes that use this descriptor:
class SomeClass:
example = ComplicatedDescriptor('example')
Now you can do something like:
>>> inst0 = SomeClass()
>>> inst1 = SomeClass()
>>> inst0.example
1
>>> inst1.example
1
>>> inst1.example
2
>>> inst0.example
2
The line name = f'_{self.name} is necessary because the descriptor here is a non-data descriptor: it has no __set__ method, so if you create inst0.__dict__['example'], the lookup will no longer happen: inst0.example will return inst0.__dict__['example'] instead of calling SomeClass.example.__get__(inst0, type(inst0)). One workaround is to store the value under the attribute name _example. The other is to make your descriptor into a data descriptor:
class ComplicatedDescriptor_v2:
def __init__(self, name):
self.name = name
def __get__(self, owner, type):
# Here, `owner` is the instance of `SomeClass` that contains this descriptor
# Use `owner` to do some complicated stuff, like DB lookup or whatever
# These two lines for demo only
value = owner.__dict__.get(self.name, 0)
value += 1
owner.__dict__[self.name] = value
return value
def __set__(self, *args):
raise AttributeError(f'{self.name} is a read-only attribute')
The usage is generally identical:
class SomeClass:
example = ComplicatedDescriptor_v2('example')
Except that now you can't accidentally override your attribute:
>>> inst = SomeClass()
>>> inst.example
1
>>> inst.example
2
>>> inst.example = 0
AttributeError: example is a read-only attribute
Descriptors are a fairly idiomatic way to get and set values in python. They are preferred to getters and setters in almost all cases. The simplest cases are handled by the built-in property. That being said, if you wanted to explicitly have a getter method, I would recommend doing something very similar, but just returning a method instead of calling __get__ directly.
For example:
def __get__(self, owner, type):
def enclosed():
# Use `owner` to do some complicated stuff, like DB lookup or whatever
name = f'_{self.name}'
# These two lines for demo only
value = owner.__dict__.get(name, 0)
value += 1
setattr(owner, name, value)
return value
return enclosed
There is really no point to doing something like this unless you plan on really just want to be able to call inst.example().
I'm using Python 3.8 and I would like to create an abstract class that will be used by other subclasses to redefine or add methods and attributes that are not common with other subclasses.
All these subclasses must have an instance attribute (my_value) and a class attribute called LENGTH.
LENGTH is fixed: subclass users (who will initialize subclass objects) could not directly modify it because all object created from that subclass must have the same LENGTH defined by the subclass creator.
The first attempt I did to obtain that result was to use, in the abstract class, the decorators #property, #classmethod and #abstractmethod in this way:
class SuperAbstractClass(ABC):
[...]
#property
#classmethod
#abstractmethod
def LENGTH(cls):
return NotImplementedError
In that way I solved the problem: when you define a subclass you also have to define LENGTH.
I also added a new problem regarding the fact that in the abstract class I'm also redefining the __setattr__ magic method to ensure that a subclass value alway matches the LENGTH value, filling my_value with zeros (using the zfill method):
def __setattr__(self, name, value):
'''
Every time a user will assign a value to "my_value", "__setattr__" will ensure
that the value get filled by zeros to match the "LENGTH" value
(example: with LENGTH=4, the value "A" will become "000A")
'''
if name == 'my_value':
super(SuperAbstractClass, self).__setattr__(
'my_value',
value.zfill(SuperAbstractClass.LENGTH)
)
else: # all the other assignment will not be modified
super(SuperAbstractClass, self).__setattr__(name, value)
In this way I get an error because zfill tells me that need an int and at that time LENGTH is a property.
Now I came up with a solution that is not ideal: the users of my abstract class have to redefine __init__ but ideally they can avoid to define LENGTH (in this example LENGTH is now called length_to_reach) and also I have the same code to every subclass:
from abc import ABC, abstractmethod
class SuperAbstractClass(ABC):
'''
We want to force all subclasses to redefine "__init__" adding an hardcoded
length to the "my_value" attribute: ideally the subclasses users should
only be able define "my_value", not the "length_to_reach"
'''
#abstractmethod
def __init__(self, my_value, length_to_reach):
self.length_to_reach = length_to_reach
self.my_value = my_value # NB: assignation managed by __setattr__
def __setattr__(self, name, value):
'''
Every time a user will assign a value to "my_value", "__setattr__" will ensure
that the value get filled by zeros to match the "length_to_reach" value
(example: with length_to_reach=4, the value "A" will become "000A")
'''
if name == 'my_value':
super(SuperAbstractClass, self).__setattr__(
'my_value',
value.zfill(self.length_to_reach)
)
else: # all the other assignment will not be modified
super(SuperAbstractClass, self).__setattr__(name, value)
class SubClassOne(SuperAbstractClass):
LENGTH = 12
def __init__(self, my_value):
super(SubClassOne, self).__init__(my_value, SubClassOne.LENGTH)
class SubClassTwo(SuperAbstractClass):
LENGTH = 9
def __init__(self, my_value):
super(SubClassTwo, self).__init__(my_value, SubClassTwo.LENGTH)
if __name__ == '__main__':
a = SubClassOne("ValueOne")
b = SubClassTwo("ValueTwo")
print(f'\na.my_value: {a.my_value} is now filled to the length of {a.LENGTH}')
print(f'\nb.my_value: {b.my_value} is now filled to the length of {b.LENGTH}')
#*Output:*
#
#a.my_value: 0000ValueOne is now filled to the length of 12
#
#b.my_value: 0ValueTwo is now filled to the length of 9
My final question is: what is the best method to obtain that? Should I try to avoid abstract class users to define some attributes because is not very pythonic? Do I totally approach my needs from the wrong way?
I am using python and have an object, that object has a method. I am looking for a simple way, to replace the entire object from within that function.
E.g
class a():
def b(self):
self = other_object
How can you do that?
Thanks
You use a proxy/facade object to hold a reference to the actual object, the self if you wish and that proxy (better term than Facade, but not changing my code now) is what the rest of your codebase sees. However, any attribute/method access is forwarded on to the actual object, which is swappable.
Code below should give you a rough idea. Note that you need to be careful about recursion around __the_instance, which is why I am assigning to __dict__ directly. Bit messy, since it's been a while I've written code that wraps getattr and setattr entirely.
class Facade:
def __init__(self, instance):
self.set_obj(instance)
def set_obj(self, instance):
self.__dict__["__theinstance"] = instance
def __getattr__(self, attrname):
if attrname == "__theinstance":
return self.__dict__["__theinstance"]
return getattr(self.__dict__["__theinstance"], attrname)
def __setattr__(self, attrname, value):
if attrname == "__theinstance":
self.set_obj(value)
return setattr(self.__dict__["__theinstance"], attrname, value)
class Test:
def __init__(self, name, cntr):
self.name = name
self.cntr = cntr
def __repr__(self):
return "%s[%s]" % (self.__class__.__name__, self.__dict__)
obj1 = Test("first object", 1)
obj2 = Test("second", 2)
obj2.message = "greetings"
def pretend_client_code(facade):
print(id(facade), facade.name, facade.cntr, getattr(facade, "value", None))
facade = Facade(obj1)
pretend_client_code(facade)
facade.set_obj(obj2)
pretend_client_code(facade)
facade.value = 3
pretend_client_code(facade)
facade.set_obj(obj1)
pretend_client_code(facade)
output:
4467187104 first object 1 None
4467187104 second 2 None
4467187104 second 2 3
4467187104 first object 1 None
So basically, the "client code" always sees the same facade object, but what it is actually accessing depends on what your equivalent of def b is has done.
Facade has a specific meaning in Design Patterns terminology and it may not be really applicable here, but close enough. Maybe Proxy would have been better.
Note that if you want to change the class on the same object, that is a different thing, done through assigning self.__class__ . For example, say an RPG game with an EnemyClass who gets swapped to DeadEnemyClass once killed: self.__class__ = DeadEnemyClass
You can't directly do that. What you can do is save it as an instance variable.
class A():
def __init__(self, instance=None):
self.instance = val or self
# yes, you can make it a property as well.
def set_val(self, obj):
self.instance = obj
def get_val(self):
return self.instance
It is unlikely that replacing the 'self' variable will accomplish
whatever you're trying to do, that couldn't just be accomplished by
storing the result of func(self) in a different variable. 'self' is
effectively a local variable only defined for the duration of the
method call, used to pass in the instance of the class which is being
operated upon. Replacing self will not actually replace references to
the original instance of the class held by other objects, nor will it
create a lasting reference to the new instance which was assigned to
it.
Original source: Is it safe to replace a self object by another object of the same type in a method?
I would like to replace an object instance by another instance inside a method like this:
class A:
def method1(self):
self = func(self)
The object is retrieved from a database.
It is unlikely that replacing the 'self' variable will accomplish whatever you're trying to do, that couldn't just be accomplished by storing the result of func(self) in a different variable. 'self' is effectively a local variable only defined for the duration of the method call, used to pass in the instance of the class which is being operated upon. Replacing self will not actually replace references to the original instance of the class held by other objects, nor will it create a lasting reference to the new instance which was assigned to it.
As far as I understand, If you are trying to replace the current object with another object of same type (assuming func won't change the object type) from an member function. I think this will achieve that:
class A:
def method1(self):
newObj = func(self)
self.__dict__.update(newObj.__dict__)
It is not a direct answer to the question, but in the posts below there's a solution for what amirouche tried to do:
Python object conversion
Can I dynamically convert an instance of one class to another?
And here's working code sample (Python 3.2.5).
class Men:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a men! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_men(self):
print('I made The Matrix')
class Women:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a women! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_women(self):
print('I made Cloud Atlas')
men = Men('Larry')
men.who_are_you()
#>>> I'm a men! My name is Larry
men.method_unique_to_men()
#>>> I made The Matrix
men.cast_to(Women, 'Lana')
men.who_are_you()
#>>> I'm a women! My name is Lana
men.method_unique_to_women()
#>>> I made Cloud Atlas
Note the self.__class__ and not self.__class__.__name__. I.e. this technique not only replaces class name, but actually converts an instance of a class (at least both of them have same id()). Also, 1) I don't know whether it is "safe to replace a self object by another object of the same type in [an object own] method"; 2) it works with different types of objects, not only with ones that are of the same type; 3) it works not exactly like amirouche wanted: you can't init class like Class(args), only Class() (I'm not a pro and can't answer why it's like this).
Yes, all that will happen is that you won't be able to reference the current instance of your class A (unless you set another variable to self before you change it.) I wouldn't recommend it though, it makes for less readable code.
Note that you're only changing a variable, just like any other. Doing self = 123 is the same as doing abc = 123. self is only a reference to the current instance within the method. You can't change your instance by setting self.
What func(self) should do is to change the variables of your instance:
def func(obj):
obj.var_a = 123
obj.var_b = 'abc'
Then do this:
class A:
def method1(self):
func(self) # No need to assign self here
In many cases, a good way to achieve what you want is to call __init__ again. For example:
class MyList(list):
def trim(self,n):
self.__init__(self[:-n])
x = MyList([1,2,3,4])
x.trim(2)
assert type(x) == MyList
assert x == [1,2]
Note that this comes with a few assumptions such as the all that you want to change about the object being set in __init__. Also beware that this could cause problems with inheriting classes that redefine __init__ in an incompatible manner.
Yes, there is nothing wrong with this. Haters gonna hate. (Looking at you Pycharm with your in most cases imaginable, there's no point in such reassignment and it indicates an error).
A situation where you could do this is:
some_method(self, ...):
...
if(some_condition):
self = self.some_other_method()
...
return ...
Sure, you could start the method body by reassigning self to some other variable, but if you wouldn't normally do that with other parametres, why do it with self?
One can use the self assignment in a method, to change the class of instance to a derived class.
Of course one could assign it to a new object, but then the use of the new object ripples through the rest of code in the method. Reassiging it to self, leaves the rest of the method untouched.
class aclass:
def methodA(self):
...
if condition:
self = replace_by_derived(self)
# self is now referencing to an instance of a derived class
# with probably the same values for its data attributes
# all code here remains untouched
...
self.methodB() # calls the methodB of derivedclass is condition is True
...
def methodB(self):
# methodB of class aclass
...
class derivedclass(aclass):
def methodB(self):
#methodB of class derivedclass
...
But apart from such a special use case, I don't see any advantages to replace self.
You can make the instance a singleton element of the class
and mark the methods with #classmethod.
from enum import IntEnum
from collections import namedtuple
class kind(IntEnum):
circle = 1
square = 2
def attr(y): return [getattr(y, x) for x in 'k l b u r'.split()]
class Shape(namedtuple('Shape', 'k,l,b,u,r')):
self = None
#classmethod
def __repr__(cls):
return "<Shape({},{},{},{},{}) object at {}>".format(
*(attr(cls.self)+[id(cls.self)]))
#classmethod
def transform(cls, func):
cls.self = cls.self._replace(**func(cls.self))
Shape.self = Shape(k=1, l=2, b=3, u=4, r=5)
s = Shape.self
def nextkind(self):
return {'k': self.k+1}
print(repr(s)) # <Shape(1,2,3,4,5) object at 139766656561792>
s.transform(nextkind)
print(repr(s)) # <Shape(2,2,3,4,5) object at 139766656561888>
In class B below I wanted the __set__ function in class A to be called whenever you assign a value to B().a . Instead, setting a value to B().a overwrites B().a with the value. Class C assigning to C().a works correctly, but I wanted to have a separate instance of A for each user class, i.e. I don't want changing 'a' in one instance of C() to change 'a' in all other instances. I wrote a couple of tests to help illustrate the problem. Can you help me define a class that will pass both test1 and test2?
class A(object):
def __set__(self, instance, value):
print "__set__ called: ", value
class B(object):
def __init__(self):
self.a = A()
class C(object):
a = A()
def test1( class_in ):
o = class_in()
o.a = "test"
if isinstance(o.a, A):
print "pass"
else:
print "fail"
def test2( class_in ):
o1, o2 = class_in(), class_in()
if o1.a is o2.a:
print "fail"
else:
print "pass"
Accordingly to the documentation:
The following methods only apply when an instance of the class containing
the method (a so-called descriptor
class) appears in the class dictionary
of another new-style class, known as
the owner class. In the examples
below, “the attribute” refers to the
attribute whose name is the key of the
property in the owner class’ __dict__.
Descriptors can only be implemented as
new-style classes themselves.
So you can't have descriptors on instances.
However, since the descriptor gets a ref to the instance being used to access it, just use that as a key to storing state and you can have different behavior depending on the instance.
Here's a class that can pass the original tests, but don't try using it in most situations. it fails the isinstance test on itself!
class E(object):
def __new__(cls, state):
class E(object):
a = A(state)
def __init__(self, state):
self.state = state
return E(state)
#>>> isinstance(E(1), E)
#False
I was bitten by a similar issue in that I wanted to class objects with attributes governed by a descriptor. When I did this, I noticed that the attributes were being overwritten in all of the objects such that they weren't individual.
I raised a SO question and the resultant answer is here: class attribute changing value for no reason
A good document link discussing descriptors is here: http://martyalchin.com/2007/nov/24/python-descriptors-part-2-of-2/
An example descriptor from the aforementioned link is below:
class Numberise(object):
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
if self.name not in instance.__dict__:
raise (AttributeError, self.name)
return '%o'%(instance.__dict__[self.name])
def __set__(self, instance, value):
print ('setting value to: %d'%value)
instance.__dict__[self.name] = value