How can I define a class attribute from a variable in Python? - python

I need to access a variable from a nested class. The objective is to create a Schema using the Marshmallow library. The code looks like this :
class ParserScheme(Schema):
class Meta:
# Here I meed to access the value of my_variable :
result = func(my_variable)
my_variable = 'foo'
my_parser = ParserScheme()
If I manage to pass my variable as a class attribute of the outer class (ParserScheme), then it is easy to get it into the inner class (Meta).
class ParserScheme(Schema):
class_attribute = my_variable
class Meta:
result = func(ParserScheme.class_attribute)
my_variable = 'foo'
my_parser = ParserScheme()
However I can't seem to find a way to dynamically set a class attribute. And if I set a "classic" attribute (I mean an attribute of instances of the class, not of the class itself), then I can't access it from the inner class.
I also thought of using a global variable, but that does not really quite satisfy me. Is there another way of doing this ?
I am rather new to OOP, and I am not sure I understand really well the concept of class attribute. I fear that there is an easy way to do that but I did not see it as I am to focused on the way I think this should work...

Your first example breaks because name my_variable is not yet defined when the class Meta statement's body is executed.
You second example won't work either for the same reason (my_variable is not yet defined when the class ParserScheme statement's body is executed), and if it was it would still break when executing the class Meta statement's body because it will be executed as part of the class ParserScheme statement's body hence before the name ParserScheme is defined.
What you have to understand here is that class and def are executable statements which (if at the top level of a module) are executed sequentially when the module is first imported into the current process. In the case of a class statement, the statement's body is first sequentially executed in a dedicated namespace then this namespace is passed to the metaclass constructor and used to create the class object's attributes (YourClass.__dict__).
To make a long story short: in a class statement body, you just cannot reference names that are not yet defined in the current or enclosing scope. Period.
The obvious solution here would be to define my_variable before the class statement, but I assume you want it to be more dynamic ? If yes, you'll have to define your class in a function:
def create_parser_class(my_variable):
class ParserScheme(Schema):
class Meta:
result = func(my_variable)
return ParserScheme
my_variable = 42
cls = create_parser_class(my_variable)
my_parser = cls()
But I can't garantee it will work out of the box (nor even work at all FWIW) with Marshmallow (which I never used but probably has some metaclass stuff happening). Also depending on what my_variable is used for, you may want to make sure you don't have two calls to create_parser_class with the same value as argument.
As a last note : you perhaps have a XY problem here - that's sometimes the case when someone asks how to do something a bit non-obvious or unusual. Perhaps you should edit your post to explain the "problem behind" - that is, the problem you are actually trying to solve with this "solution".
Oh and yes:
I am rather new to OOP, and I am not sure I understand really well the concept of class attribute
In Python, classes are objects too (instances of their metaclass, by default the type object), and as such they have their own attributes. Every name you define (with an assignment, a def statement, a class statement or an import statement) at the top-level of the class statement becomes an attribute of the class object (unless a custom metaclass makes some transformations on the way, that is).
Class attributes are accessible from the instances too (unless shadowed by an eponym instance variable), and are shared between all instances.

Related

How to access Child Class members in Parent class in Python

Short version: For normal Object members, this is simple - you just use self.member in the parent, and the child can override the member and everything is happily object orientated. But what about class members that may get overriden by a child class?
To make that clear:
I know in Python I can just give Classname.membername but how do I allow Class members to be overriden? For example I have
class BaseDB:
user_table = "users"
# Class member function
def make_sql():
return f'SELECT * from {BaseDB.user_table};'
# Boilerplate functions that use "user_table"
def load_users(self):
return db.connection.cursor.execute(BaseDB.make_sql())
class SomeDatabase(BaseDB):
user_table = "the_users_table"
# Somewhere else in the code....
dbwrapper = SomeDatabase()
dbwrapper.load_users() # This does not use the overwridden value in SomeDatabase, it uses the value form the parent class
What I'm looking for something like self, but for the Class, not for the object.
At first I thought I could try and use type(self).class_member .... Not sure if that would even work, but self might not be available, eg in a non-class member method.
My workaround at present is to use normal object members - right now I don't have a requirement to access these from a class method. The only reason why I want to make these into Class members is because the values are constant for the class, not the object.
Edit: Added the somewhat contrived Class member function make_sql and used it in the normal member function.
Note: The derived class only sets the class member - Nothing else is overridden.
Note #2 - This is not a major obstacle. If there is a solution, I am sure I can use it ... if not, I've been getting along without it fine, so I'm just asking to find out if I'm missing out on something.
EDIT #2:
I just thought I should put the code into my IDE and see if I had any errors (I'm lazy). The IDE told me I need to have a "self" on the class member so I annotated it with #classmember. The IDE told me "Well then you should have a cls parameter. VOILA! This solves the problem, of course.

Method reference in attribute before method is defined causing error

I don't understand why this works;
class parentClass(object):
pass
class childClass(parentClass):
def my_meth(var):
print(var)
a = {'meth': my_meth}
x = childClass.a['meth']("Helloworld")
Whilst this fails;
class parentClass(object):
pass
class childClass(parentClass):
a = {'meth': my_meth}
def my_meth(var):
print(var)
x = childClass.a['meth']("Helloworld")
It would seem that a class is read line by line on execution and if the method definition has not been parsed before it is referenced within an attribute, an error occurs?
Is this true? Why does this occur in class/static attributes whilst you can def methods in any order and reference them from other methods written above or below them?
Is there a way to keep the class attributes at the top of the class to preserve readability and consistent layout?
It would seem that a class is read line by line on execution and if the method definition has not been parsed before it is referenced within an attribute, an error occurs?
Yes, that is true. Class definitions are executed from top to bottom, just like module-level code. You can even put things like if/else statements and for loops directly inside the class body.
Is there a way to keep the class attributes at the top of the class to preserve readability and consistent layout?
Your first example is fine. The order is not considered strange in Python.
That said, you do have potential alternatives. You could, for example, create a #classmethod to initialize class attributes at the top of the class, and then call immediately after the class declaration, e.g.
class childClass(parentClass):
#classmethod
def _initialize(cls)
cls.a = {'meth': cls.my_meth}
def my_meth(var):
print(var)
childClass._initialize()
You could even write a class decorator to do this step for you (if you think that's prettier), as they execute after the class declaration code has completed execution.
Why does this occur in class/static attributes whilst you can def methods in any order and reference them from other methods written above or below them?
Executing a function definition is different from calling the function object it creates. The former just creates the function object and assigns its name to the local context. The latter runs its code.
Classes are just fancy dicts. You can swap attributes in and out of them at runtime. When you do a self.foo() inside of a method bar, the . operator is doing an attribute lookup of the foo attribute on the self object. It's a similar idea when using cls.foo() in a classmethod.
It's entirely possible to write a function that references an attribute that doesn't exist. It will fail with an AttributeError, of course, if you call it, but if somehow the attribute gets set later, then you can call it successfully.

how can i add data in a class object after i ran def __init__(self) function?

i created this class for my homework:
class sayfa():
isim=" "
def __init__(self,bSayisi,ySayisi,pSayisi,iSayisi,tSayisi):
self.bSayisi=bSayisi
self.ySayisi=ySayisi
self.pSayisi=pSayisi
self.iSayisi=iSayisi
self.tSayisi=tSayisi
if ((((bSayisi+ySayisi+pSayisi)/iSayisi)/tSayisi)*100)>0.2:
print(isim,"başarılı")
else:
print(isim,"başarısız")
then i called it in another .py file:
from eRate import sayfa
ybs1=sayfa(365000,65000,870,500,1125000)
ybs1.isim="YBS-1"
then i tried to work it and it gave me this error:
NameError: name 'isim' is not defined
I think i did something wrong when i'm writing class but i don't know what i actually done wrong.Can you help me?
edit:
My code worked when i put isim variable in def init but it looks weird.It looks like this:
class sayfa():
def __init__(self,bSayisi,ySayisi,pSayisi,iSayisi,tSayisi,isim):
self.isim=str(isim)
self.bSayisi=bSayisi
self.ySayisi=ySayisi
self.pSayisi=pSayisi
self.iSayisi=iSayisi
self.tSayisi=tSayisi
if ((((bSayisi+ySayisi+pSayisi)/iSayisi)/tSayisi)*100)>0.2:
print(isim,"başarılı")
else:
print(isim,"başarısız")
and when i'm adding data in class it gets weirder:
from eRate import sayfa
ybs1=sayfa(365000,65000,870,500,1125000,"YBS-1")
The error isn't with the way you're assigning things, but with the way you're accessing them.
Just as you have to do self.bSayisi to set an attribute, you have to do self.isim to access one. So:
print(self.isim, "başarılı")
(and the same for the other line…)
If you're wondering why you were able to access other values like bSayisi without self.bSayisi—that's just because you happen to have a parameter named bSayisi that happens to have the same value as self.bSayisi (because you just made that true a few lines earlier). If you changed it to, say, self.bSayisi = bSayisi*2, or you renamed the parameter to myBSayisi and did self.bSayisi = myBSayisi, you'd see that just using bSayisi instead of self.bSayisi was no longer correct.
However, while this eliminates the error, I'm not sure it actually does what you want. At the time you're doing this print, you haven't assigned an isim value to the object yet, so it's going to get the class value as a default, so it's always just going to be " ". Is that really what you wanted?
If not, you need to move the print calls to some other method that you can call later, after having assigned isim. For example:
class sayfa():
isim=" "
def __init__(self,bSayisi,ySayisi,pSayisi,iSayisi,tSayisi):
self.bSayisi=bSayisi
self.ySayisi=ySayisi
self.pSayisi=pSayisi
self.iSayisi=iSayisi
self.tSayisi=tSayisi
def displaystuff(self):
if ((((self.bSayisi+self.ySayisi+self.pSayisi)/self.iSayisi)/self.tSayisi)*100)>0.2:
print(self.isim,"başarılı")
else:
print(self.isim,"başarısız")
ybs1=sayfa(365000,65000,870,500,1125000)
ybs1.isim="YBS-1"
ybs1.displaystuff()
Of course moving the isim into the constructor works, by avoiding the problem you were running into. It's not an answer to how to add data after the __init__ method, of course, because you're instead adding the data in the __init__ method. When that's appropriate, it's the simplest answer.
But if it looks weird in this case (I'll take your word for it; I don't know exactly what this code is trying to do), it's probably the wrong answer for this particular class.
In which case, you do need to know how to add data after the __init__ method, as you asked. Or, rather, you need to know how to access that data—because you were already adding it correctly.
This is the difference between class attributes (when it is outside of the __init__ with no self.) and instance attributes (when you added it inside the __init__ with the self.).
Class attributes are a little more complicated since they pertain to all the instances of that class (you could overwrite them within some instances, but then they'd become instance attributes in those cases)... and so if you changed a class attribute, it would affect all other instances you may have created or will create in the future.
For a more in-depth discussion of class attributes vs instance attributes see this answer that summarizes this post.
Normall __init__(..) is used to initialize / instantiate your instance. I would not print in it, nor calculate (unless you calculate some other class-variables and set them).
You need to prefix your variables of the instance by self. and the static class variable with the class name to acess it:
class sayfa():
isim=" " # this is a shared class variabl (aka static)
def __init__(self,bSayisi,ySayisi,pSayisi,iSayisi,tSayisi):
self.bSayisi=bSayisi # these are all instance variables, not shared
self.ySayisi=ySayisi
self.pSayisi=pSayisi
self.iSayisi=iSayisi
self.tSayisi=tSayisi
self.unusedSum = ySayisi + pSayisi + iSayisi
def printMe(self): # lookup __str__() and __repr__() for how to output your instance
if ((((self.bSayisi+self.ySayisi+self.pSayisi)/self.iSayisi)/self.tSayisi)*100)>0.2:
print(sayfa.isim,"some text") # use the static class variable
else:
print(sayfa.isim,"some other text")
sayfa.isim = "Coffee " # you set static class variables by prefixing class name
my_sayfa_instance = sayfa(365000,65000,870,500,1125000)
other_sayfa_instance = sayfa(3600,65000,870,500,10)
my_sayfa_instance.printMe()
other_sayfa_instance.printMe()
Output:
Coffee some other text
Coffee some text

Instance variables in methods outside the constructor (Python) -- why and how?

My questions concern instance variables that are initialized in methods outside the class constructor. This is for Python.
I'll first state what I understand:
Classes may define a constructor, and it may also define other methods.
Instance variables are generally defined/initialized within the constructor.
But instance variables can also be defined/initialized outside the constructor, e.g. in the other methods of the same class.
An example of (2) and (3) -- see self.meow and self.roar in the Cat class below:
class Cat():
def __init__(self):
self.meow = "Meow!"
def meow_bigger(self):
self.roar = "Roar!"
My questions:
Why is it best practice to initialize the instance variable within the constructor?
What general/specific mess could arise if instance variables are regularly initialized in methods other than the constructor? (E.g. Having read Mark Lutz's Tkinter guide in his Programming Python, which I thought was excellent, I noticed that the instance variable used to hold the PhotoImage objects/references were initialized in the further methods, not in the constructor. It seemed to work without issue there, but could that practice cause issues in the long run?)
In what scenarios would it be better to initialize instance variables in the other methods, rather than in the constructor?
To my knowledge, instance variables exist not when the class object is created, but after the class object is instantiated. Proceeding upon my code above, I demonstrate this:
>> c = Cat()
>> c.meow
'Meow!'
>> c.roar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Cat' object has no attribute 'roar'
>>> c.meow_bigger()
>>> c.roar
'Roar!'
As it were:
I cannot access the instance variable (c.roar) at first.
However, after I have called the instance method c.meow_bigger() once, I am suddenly able to access the instance variable c.roar.
Why is the above behaviour so?
Thank you for helping out with my understanding.
Why is it best practice to initialize the instance variable within the
constructor?
Clarity.
Because it makes it easy to see at a glance all of the attributes of the class. If you initialize the variables in multiple methods, it becomes difficult to understand the complete data structure without reading every line of code.
Initializing within the __init__ also makes documentation easier. With your example, you can't write "an instance of Cat has a roar attribute". Instead, you have to add a paragraph explaining that an instance of Cat might have a "roar" attribute, but only after calling the "meow_louder" method.
Clarity is king. One of the smartest programmers I ever met once told me "show me your data structures, and I can tell you how your code works without seeing any of your code". While that's a tiny bit hyperbolic, there's definitely a ring of truth to it. One of the biggest hurdles to learning a code base is understanding the data that it manipulates.
What general/specific mess could arise if instance variables are
regularly initialized in methods other than the constructor?
The most obvious one is that an object may not have an attribute available during all parts of the program, leading to having to add a lot of extra code to handle the case where the attribute is undefined.
In what scenarios would it be better to initialize instance variables
in the other methods, rather than in the constructor?
I don't think there are any.
Note: you don't necessarily have to initialize an attribute with it's final value. In your case it's acceptable to initialize roar to None. The mere fact that it has been initialized to something shows that it's a piece of data that the class maintains. It's fine if the value changes later.
Remember that class members in "pure" Python are just a dictionary. Members aren't added to an instance's dictionary until you run the function in which they are defined. Ideally this is the constructor, because that then guarantees that your members will all exist regardless of the order that your functions are called.
I believe your example above could be translated to:
class Cat():
def __init__(self):
self.__dict__['meow'] = "Meow!"
def meow_bigger(self):
self.__dict__['roar'] = "Roar!"
>>> c = Cat() # c.__dict__ = { 'meow': "Meow!" }
>>> c.meow_bigger() # c.__dict__ = { 'meow': "Meow!", 'roar': "Roar!" }
To initialize instance variables within the constructor, is - as you already pointed out - only recommended in python.
First of all, defining all instance variables within the constructor is a good way to document a class. Everybody, seeing the code, knows what kind of internal state an instance has.
Secondly, order matters. if one defines an instance variable V in a function A and there is another function B also accessing V, it is important to call A before B. Otherwise B will fail since V was never defined. Maybe, A has to be invoked before B, but then it should be ensured by an internal state, which would be an instance variable.
There are many more examples. Generally it is just a good idea to define everything in the __init__ method, and set it to None if it can not / should not be initialized at initialization.
Of course, one could use hasattr method to derive some information of the state. But, also one could check if some instance variable V is for example None, which can imply the same then.
So in my opinion, it is never a good idea to define an instance variable anywhere else as in the constructor.
Your examples state some basic properties of python. An object in Python is basically just a dictionary.
Lets use a dictionary: One can add functions and values to that dictionary and construct some kind of OOP. Using the class statement just brings everything into a clean syntax and provides extra stuff like magic methods.
In other languages all information about instance variables and functions are present before the object was initialized. Python does that at runtime. You can also add new methods to any object outside the class definition: Adding a Method to an Existing Object Instance
3.) But instance variables can also be defined/initialized outside the constructor, e.g. in the other methods of the same class.
I'd recommend providing a default state in initialization, just so its clear what the class should expect. In statically typed languages, you'd have to do this, and it's good practice in python.
Let's convey this by replacing the variable roar with a more meaningful variable like has_roared.
In this case, your meow_bigger() method now has a reason to set has_roar. You'd initialize it to false in __init__, as the cat has not roared yet upon instantiation.
class Cat():
def __init__(self):
self.meow = "Meow!"
self.has_roared = False
def meow_bigger(self):
print self.meow + "!!!"
self.has_roared = True
Now do you see why it often makes sense to initialize attributes with default values?
All that being said, why does python not enforce that we HAVE to define our variables in the __init__ method? Well, being a dynamic language, we can now do things like this.
>>> cat1 = Cat()
>>> cat2 = Cat()
>>> cat1.name = "steve"
>>> cat2.name = "sarah"
>>> print cat1.name
... "steve"
The name attribute was not defined in the __init__ method, but we're able to add it anyway. This is a more realistic use case of setting variables that aren't defaulted in __init__.
I try to provide a case where you would do so for:
3.) But instance variables can also be defined/initialized outside the constructor, e.g. in the other methods of the same class.
I agree it would be clear and organized to include instance field in the constructor, but sometimes you are inherit other class, which is created by some other people and has many instance fields and api.
But if you inherit it only for certain apis and you want to have your own instance field for your own apis, in this case, it is easier for you to just declare extra instance field in the method instead override the other's constructor without bothering to deep into the source code. This also support Adam Hughes's answer, because in this case, you will always have your defined instance because you will guarantee to call you own api first.
For instance, suppose you inherit a package's handler class for web development, you want to include a new instance field called user for handler, you would probability just declare it directly in the method--initialize without override the constructor, I saw it is more common to do so.
class BlogHandler(webapp2.RequestHandler):
def initialize(self, *a, **kw):
webapp2.RequestHandler.initialize(self, *a, **kw)
uid = self.read_cookie('user_id') #get user_id by read cookie in the browser
self.user = User.by_id(int(uid)) #run query in data base find the user and return user
These are very open questions.
Python is a very "free" language in the sense that it tries to never restrict you from doing anything, even if it looks silly. This is why you can do completely useless things such as replacing a class with a boolean (Yes you can).
The behaviour that you mention follows that same logic: if you wish to add an attribute to an object (or to a function - yes you can, too) dynamically, anywhere, not necessarily in the constructor, well... you can.
But it is not because you can that you should. The main reason for initializing attributes in the constructor is readability, which is a prerequisite for maintenance. As Bryan Oakley explains in his answer, class fields are key to understand the code as their names and types often reveal the intent better than the methods.
That being said, there is now a way to separate attribute definition from constructor initialization: pyfields. I wrote this library to be able to define the "contract" of a class in terms of attributes, while not requiring initialization in the constructor. This allows you in particular to create "mix-in classes" where attributes and methods relying on these attributes are defined, but no constructor is provided.
See this other answer for an example and details.
i think to keep it simple and understandable, better to initialize the class variables in the class constructor, so they can be directly called without the necessity of compiling of a specific class method.
class Cat():
def __init__(self,Meow,Roar):
self.meow = Meow
self.roar = Roar
def meow_bigger(self):
return self.roar
def mix(self):
return self.meow+self.roar
c=Cat("Meow!","Roar!")
print(c.meow_bigger())
print(c.mix())
Output
Roar!
Roar!
Meow!Roar!

Is there a way to modify a class in a class method in Python?

I wanted to do something like setattr to a class in class method in Python, but the class doesn't exist so I basically get:
NameError: global name 'ClassName' is not defined
Is there a way for a class method to modify the class? Something like this but that actually works:
class ClassName(object):
def HocusPocus(name):
setattr(ClassName, name, name)
HocusPocus("blah")
HocusPocus("bleh")
Class methods get the class passed as the first argument:
class Bla(object):
#classmethod
def cm(cls,value):
cls.storedValue = value
Bla.cm("Hello")
print Bla.storedValue # prints "Hello"
Edit: I think I understand your problem now. If I get it correctly, all you want to do is this:
class Bla(object):
storedValue = "Hello again"
print Bla.storedValue # prints "Hello again"
Class creation in Python (pretty much) simply means:
Create a fresh namespace.
Run the code that you find inside the class body using this namespace
Put everything that's left in the namespace into the class as class attributes.
Since storedValue is in the namespace after step 2, it's turned into a class attribute in step 3.
Another way you could do this would be to use a class decorator, though these are only available from Python 2.6 onwards IIRC.
Something like this:
def addattributes(cls):
cls.foobar = 10
return cls
#addattributes
class MyClass(object):
pass
print MyClass.foobar
This kind of this most useful when you want to "decorate" a number of classes with some specific functionality / properties. In your case, if you only want to do this once, you might just want to use class methods as previously shown.
While many good suggestions have been advanced, the closest one can get to the originally requested code, that is:
class ClassName(object):
def HocusPocus(name):
setattr(ClassName, name, property(fget=..., fset=...))
HocusPocus("blah")
HocusPocus("bleh")
is this:
class ClassName(object):
def HocusPocus(name):
return property(fget=..., fset=...)
blah = HocusPocus("blah")
bleh = HocusPocus("bleh")
I'm assuming the mysterious ... redacted parts need access to name too (otherwise it's not necessary to pass it as an argument).
The point is that, within the class body, HocusPocus is still just a function (since the class object doesn't exist yet until the class body finishes executing, the body is essentially like a function body that's running in its local dict [without the namespace optimizations typically performed by the Python compiler on locals of a real function, but that only makes the semantics simpler!]) and in particular it can be called within that body, can return a value, that value can be assigned (to a local variable of the class body, which will become a class attribute at the end of the body's execution), etc.
If you don't want ClassName.HocusPocus hanging around later, when you're done executing it within the class body just add a del statement (e.g. as the last statement in the class body):
del HocusPocus

Categories