In the book learning python 5th edition (o'reilly Mark Lutz)page912)
class PrivateExc(Exception): pass # More on exceptions in Part VII
class Privacy:
def __setattr__(self, attrname, value): # On self.attrname = value
if attrname in self.privates:
raise PrivateExc(attrname, self) # Make, raise user-define except
else:
self.__dict__[attrname] = value # Avoid loops by using dict key
class Test1(Privacy):
privates = ['age']
class Test2(Privacy):
privates = ['name', 'pay']
def __init__(self):
self.__dict__['name'] = 'Tom' # To do better, see Chapter 39!
Maybe it is wrong in the 5th lineraise PrivateExc(attrname, self) ,
the self argument will be set as position 1st.
Will be the line changed into raise PrivateExc(self,attrname)?Why not?
Actually it doesn't matter.
Subclassing from Exception without any additional constructor doesn't restrict what you can pass as arguments to the exception class. And you can pass them in any order you want.
The arguments passed to the PrivateExc class just get stored in the instance as the instance attribute .args
Example:
>>> class MyError(Exception):
... """MyError"""
...
>>> e = MyError("foo", "bar")
>>> e.args
('foo', 'bar')
>>> e
MyError('foo', 'bar')
What this basically means in the book you're reading is;
If you were to catch the exception PrivateExc you'd do something like this:
try:
...
except PrivateExc as error:
attrname, obj = error.args
...
When you are calling a method like this:
#!/bin/python
myinstance.some_method(a,b,c)
... then this is dispatched to some_method as: some_method(myinstance, a, b, c)
The instance through which the method was invoked is passed as your first argument. This is completely different than C++ and Java ... which use an implicit "this" reference ... a pointer valid from within your method's scope but not passed to it as an argument.
I hope that answers your question, thought the code example does nothing to clarify what you're attempting to do.
I think you are just confused about parameters in function definition and function calling.
In a class, a method(instance method) has a non-optional parameter in the first position, usually named self, in the definition, like this:
class Foo:
def foo(self, another_param):
pass
And the self references the instance that you call foo function with. If you have code like this:
f=Foo()
f.foo("test")
self references the f and another_param references the "test" string in the above code.
And then in the foo function, you can use self just like other parameters.
Suppose you have a Print function like this:
def Print(x):
print "Param:", x
Then you can make you Foo class like this:
class Foo:
def foo(self, another_param):
Print(another_param) # I think this will not confuse you
Or this:
class Foo:
def foo(self, another_param):
Print(self) # Now, you may understand this, self is just a param in function calling, like another_param
And now, change the Print function to PrivateExc(you can think it a function to create a PrivateExc instance here), you may understand it either.
Hope these examples can help you understand you question.
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>
I am new to Python with Java background, the concept of "self" in function confuses me. I understand first argument "self" mean the object itself, but I do not understand how Python make this work. I also know that I could use "this" or "that" or "somethingElse", and Python would still understanding I mean to use the object.
I copied some code from a reddit post:
class A():
def __init__(self):
self.value = ""
def b(this):
this.value = "b"
def c(that):
that.value = "c"
a = A()
print(a.value)
a.b()
print(a.value)
>>>"b"
a.c()
print(a.value)
>>>"c"
How do python knows I do not mean to use an object here in the first argument? For example I modified the above code a bit:
class A():
def __init__(self):
self.value = ""
def b(this):
this.value = "b"
def c(that):
that.value = "c"
def somethingElse(someObjectIWantToPass):
someObjectIWantToPass.value = "still referring A.value"
class B():
def __init__(self):
self.value = ""
a = A()
print(a.value)
a.b()
print(a.value)
a.c()
print(a.value)
a.somethingElse()
print(a.value)
b = B()
a.somethingElse(b)
print (b.value)
And it broke:
b
c
still referring A.value
Traceback (most recent call last):
File "D:/Documents/test.py", line 32, in <module>
a.somethingElse(b)
TypeError: somethingElse() takes 1 positional argument but 2 were given
A method's first argument is always1 its instance. Calling it self is idiomatic in Python but that name is strictly convention.
class A():
def some_method(me): # not called `self`
print(str(id(me))
a = A()
a.some_method()
print(id(a))
If you're trying to pass another arbitrary object in, it has to be the second argument.
class B():
def another_method(self, other):
print(id(other))
b = B()
b.another_method(a)
print(id(b)) # different!
print(id(a)) # the same.
1 Not actually always. #classmethod decorated methods use cls as their first argument, and #staticmethod` decorated methods have nothing passed to its first argument by default.
class C():
#classmethod
def some_classmethod(cls, other, arguments):
# first argument is not the instance, but
# the class C itself.
#staticmethod
def something_related(other, arguments):
# the first argument gets neither the instance
# nor the class.
You are too focused on syntactic sugar. Just realize that the first parameter in a non static member function in python is the reference to the current object. Whether you want to call it this, that, foobar, poop, it doesn't matter. The first parameter of a member function is considered the reference to the object on which the method is called.
The use of self is just a universal way everyone has understood it and the way Python recommends - a convention if you may.
The same goes for **kwargs and *args. These are simply conventions that have permeated the Python ecosystem and everyone just uses it that way, but it doesn't mean you can't give them a different name.
Your last example broke because the function you are calling (A.something) does not take any parameters. This will make sense if you understood what I had said earlier about first parameter in non static member function being a reference to the object on which the method was called.
I tried writing a decorator as such (going off memory, excuse any problems in code):
def required(fn):
def wrapped(self):
self.required_attributes += [fn.__name__]
fn(self)
return wrapped
and I used this to decorate #property attributes in classes, e.g.:
#property
#required
def some_property(self):
return self._some_property
...so that I could do something like this:
def validate_required_attributes(instance):
for attribute in instance.required_attributes:
if not hasattr(instance, attribute):
raise ValueError(f"Required attribute {attribute} was not set!")
Now I forgot that this wouldn't work because in order for the required_attributes to be updated with the name of the property, I would have to retrieve the property first. So in essence, when I do init in the class, I can just do a self.propertyname to add it... but this solution is not nice at all, I might as well create a list of required attribute names in the init.
From what I know, the decorator is applied at compile time so I wouldn't be able to modify the required_attributes before defining the wrapped function. Is there another way I can make this work? I just want a nice, elegant solution.
Thanks!
I think the attrs library does what you want. You can define a class like this, where x and y are required and z is optional.
from attr import attrs, attrib
#attrs
class MyClass:
x = attrib()
y = attrib()
z = attrib(default=0)
Testing it out:
>>> instance = MyClass(1, 2)
>>> print(instance)
MyClass(x=1, y=2, z=0)
Here's my take at doing it with a class decorator and a method decorator. There's probably a nicer way of doing this using metaclasses (nice being the API not the implementation ;)).
def requiredproperty(f):
setattr(f, "_required", True)
return property(f)
def hasrequiredprops(cls):
props = [x for x in cls.__dict__.items() if isinstance(x[1], property)]
cls._required_props = {k for k, v in props if v.fget._required}
return cls
#hasrequiredprops
class A(object):
def __init__(self):
self._my_prop = 1
def validate(self):
print("required attributes are", ",".join(self._required_props))
#requiredproperty
def my_prop(self):
return self._my_prop
This should make validation work without the requiring the caller to touch the property first:
>>> a = A()
>>> a.validate()
required attributes are my_prop
>>> a.my_prop
1
The class decorator is required to make sure it has the required property names duing instantiation. The requiredproperty function is just a way to mark the properties as required.
That being said, I'm not completely sure what you are trying to achieve here. Perhaps validation of the instance attribute values that the property should return?
If you have a class that can store a function, in my case used as a callback, and I want to call this function without having to also give self as a parameter how do I do that? As en example:
class foo:
def __init__(self, fun):
self.fun = fun
def call_fun(self):
self.fun()
Now, I would have expected this forces fun to look like:
def fun(foreign_self):
pass
since I expected object.fun() to be a shortcut for fun(object).
Edit: Updated the question to correctly reflect the situation.
Now, this forces fun to look like: def fun(foreign_self)
No, it does not.
fun doesn't have to accept anything:
class foo:
def __init__(self, fun):
self.fun = fun
def call_fun(self):
print(self.fun)
# <function fun at 0x02269588>
self.fun()
def fun():
print('in fun')
f = foo(fun)
f.fun()
# 'in fun'
f.call_fun()
# 'in fun'
print(f.call_fun)
# <bound method foo.call_fun of <__main__.foo object at 0x022239D0>>
Note that fun is a function while call_fun is an instance method. call_fun just happens to call the fun function by a reference that is kept within the instance.
Suppose I have a class Foo, I want to define a function that receives the class constructor as a parameter:
def bar(class_name):
local_class = None
# TODO: if I call bar(Foo()), I want to get local_class = Foo()
How can I implement the function?
The following bar function will work. Note, the first parameter will be a class itself and not the name of a class, so "class_name", which implies that it's a str, is misleading. args will be a tuple of args to initialize klass objects with, *-unpacked in the calls to klass. You said in a later comment that you wanted to "create multiple independent objects", all of the same class and initialized with the same args, so I've revised my answer to reflect that:
def bar(klass, *args):
# Now you can create multiple independent objects of type klass,
# all initialized with the same args
obj1 = klass(*args)
obj2 = klass(*args)
# ...
# do whatever you have in mind with the objs
Your "local_class" isn't a class at all, but rather an instance of klass, so that's a bad name; and anyway you want several of them.
Assuming Foo objects are initialized with three int arguments, and Baz objects with two strings, you can call bar like so:
bar(Foo, 1, 2, 3)
bar(Baz, 'Yo', 'bro')
etc.
Especially in a dynamically-typed language like Python, reasoning about code is more difficult when variables have misleading names.
When can pass the classname as an argument to your function, and then call class_name(). E.g., if you also want to pass arguments.
class Foo:
def __init__(self, arg1, arg2):
pass
def bar1(class_name):
args = ("val1", "val2")
local_class = class_name(*args)
or
def bar2(class_name):
kwargs = {'arg1':'val1','arg2':'val2'}
local_class = class_name(**kwargs)
You can call the functions like:
one = bar1(Foo)
two = bar2(Foo)
If you really want to call the class from a string read this post. I would suggest you use #Evan Fosmark's solution because use of eval and globals should be avoided