Setting class variable - python

I have noticed the following in setting a class variable:
from ingest.models import WBReport
wb=WBReport()
wb.date = '2019-01-09'
The above does not set the date for the class. For example, calling this method, it prints None:
#classmethod
def load_asin(cls):
print cls.date
However, if I add another method to set that variable it does work. For example:
#classmethod
def set_date(cls, date):
cls.date=date
from ingest.models import WBReport
wb=WBReport()
wb.set_date('2019-01-09')
Why does the first method (wb.date=X)not work but the second one (wb.set_date(X)) does?

Instance variables and class variables exist separately. wb.date = '2019-01-09' sets an instance variable on the object wb, not the class variable WBReport.date, which is what the class method set_date sets.
The call to the class method is roughly equivalent to WBReport.date = '2019-01-09'.

Related

Python - Class object as function argument: Object only - Class not in argument

I am trying to write a function taking a string as an argument and using this argument as a class object.
Note that my explanantion might be strangely formulated sice I could not find an answer online. The MWE below should clarify what I mean, the problematic line is indicated.
Edit: in the MWE, "print" is an example. I need to be able to call the object to update it, print it or, in the case of a list, append to it. I need access to the object itself, not the value of the object.
MWE
# Create a class
class myClass():
def __init__(self):
self.one = "Test"
self.two = "Plop"
# Define function
def myFunction (parameter):
print(myObject.parameter)##### This line is currently not possible.
# Use class
myObject = myClass()
# Use function
myFunction("one")
I am not trying to append a new object to the class, only to call an existing object.
Is this even possible?
Looks like you need the built-in function called getattr
my_object = myClass()
def my_function(parameter):
print(getattr(my_object, parameter, None))
also this is not the best practice to call objects from outer scope like that. i'd suggest to use dict magic methods:
class MyClass:
def __init__(self):
self.one = "Test"
self.two = "Plop"
def __getitem__(self, parameter):
return getattr(self, parameter, None)
def __setitem__(self, parameter, value):
return setattr(self, parameter, value)
my_obj = MyClass()
parameter = "x"
print(my_obj[parameter])
my_obj[parameter] = "test"
print(my_obj.x)
You need to use getarttr():
# Create a class
class myClass():
def __init__(self):
self.one = "Test"
self.two = "Plop"
# Use class
myObject = myClass()
# Define function
def myFunction(parameter):
print(getattr(myObject, parameter))##### This line is currently possible.
# Use function
myFunction("one")

python get new value in a class or method

i'am new to python and try to get the new value for my bool in a class .
i try create a global, set in the init.
How can i get the new value of the test bool in getnewvalue() ?
Here is my code :
test = False
class myclass():
def changevalue()
test = True
getnewvalue()
def getnewvalue():
print(test)
If you want to have data inside your class, it's a good idea to use the __init__()
and save it like that. More here in the Python tutorial: Class Objects.
And use the __init__ to initialize the class with desired values.
Your code should look something like this:
test = False
class myclass():
def __init__(self, test):
self.test = test # self keyword is used to access/set attrs of the class
# __init__() gets called when the object is created, if you want to call
# any function on the creation of the object after setting the values
# you can do it here
self.changevalue()
def changevalue(self): # if you want to access the values of the class you
# need to pass self as a argument to the function
self.test = not test
self.getnewvalue()
def getnewvalue(self):
print(self.test) # use self to access objects test value
_class = myclass(False)
Or if you just want to have a class with functions, you can do something like this:
test = False
class myclass():
#staticmethod
def changevalue(val)
return not val
#staticmethod
def getnewvalue(test):
print(test)
_class = myclass()
test = _class.changevalue(test)
This way it won't print your value on call because it's just setting your value to return of that function. You'll have to do it yourself but that shouldn't be a problem.
More about staticmethods here: #staticmethod
Add
global test
to both functions. The resulting code would be...
test = False
class myclass():
def changevalue():
global test
test = True
getnewvalue()
def getnewvalue():
global test
print(test)
global allows the function to access variables outside of itself.
Hope this helps!

Simple Question : about python class parenthesis

Look at the code below.
class A :
def __init__(self, a = "Hello") :
self.a = a
print(A().a) # 1
print(A.a) # 2
1 is not error
2 is error - AttributeError: type object 'A' has no attribute 'a'
What is the difference between the two results?
In your code A refers the the type of a class and also to its constructor/initialiser. A is called the class and when you construct an object of type A with the constructor you get an instance of that class.
A # Refers to the class A
A() # is an instance of class A
There is a difference between a class property and an instance property. Consider the following code:
class A:
propertyA = "hello"
def __init__(self, string="world"):
self.propertyB = string
In this snippet propertyA is a class property while propertyB is an instance property. Each instance of type A has its own propertyB and you must instantiate and object (an instance) first.
A.propertyA # Class property, does not need an instance
A().propertyB # instance property, needs an instance
In your code the constructor for A is the code written in the __init__. This code will be called when you type A(). Note that you specified a default value for the parameter a but if you don't you would call the constructor like this:
A("hello") # or:
A(a="hello")
Note that classes, instances and constructors are fundamentals of OOP (and by extension Python), you really should learn this, it avoids lots of basic errors.
You need to create an instance of the class first:
class A :
def __init__(self, a = "Hello") :
self.a = a
class_instance = A()
print(class_instance.a)
You can set the value of "a" when creating the instance by typing in the parenthesis:
class_instance = A("this is the value of a")
you can change the value after the creation like so:
class_instance.a = "New value of a"
A().a is creating an instance and returns the a value of the instance.
A.a cannot be executed because A is the Class name and doesn't have any attributes if you don't create an instance first

How do I reference the object passed to my class when I instantiate?

I have this class
class SECHeader(object):
def __init__(self,header_path):
self.header = open(header_path).read()
I have some methods in this class, one of the methods I am trying to do needs to parse the name
def parsed_name(self):
return header_path.split('-')[-1]
This works fine if in my code I use the name header_path to identify the thing I am trying to operate on
for header_path in header_paths:
header = SECHeader(header_path)
print header.parsed_name()
But if I change the name
for named_path in header_paths:
header = SECHeader(named_path)
print header.parsed_name()
I get a NameError
I played around - if can use any name for the object in the parsed_name function as long as I use the same name for the object I want to process but I can't seem to figure out how to name it so a user does not have to use my naming scheme
specifically if I change the parsed_name function to
def parsed_name(self):
return banana.split('-')[-1]
and in my loop if change it to
for banana in header_paths:
header = SECHeader(banana)
print header.parsed_name()
it works like a charm but that limits the portability of this thing I am working on. as any user would have to reference the path with whatever label I use in the function.
The problem here is that you have header_path declared as a variable for the init function. It's scope is local to the init function.
What you need is to associate header_path as a variable for the class instance.
Class SECHeader(object):
def __init__(self,header_path):
self.header_path = header_path # Instantiate a variable for class object
self.header = open(header_path).read()
def parsed_name(self):
return self.header_path.split('-')[-1] # Call the associated variable
Another way is to actually call the variable that you gave as an argument to SECHeader in parsed_name. This variable name would be in the class namespace.
for banana in header_paths:
header = SECHeader(banana)
print header.parsed_name()
Class SECHeader(object):
def __init__(self,header_path): # header_path takes value of banana
# and ends scope in __init__
self.header = open(header_path).read()
def parsed_name(self):
return banana.split('-')[-1] # banana was passed to class and is known

Is it safe to replace a self object by another object of the same type in a method?

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>

Categories

Resources