I'm trying to set a Python class property outside of the class via the setattr(self, item, value) function.
class MyClass:
def getMyProperty(self):
return self.__my_property
def setMyProperty(self, value):
if value is None:
value = ''
self.__my_property = value
my_property = property( getMyProperty, setMyProperty )
And in another script, I create an instance and want to specify the property and let the property mutator handle the simple validation.
myClass = MyClass()
new_value = None
# notice the property in quotes
setattr(myClass, 'my_property', new_value)
The problem is that it doesn't appear to be calling the setMyProperty(self, value) mutator. For a quick test to verify that it doesn't get called, I change the mutator to:
def setMyProperty(self, value):
raise ValueError('WTF! Why are you not being called?')
if value is None:
value = ''
self.__my_property = value
I'm fairly new to Python, and perhaps there's another way to do what I'm trying to do, but can someone explain why the mutator isn't being called when setattr(self, item, value) is called?
Is there another way to set a property via a string? I need the validation inside the mutator to be executed when setting the property value.
Works for me:
>>> class MyClass(object):
... def get(self): return 10
... def setprop(self, val): raise ValueError("hax%s"%str(val))
... prop = property(get, setprop)
...
>>> i = MyClass()
>>> i.prop =4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in setprop
ValueError: hax4
>>> i.prop
10
>>> setattr(i, 'prop', 12)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in setprop
ValueError: hax12
The code you pasted seems to do the same as mine, except that my class inherits from object, but that's cause I'm running Python 2.6 and I thought that in 2.7 all classes automatically inherit from object. Try that, though, and see if it helps.
To make it even clearer: try just doing myClass.my_property = 4. Does that raise an exception? If not then it's an issue with inheriting from object - properties only work for new-style classes, i.e. classes that inherit from object.
Related
I need to create a custom ConfigParser which adds a few features including, most relevantly here, a default value for unset keys of None. This seems to be supported through custom dict types and accordingly I wrote something like this:
class SyncDict(collections.UserDict):
...
def __getitem__(self, key):
if key in self.data:
return self.data[key]
return None
...
class SyncConfig(ConfigParser):
...
def __init__(self, filename):
super().__init__(allow_no_value=True, dict_type = SyncDict)
...
However, this does not work as it still raises KeyError in SectionProxy. For example,
>>> a = SyncConfig('aaa.cfg')
>>> a.add_section('b')
>>> b = a['b']
>>> b['c']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Program Files\Python38\lib\configparser.py", line 1254, in __getitem__
raise KeyError(key)
KeyError: 'c'
Am I missing something, or this really not supposed to be possible?
PS: Bonus points for a way to make SyncDict return a value of an empty SyncDict when asked for a section and None when asked for an option.
When I try to monkey-patch a class with a method from another class, it doesn't work because the argument self isn't of the right type.
For example, let's like the result of the method __str__ created by the fancy class A:
class A:
def __init__(self, val):
self.val=val
def __str__(self):
return "Fancy formatted %s"%self.val
and would like to reuse it for a boring class B:
class B:
def __init__(self, val):
self.val=val
That means:
>>> b=B("B")
>>> #first try:
>>> B.__str__=A.__str__
>>> str(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method __str__() must be called with A instance as first argument (got nothing instead)
>>> #second try:
>>> B.__str__= lambda self: A.__str__(self)
>>> str(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
TypeError: unbound method __str__() must be called with A instance as first argument (got B instance instead)
So in both cases the it doesn't work because the argument self should be an instance of class A, but evidently isn't.
It would be nice to find a way to do the monkey-patching, but my actual question is, why it is necessary for the implicit parameter self to be an instance of the "right" class and not just depend on the duck-typing?
Because of the way methods are contributed to class objects in Python 2, the actual function object is hidden behind an unbound method, but you can access it using the im_func aka __func__ attribute:
>>> B.__str__ = A.__str__.__func__
>>> str(B('stuff'))
'Fancy formatted stuff'
Arguably, a better way to do this is using new-style classes and inheritance.
class MyStrMixin(object):
def __str__(self):
return "Fancy formatted %s" % self.val
Then inherit from MyStrMixin in both A and B, and just let the MRO do its thing.
I have a class that inherit from OrderedDict, but I don't know if this is the right way to accomplish what I need.
I would like the class to have the duel method of the javascript '.' notation like obj.<property> and I would also like the users to be able to access the class properties like obj['myproperty'] but I was to hide all the key() and get() functions. The inheritance model is providing good functionality, but it cluttering up the object with additional methods that are not really needed.
Is it possible to get the dictionary behavior without all the other functions coming along?
For this discussion, let's assume my class is this:
from six.moves.urllib import request
import json
class MyClass(OrderedDict):
def __init__(self, url):
super(MyClass, self).__init__(url=url)
self._url = url
self.init()
def init(self):
# call the url and load the json
req = request.Request(self._url)
res = json.loads(request.urlopen(req).read())
for k,v in res.items():
setattr(self, k, v)
self.update(res)
self.__dict__.update(res)
if __name__ == "__main__":
url = "https://sampleserver5.arcgisonline.com/ArcGIS/rest/services?f=json"
props = MyClass(url=url)
props.currentVersion
Is there another way to approach this dilemma?
Thanks
If all you want is x['a'] to work the same way as x.a without any other functionality of dictionaries, then don't inherit from dict or OrderedDict, instead just forward key/indice operations (__getitem__, __setitem__ and __delitem__) to attribute operations:
class MyClass(object):
def __getitem__(self,key):
try: #change the error to a KeyError if the attribute doesn't exist
return getattr(self,key)
except AttributeError:
pass
raise KeyError(key)
def __setitem__(self,key,value):
setattr(self,key,value)
def __delitem__(self,key):
delattr(self,key)
As an added bonus, because these special methods don't check the instance variables for the method name it doesn't break if you use the same names:
x = MyClass()
x['__getitem__'] = 1
print(x.__getitem__) #still works
print(x["__getattr__"]) #still works
The only time it will break is when trying to use __dict__ since that is where the instance variables are actually stored:
>>> x = MyClass()
>>> x.a = 4
>>> x.__dict__ = 1 #stops you right away
Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
x.__dict__ = 1
TypeError: __dict__ must be set to a dictionary, not a 'int'
>>> x.__dict__ = {} #this is legal but removes all the previously stored values!
>>> x.a
Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
x.a
AttributeError: 'MyClass' object has no attribute 'a'
In addition you can still use the normal dictionary methods by using vars():
x = MyClass()
x.a = 4
x['b'] = 6
for k,v in vars(x).items():
print((k,v))
#output
('b', 6)
('a', 4)
>>> vars(x)
{'b': 6, 'a': 4}
Let's say a function looks at an object and checks if it has a function a_method:
def func(obj):
if hasattr(obj, 'a_method'):
...
else:
...
I have an object whose class defines a_method, but I want to hide it from hasattr. I don't want to change the implementation of func to achieve this hiding, so what hack can I do to solve this problem?
If the method is defined on the class you appear to be able to remove it from the __dict__ for the class. This prevents lookups (hasattr will return false). You can still use the function if you keep a reference to it when you remove it (like the example) - just remember that you have to pass in an instance of the class for self, it's not being called with the implied self.
>>> class A:
... def meth(self):
... print "In method."
...
>>>
>>> a = A()
>>> a.meth
<bound method A.meth of <__main__.A instance at 0x0218AB48>>
>>> fn = A.__dict__.pop('meth')
>>> hasattr(a, 'meth')
False
>>> a.meth
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'meth'
>>> fn()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: meth() takes exactly 1 argument (0 given)
>>> fn(a)
In method.
You could redefine the hasattr function. Below is an example.
saved_hasattr = hasattr
def hasattr(obj, method):
if method == 'MY_METHOD':
return False
else:
return saved_hasattr(obj, method)
Note that you probably want to implement more detailed checks than just checking the method name. For example checking the object type might be beneficial.
Try this:
class Test(object):
def __hideme(self):
print 'hidden'
t = Test()
print hasattr(t,"__hideme") #prints False....
I believe this works b/c of the double underscore magic of hiding members (owning to name mangling) of a class to outside world...Unless someone has a strong argument against this, I'd think this is way better than popping stuff off from __dict__? Thoughts?
I ran the code below, by calling the function in the constructor
First --
>>> class PrintName:
... def __init__(self, value):
... self._value = value
... printName(self._value)
... def printName(self, value):
... for c in value:
... print c
...
>>> o = PrintName('Chaitanya')
C
h
a
i
t
a
n
y
a
Once again I run this and I get this
>>> class PrintName:
... def __init__(self, value):
... self._value = value
... printName(self._value)
... def printName(self, value):
... for c in value:
... print c
...
>>> o = PrintName('Hello')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
NameError: global name 'printName' is not defined
Can I not call a function in the constructor? and whay a deviation in the execution of similar code?
Note: I forgot to call a function local to the class, by using self (ex: self.printName()). Apologize for the post.
You need to call self.printName since your function is a method belonging to the PrintName class.
Or, since your printname function doesn't need to rely on object state, you could just make it a module level function.
class PrintName:
def __init__(self, value):
self._value = value
printName(self._value)
def printName(value):
for c in value:
print c
Instead of
printName(self._value)
you wanted
self.printName(self._value)
It probably worked the first time because you had another function printName in a parent scope.
What you want is self.printName(self._value) in __init__, not just printName(self._value).
I know this is an old question, but I just wanted to add that you can also call the function using the Class name and passing self as the first argument.
Not sure why you'd want to though, as I think it might make things less clear.
class PrintName:
def __init__(self, value):
self._value = value
PrintName.printName(self, self._value)
def printName(self, value):
for c in value:
print(c)
See Chapter 9 of the python manuals for more info:
9.3.4. Method Objects
Actually, you may have guessed the answer: the special thing about methods is that the object is passed as the first argument of the function. In our example, the call x.f() is exactly equivalent to MyClass.f(x). In general, calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method’s object before the first argument.