I have a class like this:
class Rank (models.Model):
respect=models.IntegerField(max_length=3)
#some other attributes
Rank has many attributes (the first of which is respect).
The names of the attributes of Rank are stored in the list, attributes.
I would like to iterate through them, setting them to somevalue, an arbitrary variable.
I'm attempting:
rank=Rank()
for att in attributes:
rank.att=somevalue #I want rank.(value of att) instead of this
I think what you're trying to do is set a value to an attribute by name. This is what the setattr built in method is for.
rank=Rank()
for att in attributes:
setattr(rank, att, somevalue)
You can use the *args or **kwargs wildcard argument. Try the following to see how it works:
def foo(*args, **kwargs):
print args
print kwargs
foo(1,2,3)
foo(a=1,b=2,c=3)
foo(1,2,z=3)
You can inject attributes to objects using setattr
for att in attributes:
setattr(classobj, att.name, att.value)
Note however that this may work or not because the class could have been based on a metaclass that inspects the attributes when creating the class object.
Adding attributes or methods later may work or not, depending on what kind of magic has been used in the metaclass.
If the class wants to inspect the attributes at creation time the only solution (without messing with the class specific magic) is using eval of a string.
In general, you can't pass a name of a variable to a function - python is call by value only*
What you can do, and I think this is what you want, is use getattr and setattr:
for att in attributes:
print getattr(rank, att)
setattr(rank, att, somevalue)
* I'm aware of the sect who believe that Python has some other calling convention. It's not a thing.
Related
I have a list of settings defaults held within my init function. These defaults are all instance variables. For example,
self.set_acqmode = 1
self.set_readmode = 4
self.set_triggermode = 0
I have a function within this class which I want to use to change these default settings by only passing in a name and a value as arguments. For example,
def change_setting(self, setting, *arg):
What would be a pythonic way of accessing and changing the correct instance variable. I have tried using both vars() and dict to view these variables but the former only showed the the classes functions and the latter needs to refer to a instance of the class (which won't exist yet as this is within the class).
(If there is a better way of doing this without searching for the variables I would still like to know how to view them, just out of interest.)
Use setattr:
def change_setting(self, setting, *arg):
setattr(self, setting, arg)
setattr will work. But you have to ask, if you're going through all this trouble to rewrite setattr, are you even doing this the right way?
If you just want to have some arbitrary keys & values - well, that's a dictionary, and you should use it as such. override __getitem__/__setitem__ if you need custom behaviour.
if you really need attributes, then there's no reason a parent function wouldn't just do
myobj.set_triggermode = value
rather than the overly complex
myobj.change_setting('triggermode', value)
so you should do that. and even if you want to do that for some reason - use kwargs instead of args, probably closer to what you want.
You can certainly use __dict__:
>>> class Test(object):
def __init__(self):
self.x = 1
def set(self, attr, val):
self.__dict__[attr] = val
>>> a = Test()
>>> a.set('x', 2)
>>> a.x
2
You can use __dict__ on the name of a class without having instantiated an object of that class. For example:
print myClass.__dict__.keys()
::edit:: Of course, if you're being rigorous in your programming, you may consider using __slots__, in which case you will have predefined all the instance variables of your class by yourself.
I have class with custom getter, so I have situations when I need to use my custom getter, and situations when I need to use default.
So consider following.
If I call method of object c in this way:
c.somePyClassProp
In that case I need to call custom getter, and getter will return int value, not Python object.
But if I call method on this way:
c.somePyClassProp.getAttributes()
In this case I need to use default setter, and first return need to be Python object, and then we need to call getAttributes method of returned python object (from c.somePyClassProp).
Note that somePyClassProp is actually property of class which is another Python class instance.
So, is there any way in Python on which we can know whether some other methods will be called after first method call?
No. c.someMethod is a self-contained expression; its evaluation cannot be influenced by the context in which the result will be used. If it were possible to achieve what you want, this would be the result:
x = c.someMethod
c.someMethod.getAttributes() # Works!
x.getAttributes() # AttributeError!
This would be confusing as hell.
Don't try to make c.someMethod behave differently depending on what will be done with it, and if possible, don't make c.someMethod a method call at all. People will expect c.someMethod to return a bound method object that can then be called to execute the method; just define the method the usual way and call it with c.someMethod().
You don't want to return different values based on which attribute is accessed next, you want to return an int-like object that also has the required attribute on it. To do this, we create a subclass of int that has a getAttributes() method. An instance of this class, of course, needs to know what object it is "bound" to, that is, what object its getAttributes() method should refer to, so we'll add this to the constructor.
class bound_int(int):
def __new__(cls, value, obj):
val = int.__new__(cls, value)
val.obj = obj
return val
def getAttributes(self):
return self.obj.somePyClassProp
Now in your getter for c.somePyClassProp, instead of returning an integer, you return a bound_int and pass it a reference to the object its getAttributes() method needs to know about (here I'll just have it refer to self, the object it's being returned from):
#property
def somePyClassProp(self):
return bound_int(42, self)
This way, if you use c.somePyPclassProp as an int, it acts just like any other int, because it is one, but if you want to further call getAttributes() on it, you can do that, too. It's the same value in both cases; it just has been built to fulfill both purposes. This approach can be adapted to pretty much any problem of this type.
It looks like you want two ways to get the property depending on what you want to do with it. I don't think there's any inherent Pythonic way to implement this, and you therefore need to store a variable or property name for each case. Maybe:
c.somePyClassProp
can be used in the __get__ and
c.somePyClassProp__getAttributes()
can be implemented in a more custom way inside the __getattribute__ function.
One way I've used (which is probably not the best) is to check for that exact variable name:
def __getattribute__(self, var_name):
if ('__' in var_name):
var_name, method = var_name.split('__')
return object.__getattribute__(self, var_name).__getattribute__(method)
Using object.__get__(self, var_name) uses the object class's method of getting a property directly.
You can store the contained python object as a variable and the create getters via the #property dectorator for whatever values you want. When you want to read the int, reference the property. When you want the contained object, use its variable name instead.
class SomePyClass(object):
def getInt(self):
return 1
def getAttributes(self):
return 'a b c'
class MyClass(object):
def __init__(self, py_class):
self._py_class = py_class
#property
def some_property(self):
return self._py_class.getInt()
x = MyClass(SomePyClass())
y = self.some_property
x._py_class.getAttributes()
I am reading this Genshi Tutorial and see there the following example:
from formencode import Schema, validators
class LinkForm(Schema):
username = validators.UnicodeString(not_empty=True)
url = validators.URL(not_empty=True, add_http=True, check_exists=False)
title = validators.UnicodeString(not_empty=True)
As far as I understand this example, we create a new class that inherits Schema class and this class contain three methods: username, url, title. However, I am not sure about the last because before I only saw methods created with def.
Anyway, my question is not about that. I would like to know if it is possible to make the definition of the class dynamic. For example, sometimes I do not want url or title to be in the class. It seems to be doable (I just use if and assign a value to url only if-statement is satisfied.
But what if I do not know in advance what fields I would like to have in the form? For example, now I have username, url and title. But what if later I would like to have city or age. Can I do something like that:
from formencode import Schema, validators
class LinkForm(Schema):
__init__(self, fields):
for field in fields:
condition = fields[field]
field = validators.UnicodeString(condition)
I think it will not work. Is there a work around in this case?
Yes, you can add methods to an instance dynamically. No, you can't do what you want.
You can bind methods to the instance in the initializer. Unfortunately what you have there are descriptors and those must be bound to the class.
I would go the other way round—first define all form fields that might be used, and delete unneeded ones later.
Provided that you have:
from formencode import Schema, validators
class LinkForm(Schema):
username = validators.UnicodeString(not_empty=True)
url = validators.URL(not_empty=True, add_http=True, check_exists=False)
title = validators.UnicodeString(not_empty=True)
you could do either this:
def xy():
my_form = LinkForm()
del my_form.url
…
… or this:
def xy():
class CustomLinkForm(LinkForm):
pass
if …:
del CustomLinkForm.url
…
Disclaimer: I am not familiar with FormEncode, so it might depend on its inner workings which of these two versions actually works.
of course you can have a constructor with some arguments after self and these arguments will be the value for some members of your class if you have for instance
__init__(self, fields):
self.fields = []
for field in fields:
self.fields = self.fields + field
see this in Dive into Python
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename
Classes can (and should) have doc strings too, just like modules and
functions.
init is called immediately after an instance of the
class is created. It would be tempting but incorrect to call this the
constructor of the class. It's tempting, because it looks like a
constructor (by convention, init is the first method defined for
the class), acts like one (it's the first piece of code executed in a
newly created instance of the class), and even sounds like one (“init”
certainly suggests a constructor-ish nature). Incorrect, because the
object has already been constructed by the time init is called,
and you already have a valid reference to the new instance of the
class. But init is the closest thing you're going to get to a
constructor in Python, and it fills much the same role.
The first
argument of every class method, including init, is always a
reference to the current instance of the class. By convention, this
argument is always named self. In the init method, self refers to
the newly created object; in other class methods, it refers to the
instance whose method was called. Although you need to specify self
explicitly when defining the method, you do not specify it when
calling the method; Python will add it for you automatically.
init methods can take any number of arguments, and just like
functions, the arguments can be defined with default values, making
them optional to the caller. In this case, filename has a default
value of None, which is the Python null value.
Note that in the later example you learn how to deal with inherited class, calling __init()__ for this inherited class.
To answer your not-a-question about class or instance variables, see this
Variables defined in the class definition are class variables; they
are shared by all instances. To create instance variables, they can be
set in a method with self.name = value. Both class and instance
variables are accessible through the notation “self.name”, and an
instance variable hides a class variable with the same name when
accessed in this way. Class variables can be used as defaults for
instance variables, but using mutable values there can lead to
unexpected results. For new-style classes, descriptors can be used to
create instance variables with different implementation details.
I'm new to using classes and I'm trying to pass a variable to one of the methods inside of my class. How do I do it?
Here's an example of what I'm trying to accomplish:
class a_class():
def a_method(txt):
print txt
instance = a_class()
instance.a_method('hello world!)
P.S. I don't understand the whole self and __blah__ concepts yet, and I will avoid them at this point if I don't have to use them.
When writing an instance method for a class in Python- which looks exactly like what you've just coded up- you can't avoid using self. The first parameter to an instance method in Python is always the object the method is being called on. self is not a reserved word in Python- just the traditional name for that first parameter.
To quote from the official Python tutorial, chapter 9:
[...] 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.
Therefore, you need to define two parameters for your method. The first is always self- at least that is the conventional name- and the second is your actual parameter. So your code snippet should be:
class a_class(object):
def a_method(self, txt):
print txt
instance = a_class()
instance.a_method('hello world!')
Note that the class explicitly inherits from object (I'm not sure empty parentheses there are legal). You can also provide no inheritance, which is identical for most purposes, but different in some details of the behavior of the type system; the inheritance from object defines a_class as a new-style class rather than an old-style class, which is irrelevant for most purposes but probably worth being aware of.
You need to have
class a_class():
def a_method(self,txt):
print txt
The first variable of a class method always contains a reference to the object no matter what variable name you use. (Unless you are using it as a static method).
Instance Methods in Python must be provided the instance (given as self) as the first parameter in the method signature.
class a_class():
def a_method(self,txt):
print txt
That should be what you're looking for. Additionally, if you were to interact with a member variable you'd want to do something like this:
class a_class():
name = "example"
def a_method(self,txt):
print txt
print self.name
The self concept and the use of __init__ really isn't that confusing and it is essential to writing good Python code. __init__ is called on instantiation of a class, and simply include a self parameter in every class method, you can then use self to reference the instance of the class.
class a_class():
def __init__(self):
self.count = 0
def a_method(self, txt):
self.count += 1
print str(self.count), txt
instance = a_class()
instance.a_method('hello world!')
# prints "1 hello world!"
instance.a_method('hello again!')
# prints "2 hello again!"
I know that I can dynamically add an instance method to an object by doing something like:
import types
def my_method(self):
# logic of method
# ...
# instance is some instance of some class
instance.my_method = types.MethodType(my_method, instance)
Later on I can call instance.my_method() and self will be bound correctly and everything works.
Now, my question: how to do the exact same thing to obtain the behavior that decorating the new method with #property would give?
I would guess something like:
instance.my_method = types.MethodType(my_method, instance)
instance.my_method = property(instance.my_method)
But, doing that instance.my_method returns a property object.
The property descriptor objects needs to live in the class, not in the instance, to have the effect you desire. If you don't want to alter the existing class in order to avoid altering the behavior of other instances, you'll need to make a "per-instance class", e.g.:
def addprop(inst, name, method):
cls = type(inst)
if not hasattr(cls, '__perinstance'):
cls = type(cls.__name__, (cls,), {})
cls.__perinstance = True
inst.__class__ = cls
setattr(cls, name, property(method))
I'm marking these special "per-instance" classes with an attribute to avoid needlessly making multiple ones if you're doing several addprop calls on the same instance.
Note that, like for other uses of property, you need the class in play to be new-style (typically obtained by inheriting directly or indirectly from object), not the ancient legacy style (dropped in Python 3) that's assigned by default to a class without bases.
Since this question isn't asking about only adding to a spesific instance,
the following method can be used to add a property to the class, this will expose the properties to all instances of the class YMMV.
cls = type(my_instance)
cls.my_prop = property(lambda self: "hello world")
print(my_instance.my_prop)
# >>> hello world
Note: Adding another answer because I think #Alex Martelli, while correct, is achieving the desired result by creating a new class that holds the property, this answer is intended to be more direct/straightforward without abstracting whats going on into its own method.