I'm confused with how attribute variables are behaving in my class when using the property decorator.
See this example:
class Example:
def __init__(self, x):
self.x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
self.__x = x
This works fine, but how? The variable inside the setter property (self.__x) has not been "defined" in the constructor, so how can it be assigned a value?
Other stuff also works, for example, take the same class defined above and add a new member function to it:
def set_val_x(self):
self.__x = 8765
Again, using this function actually works, similar to the property.setter (but it's not using the property decorator).
Inside __init__, the line
self.x = x
is no longer short for
setattr(self, 'x', x)
because the class attribute Example.x exists. You are no longer creating an instance attribute x, but calling
type(self).X.__set__(self, 'x', x)
which will set the instance attribute __x.
Instance attributes can be created, modified, or deleted at any time. The __init__ method is just a convenient, single place to create them because it is called for you automatically every time you create an instance.
In Python, you don’t have to define variables in the constructor. You can assign them whenever you want.
class Foo:
def __init__(self, bar):
self.bar = bar
my_foo = Foo(3)
my_foo.other_thing = 6
is perfectly legal, for example.
Related
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>
Say I have a simple class Foo, which comes from an external library, thus I cannot change it directly:
class Foo(object):
def __init__(self, x):
self.x = x
I want to create a subclass Bar and prevent x from being change from an instance of Bar, but still use the x in Bar's methods.
Here's what I tried, and it will probably enlighten the basic idea, but unfortunately it doesn't work:
class Bar(Foo):
#property
def x(self):
return super().x
#x.setter
def x(self, value):
raise NotImplementedError('Do not change x directly, use "do_stuff()" instead')
def do_stuff(self, value):
if <something>:
super().x = value
So basically I've created some wrapper functions (do_stuff()) around an attribute, and now I want to prevent the attribute from being changed directly, as it might mess up some functionality of the wrapper functions. Is this possible in a reasonable way?
Edited with a better example of what I want. I'm not trying to prevent them from seeing the variable x, but instead changing it from outside of do_stuff()
This should be much simpler to accomplish if you are willing to avoid inheritance altogether:
def main():
bar = Bar(123)
bar.fizz()
bar.buzz()
bar.fizz()
bar.set_x(456)
print('bar.x =', bar.x)
try:
bar.x = 123
except AttributeError:
print('bar.x cannot be set directly')
else:
raise AssertionError('an AttributeError should have been raised')
bar.mutate_x(789)
bar.fizz()
bar.set_x(0)
bar.fizz()
bar.mutate_x(1)
bar.fizz()
bar.set_x('Hello World')
bar.fizz()
class Foo:
def __init__(self, x):
self.x = x
def fizz(self):
print(self.x)
def buzz(self):
self.x = None
class Bar:
def __init__(self, x):
self.__foo = foo = Foo(x)
self.__copy_methods(foo)
def __copy_methods(self, obj):
for name in dir(obj):
if name.startswith('__') or name.endswith('__'):
continue
attr = getattr(obj, name)
if callable(attr):
setattr(self, name, attr)
#property
def x(self):
return self.__foo.x
def set_x(self, value):
if isinstance(value, int) and value > 0:
self.__foo.x = value
mutate_x = set_x
if __name__ == '__main__':
main()
The short answer is: No, this is not possible in a reasonable way.
Python's guiding principle here, to use the phrasing from the style guide is that we are all responsible users. Meaning that code is trusted not to do silly things, and people should generally avoid messing with members of other people's classes without a good reason.
The first and best way to prevent people from accidentally changing a value is to mark it using the single underscore (_variable). This however may not offer you the protection you want against accidental modification of your variables.
The next step up in protection is to use a double underscore. Quoting from PEP-8:
To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules.
Python mangles these names with the class name: if class Foo has an attribute named __a , it cannot be accessed by Foo.__a . (An insistent user could still gain access by calling Foo._Foo__a .) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.
The mangling makes it more difficult to accidentally overwrite a value.
I added emphasis to that last sentence because it is important. Using this mechanism for preventing accidental access to a member is not really the something that should be done for a lot of members.
In your specific case, the way that I'd solve the problem would be to not subclass at all. Consider:
class Foo(object):
def __init__(self, x):
self.x = x
class Bar():
def __init__(self, x):
self._foo = Foo(x)
#property
def x(self):
return self._foo.x
def do_stuff(self, value):
# Validate the value, and the wrapped object's state
if valid:
self._foo.x = value
Of course this means that Bar has to wrap all of Foo's methods that you want to wrap. Yes, someone could still,
b = Bar(100)
b._foo.x = 127 # shame on them :)
or
b = Bar(100)
b._foo = EvilFoo(127)
but it's harder to unintentionally do.
You're on the right track, you want to make x a property instead of having it be an attribute in the subclass. Where you went wrong was trying to store the raw data for x on super. What you want to do is exploit the fact that the parent class can use the new property of the subclass transparently and does not need to know that it is now a property and not a attribute. Something like this should work for you:
class Foo(object):
def __init__(self, x):
self.x = x
class Bar(Foo):
_protected_x = None
#property
def x(self):
return self._protected_x
#x.setter
def x(self, value):
if self._protected_x is None:
self._protected_x = value
else:
raise ValueError("Use set_x to change x.")
def set_x(self, value):
self._protected_x = value
b = Bar(12)
print b.x
b.set_x(5)
print b.x
I have a class where I have multiple methods. I want to use one of the methods as a decorator for other methods. For this I am using following syntax:
#self.action
def execute(self,req):
where action is other method in my class. But it doesn't work and throws exception as
name 'self' is not defined
You cannot use a method of the class while defining it; there is no self within the class nor is the class 'baked' yet to even access any class.
You can treat methods as functions to use as a decorator:
class SomeClass():
def action(func):
# decorate
return wrapper
#action
def execute(self, req):
# something
If action is defined on a base class, then you'd have to refer to the name via the base class:
class Base():
#staticmethod
def action(func):
# decorate
return wrapper
class Derived(Base):
#Base.action
def execute(self, req):
# something
For Python 2, you'd have to make action a static method here, as otherwise you get an unbound method that'll complain you cannot call it without an instance as the first argument. In Python 3, you can leave off the #staticmethod decorator there, at least for the purposes of the decorator.
But note that action cannot then be used as a method directly; perhaps it should not be part of the class at all at that point. It is not part of the end-user API here, presumably the decorator is not used by consumers of the instances of these classes.
Just beware that both the decorator and the decorated function are unbound methods, so you can only access the self (or cls for classmethods) in the inner scope of the decorator, and must manually bind the decorated method to the instance bound in the inner decorator.
class A:
x = 5
y = 6
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
#decorate
def func(self):
return self.y
A().func() # 30!!
Still trying to wrap my head around how decorators could be inherited and overridden.
Beware that for the decorator to work it can't be bound to an instance. That is: there is no way to make this work
a = A()
#a.decorate
def func(*args):
return 1
Despite this pattern is much more common than the asked here.
At this point the question raises: is it a method at all or just code that you happen to hide in a class?
The only way to prevent the decorator being wrongfully bound is to declare it as a staticmethod, but then it must be in a previous super class because to be used it must be bound to the static class reference which would not be yet defined, just as the self.
class A:
x = 1
#staticmethod
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
class B(A):
#A.decorate
def func(self):
return 1
class C():
x = 2
#B.decorate
def func(self):
return 1
a = A()
class D():
x = 3
#a.decorate
def func(self):
return 1
B().func() # 1
C().func() # 2
D().func() # 3
But as you can see, there is no way for the decorator to use the state of its own class. class A from this last example just happens to be a mixin with a default x variable and an "unrelated" static decorator.
So, again, is it a method?
To overcome all of this, you can bind the staticmethod in your same class to an arbitrary type. Namely, the builtin type will do.
class A:
x = 1
#staticmethod
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
#decorate.__get__(type)
def func(self):
return 1
class B:
x = 2
#A.decorate
def func(self):
return 1
class C:
x = 3
#(A().decorate) # Only for Python 3.9+, see PEP-614
def func(self):
return 1
A().func() # 1
B().func() # 2
C().func() # 3
But this features too much magic for my taste. And still not a method for my gut.
In python "self" is passed to instance methods as an argument (the first), "self" is just a convention is possible to call it "foobarbaz" (of course it would be silly)… the point is that, from the outside "self" is not defined (because its scope is the method)… you can't decorate class methods with other class methods, instead you have to write a separate class!
A descriptor class is as follows:
class Des(object):
def __get__(self, instance, owner): ...
def __set__(self, instance, value): ...
def __delete__(self, instance): ...
class Sub(object):
attr = Des()
X = sub()
Question
I don't see the point of the existence of owner, how can I use it?
To make an attr read-only, we shouldn't omit __set__ but define it to catch the assignments and raise an exception. So X.attr = 123 will fail, but __set__'s arguments doesn't contain owner, which means I can still do Sub.attr = 123, right?
See http://docs.python.org/reference/datamodel.html#implementing-descriptors:
owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner
A case where you would use owner would be creating a classproperty:
class _ContentQueryProperty(object):
def __get__(self, inst, cls):
return Content.query.filter_by(type=cls.TYPE)
You can experiment with this example:
# the descriptor protocol defines 3 methods:
# __get__()
# __set__()
# __delete__()
# any class implementing any of the above methods is a descriptor
# as in this class
class Trace(object):
def __init__(self, name):
self.name = name
def __get__(self, obj, objtype):
print "GET:" + self.name + " = " + str(obj.__dict__[self.name])
return obj.__dict__[self.name]
def __set__(self, obj, value):
obj.__dict__[self.name] = value
print "SET:" + self.name + " = " + str(obj.__dict__[self.name])
# define the attributes of your class (must derive from object)
# to be references to instances of a descriptor
class Point(object):
# NOTES:
# 1. descriptor invoked by dotted attribute access: A.x or a.x
# 2. descripor reference must be stored in the class dict, not the instance dict
# 3. descriptor not invoked by dictionary access: Point.__dict__['x']
x = Trace("x")
y = Trace("y")
def __init__(self, x0, y0):
self.x = x0
self.y = y0
def moveBy(self, dx, dy):
self.x = self.x + dx # attribute access does trigger descriptor
self.y = self.y + dy
# trace all getters and setters
p1 = Point(15, 25)
p1.x = 20
p1.y = 35
result = p1.x
p2 = Point(16, 26)
p2.x = 30
p2.moveBy(1, 1)
I came across this question with similar confusion, and after I answered it for myself it seemed prudent to report my findings here for prosperity.
As ThiefMaster already pointed out, the "owner" parameter makes possible constructions like a classproperty. Sometimes, you want classes to have methods masked as non-method attributes, and using the owner parameter allows you to do that with normal descriptors.
But that is only half the question. As for the "read-only" issue, here's what I found:
I first found the answer here: http://martyalchin.com/2007/nov/23/python-descriptors-part-1-of-2/. I did not understand it at first, and it took me about five minutes to wrap my head around it. What finally convinced me was coming up with an example.
Consider the most common descriptor: property. Let's use a trivial example class, with a property count, which is the number of times the variable count has been accessed.
class MyClass(object):
def __init__(self):
self._count = 0
#property
def count(self):
tmp = self._count
self._count += 1
return tmp
#count.setter
def setcount(self):
raise AttributeError('read-only attribute')
#count.deleter
def delcount(self):
raise AttributeError('read-only attribute')
As we've already established, the owner parameter of the __get__ function means that when you access the attribute at the class level, the __get__ function intercepts the getattr call. As it happens, the code for property simply returns the property itself when accessed at the class level, but it could do anything (like return some static value).
Now, imagine what would happen if __set__ and __del__ worked the same way. The __set__ and __del__ methods would intercept all setattr and delattr calls at the class level, in addition to the instance level.
As a consequence, this means that the "count" attribute of MyClass is effectively unmodifiable. If you're used to programming in static, compiled languages like Java this doesn't seem very interesting, since you can't modify classes in application code. But in Python, you can. Classes are considered objects, and you can dynamically assign any of their attributes. For example, let's say MyClass is part of a third-party module, and MyClass is almost entirely perfect for our application (let's assume there's other code in there besides the code for count) except that we wished the count method worked a little differently. Instead, we want it to always return 10, for every single instance. We could do the following:
>>> MyClass.count = 10
>>> myinstance = MyClass()
>>> myinstance.count
10
If __set__ intercepted the call to setattr(MyClass, 'count'), then there would be no way to actually change MyClass. Instead, the code for setcount would intercept it and couldn't do anything with it. The only solution would be to edit the source code for MyClass. (I'm not even sure you could overwrite it in a subclass, because I think defining it in a subclass would still invoke the setattr code. But I'm not sure, and since we're already dealing with a counterfactual here, I don't really have a way of testing it.)
Now, you may be saying, "That's exactly what I want! I intentionally did not want my user to reassign attributes of my class!" To that, all I can say is that what you wanted is impossible using naive descriptors, and I would direct you to the reasoning above. Allowing class attributes to be reassigned is much more in line with current Python idioms.
If you really, REALLY want to make a read-only class attribute, I don't think could tell you how. But if there is a solution, it would probably involve using metaclasses and either creating a property of the metaclass or modifying the metaclass's code for setattr and delattr. But this is Deep Magic, and well beyond the scope of this answer (and my own abilities with Python).
As far as read only properties are concerned (see discussion above), the following example shows how its done:
############################################################
#
# descriptors
#
############################################################
# define a class where methods are invoked through properties
class Point(object):
def getX(self):
print "getting x"
return self._x
def setX(self, value):
print "setting x"
self._x = value
def delX(self):
print "deleting x"
del self._x
x = property(getX, setX, delX)
p = Point()
p.x = 55 # calls setX
a = p.x # calls getX
del p.x # calls delX
# using property decorator (read only attributes)
class Foo(object):
def __init__(self, x0, y0):
self.__dict__["myX"] = x0
self.__dict__["myY"] = y0
#property
def x(self):
return self.myX
f = Foo(4,6)
print f.x
try:
f.x = 77 # fails: f.x is read-only
except Exception,e:
print e
The owner is just the class of the instance and is provided for convenience. You can always compute it from instance:
owner = instance.__class__
The __set__ method is supposed to change attributes on an instance. But what if you would like to change an attribute that is shared by all instances and therefore lives in the class, e.g., is a class attribute? This can only be done if you have access to the class, hence the owner argument.
Yes, you can overwrite the property / descriptor if you assign to an attribute through the class. This is by design, as Python is a dynamic language.
Hope that answers the question, although it was asked a long time ago.
Consider the following class :
class Token:
def __init__(self):
self.d_dict = {}
def __setattr__(self, s_name, value):
self.d_dict[s_name] = value
def __getattr__(self, s_name):
if s_name in self.d_dict.keys():
return self.d_dict[s_name]
else:
raise AttributeError('No attribute {0} found !'.format(s_name))
In my code Token have some other function (like get_all() wich return d_dict, has(s_name) which tell me if my token has a particular attribute).
Anyway, I think their is a flaw in my plan since it don't work : when I create a new instance, python try to call __setattr__('d_dict', '{}').
How can I achieve a similar behaviour (maybe in a more pythonic way ?) without having to write something like Token.set(name, value) and get(name) each I want to set or get an attribute for a token.
Critics about design flaw and/or stupidity welcome :)
Thank !
You need to special-case d_dict.
Although of course, in the above code, all you do is replicate what any object does with __dict__ already, so it's pretty pointless. Do I guess correctly if you intended to special case some attributes and actally use methods for those?
In that case, you can use properties.
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
return self._x
#x.setter
def x(self, value):
self._x = value
#x.deleter
def x(self):
del self._x
The special-casing of __dict__ works like this:
def __init__(self):
self.__dict__['d_dict'] = {}
There is no need to use a new-style class for that.
A solution, not very pythonic but works. As Lennart Regebro pointed, you have to use a special case for d_dict.
class Token(object):
def __init__(self):
super(Token,self).__setattr__('d_dict', {})
def __getattr__(self,name):
return self.a[name]
def __setattr__(self,name,value):
self.a[name] = value
You need to use new style classes.
the problem seems to be in time of evaluation of your code in __init__ method.
You could define __new__ method and initialize d_dict variable there instead of __init__.
Thats a bit hackish but it works, remember though to comment it as after few months it'll be total magic.
>>> class Foo(object):
... def __new__(cls, *args):
... my_cls = super(Foo, cls).__new__(cls, *args)
... my_cls.d_dict = {}
... return my_cls
>>> f = Foo()
>>> id(f.d_dict)
3077948796L
>>> d = Foo()
>>> id(d.d_dict)
3078142804L
Word of explanation why I consider that hackish: call to __new__ returns new instance of class so then d_dict initialised in there is kind of static, but it's initialised with new instance of dictionary each time class is "created" so everything works as you need.
It's worth remembering that __getattr__ is only called if the attribute doesn't exist in the object, whereas __setattr__ is always called.
I think we'll be able to say something about the overall design of your class if you explain its purpose. For example,
# This is a class that serves as a dictionary but also has user-defined methods
class mydict(dict): pass
# This is a class that allows setting x.attr = value or getting x.attr:
class mysetget: pass
# This is a class that allows setting x.attr = value or getting x.attr:
class mygetsethas:
def has(self, key):
return key in self.__dict__
x = mygetsethas()
x.a = 5
print(x.has('a'), x.a)
I think the last class is closest to what you meant, and I also like to play with syntax and get lots of joy from it, but unfortunately this is not a good thing. Reasons why it's not advisable to use object attributes to re-implement dictionary: you can't use x.3, you conflict with x.has(), you have to put quotes in has('a') and many more.