How to initialise class as an object with same name
>>> class test:
def name(self,name_):
self.name = name_
>>> a= test()
>>> a
<__main__.test instance at 0x027036C0>
>>> test
<class __main__.test at 0x0271CDC0>
here a is an object so I can do a.name("Hello")
But what I want to achieve is test.name("Hello") without doing something like test = test()
The simple answer is don't bother with a "setter" function. Just access the attribute directly. eg.
a = test()
a.name = "setting an instance attribute"
test.name = "setting the class attribute"
b = test()
# b has no name yet, so it defaults the to class attribute
assert b.name == "setting the class attribute"
If the function is doing something a little more complicated than just setting an attribute then you can make it a classmethod. eg.
class Test(object):
# you are using python 2.x -- make sure your classes inherit from object
# Secondly, it's very good practice to use CamelCase for your class names.
# Note how the class name is highlighted in cyan in this code snippet.
#classmethod
def set_name(cls, name):
cls.name = name
Test.set_name("hello")
assert Test().name == "hello"
Related
class MyClass():
def __init__(self):
self.attribute_1 = "foo"
self.attribute_2 = "bar"
#property
def attribute_1(self):
return self._attribute_1
#attribute_1.setter
def attribute_1(self,s):
self._attribute_1 = s
#property
def attribute_2(self):
return self._attribute_2
#attribute_2.setter
def attribute_2(self,s):
self._attribute_2 = s
>>> ob = MyClass()
>>> ob.attribute_1 = 'fizz' #Ok
>>> ob.atribute_1 = 'buzz' #want to throw an exception because this has no setter or #property def
I would like my class to complain if we try and set an attribute that has not been decorated with property and a setter. I have tried using slots but can't get it working with the property decorator. 'attribute' in __slots__ conflicts with class variable
Any thoughts?
__slots__ should contain all instance variables, in your case it is _attribute_1 and _attribute_2 (the ones with underscores used internally) so just do that:
class MyClass():
__slots__ = ["_attribute_1", "_attribute_2"]
pass # rest of implementation
note that if your property is just directly forwarding you might as well just put the public variables in the slots and only have properties for fields that need more validation or other logic. having slots is effectively a property really:
>>> MyClass._attribute_1
<member '_attribute_1' of 'MyClass' objects>
Can a particular instance make its own variable in python, if yes would it be available to other instances of the class?
for eg:
class A():
Var1 = 10
inst1 = A()
inst1.Var1 # will be 10
but can inst1 make it's own variables like Var2 etc and will these Variables be available to other class A instances like inst2?
In other Words, is a variable, which is bound to an instance of a class, accessible to another instance of the same class?
Actually, the most common use case is for instances to have their "own" variables ("data attributes" in Python terminology) which are not shared between instances. The variables x and y below are examples of such "own" variables (every instance of class A gets its own variable x when the constructor is called, and inst1 also gets its own variable y later):
class A():
def __init__(self): # Constructor - called when A is instantiated
self.x = 10 # Creates x for self only (i.e. for each instance in turn)
inst1 = A()
inst1.x = 15 # Changes x for inst1 only
inst1.y = 20 # Creates y for inst1 only
print(inst1.x, inst1.y) # 15 20
inst2 = A()
print(inst2.x) # 10
To dynamically add attributes to a class or instance you can use setattr:
class MyClass(object):
pass
my_instance = MyClass()
# add attribute to class
setattr(MyClass, 'new_attribute', 'added')
# Class now has attribute
print(MyClass.new_attribute == 'added') # True
# Which is also available to instance
print(my_instance.new_attribute == 'added') # True
# Add attribute to instance
setattr(my_instance, 'instance_only', 'yup')
# Instance now has attribute
print(my_instance.instance_only == 'yup') # True
# Class does not have attribute
MyClass.instance_only # Raises AttributeError
# Add attribute to instances class
settatr(type(my_instance), 'instance_only', 'not anymore')
# Now the attribute is available to the class as well
print(MyClass.instance_only == 'not anymore') # True
# New instances will also have the attributes
new_instance = MyClass()
print(new_instance.new_attribute == 'added') # True
If you are not adding them dynamically see #gilch's answer
Even though the actual use may be questionable, you actually can bind new attributes to a class definition in a way that they are available to all instances of that class:
class A(object):
attrib_one = 'VALUE'
def add_class_attrib(self, name, value):
# Bind new attribute to class definition, **not** to self
setattr(A, name, value)
if __name__ == '__main__':
# Instantiate _before_ changing A's class attributes
a = A()
b = A()
# Add a new class attribute using only _one_ instance
a.add_class_attrib('attrib_two', 'OTHER')
# Print attributes of both instances
print([e for e in dir(a) if not e.startswith('__')])
print([e for e in dir(b) if not e.startswith('__')])
# Create new instance _after_ changing A's class attribs
c = A()
# Print attributes of new instance
print([e for e in dir(c) if not e.startswith('__')])
Running this code will print the following:
['add_class_attrib', 'attrib_one', 'attrib_two']
['add_class_attrib', 'attrib_one', 'attrib_two']
['add_class_attrib', 'attrib_one', 'attrib_two']
And you see, that -- even if a class attribute is added to the class definition after an instance of it has been created, the newly created class attribute in fact is available to all other instances of that (changed) class.
It depends on if you set the variable in the class's dict or the instance's dict.
>>> class A:
var = 10
>>> inst1 = A()
>>> inst2 = A()
>>> inst1.var # not in instance, so looked up in class
10
>>> inst2.var
10
>>> inst2.var = 20 # instance attr shadows that from class
>>> inst2.var
20
>>> A.var = 30 # class attr can also be altered
>>> inst1.var
30
>>> inst2.var
20
>>> del inst2.var # deleting instance attr reveals shadowed class attr
>>> inst2.var
30
>>> inst1.var2 = 'spam'
>>> inst2.var2 # new attr was set on inst1, so not available in inst2
Traceback (most recent call last):
File "<pyshell#663>", line 1, in <module>
inst2.var2
AttributeError: 'A' object has no attribute 'var2'
>>> inst1.__class__.var3 = 'eggs' # same as A.var3 = 'eggs'
>>> inst2.var3 # new attr was set on the class, so all instances see it.
'eggs'
I am trying to create a class that returns the class name together with the attribute. This needs to work both with instance attributes and class attributes
class TestClass:
obj1 = 'hi'
I.e. I want the following (note: both with and without class instantiation)
>>> TestClass.obj1
('TestClass', 'hi')
>>> TestClass().obj1
('TestClass', 'hi')
A similar effect is obtained when using the Enum package in python, but if I inherit from Enum, I cannot create an __init__ function, which I want to do as well
If I use Enum I would get:
from enum import Enum
class TestClass2(Enum):
obj1 = 'hi'
>>> TestClass2.obj1
<TestClass2.obj1: 'hi'>
I've already tried overriding the __getattribute__ magic method in a meta class as suggested here: How can I override class attribute access in python. However, this breaks the __dir__ magic method, which then wont return anything, and furthermore it seems to return name of the meta class, rather than the child class. Example below:
class BooType(type):
def __getattribute__(self, attr):
if attr == '__class__':
return super().__getattribute__(attr)
else:
return self.__class__.__name__, attr
class Boo(metaclass=BooType):
asd = 'hi'
>>> print(Boo.asd)
('BooType', 'asd')
>>> print(dir(Boo))
AttributeError: 'tuple' object has no attribute 'keys'
I have also tried overriding the __setattr__ magic method, but this seems to only affect instance attributes, and not class attributes.
I should state that I am looking for a general solution. Not something where I need to write a #property or #classmethod function or something similar for each attribute
I got help from a colleague for defining meta classes, and came up with the following solution
class MyMeta(type):
def __new__(mcs, name, bases, dct):
c = super(MyMeta, mcs).__new__(mcs, name, bases, dct)
c._member_names = []
for key, value in c.__dict__.items():
if type(value) is str and not key.startswith("__"):
c._member_names.append(key)
setattr(c, key, (c.__name__, value))
return c
def __dir__(cls):
return cls._member_names
class TestClass(metaclass=MyMeta):
a = 'hi'
b = 'hi again'
print(TestClass.a)
# ('TestClass', 'hi')
print(TestClass.b)
# ('TestClass', 'hi again')
print(dir(TestClass))
# ['a', 'b']
Way 1
You can use classmethod decorator to define methods callable at the whole class:
class TestClass:
_obj1 = 'hi'
#classmethod
def obj1(cls):
return cls.__name__, cls._obj1
class TestSubClass(TestClass):
pass
print(TestClass.obj1())
# ('TestClass', 'hi')
print(TestSubClass.obj1())
# ('TestSubClass', 'hi')
Way 2
Maybe you should use property decorator so the disered output will be accessible by instances of a certain class instead of the class itself:
class TestClass:
_obj1 = 'hi'
#property
def obj1(self):
return self.__class__.__name__, self._obj1
class TestSubClass(TestClass):
pass
a = TestClass()
b = TestSubClass()
print(a.obj1)
# ('TestClass', 'hi')
print(b.obj1)
# ('TestSubClass', 'hi')
my class structure is something like this.
class A():
def __init__(self):
self.matched_condition_set = set()
def add_to_matched_condition(self,condition):
self.matched_condition_set.add(condition)
class B():
def __init__(self, list_of_A):
self.list_of_a = list_of_A
def do_stuff(self):
for a in self.list_of_a:
if helper.check_for_a(a):
print(a.matched_condition_set)
in a file called helper.py i have the following function.
def check_for_a(a):
print(type(a))
a.add_to_matched_condition("hello")
return True
Now if i call class B object,
I get that:
A instance has no attribute 'add_to_matched_condition'
.
also when I try to get the type of a >> print(type(a)) inside the helper method. i get type<'instance'>.
where is the object getting lost ?
I don't know why you're getting A instance has no attribute 'add_to_matched_condition'; your code works ok for me on Python 2.6.4
To get a more useful type signature (plus other goodies) on your classes you need to make them inherit from object.
Here's my slightly modified version of your code that illustrates that; it also shows how I tested your classes.
#!/usr/bin/env python
import helper
class A(object):
def __init__(self):
self.matched_condition_set = set()
def add_to_matched_condition(self,condition):
self.matched_condition_set.add(condition)
class B(object):
def __init__(self, list_of_A):
self.list_of_a = list_of_A
def do_stuff(self):
for a in self.list_of_a:
if helper.check_for_a(a):
print(a.matched_condition_set)
a1 = A(); a2 = A()
b = B([a1, a2])
print a1, a2
print b, b.list_of_a
b.do_stuff()
print a1.matched_condition_set
print a2.matched_condition_set
output
<__main__.A object at 0xb758f80c> <__main__.A object at 0xb758f84c>
<__main__.B object at 0xb758f86c> [<__main__.A object at 0xb758f80c>, <__main__.A object at 0xb758f84c>]
<class '__main__.A'>
set(['hello'])
<class '__main__.A'>
set(['hello'])
set(['hello'])
set(['hello'])
The reason you are seeing type<instance> is most likely that you are using Python 2.x. Because you are defining your classes as
class A():
instead of
class A(object):
you are creating "old style" classes.
As to your other problem, we'd need to see the code in which you create a list of A()s and pass that list into the constructor for B(). Please add that code if you want an answer to that part of your question.
Also, it's unclear to me why check_for_a is not a method of A(), and I'm not sure I would name a function check_for_a if it actually has the side-effect of altering the object it's checking.
I'm new to Python, and I'm having a little trouble comprehending how Python interprets class and instance variables. My background is C#, so I have a fairly good understanding of OOP (from a C# mindset), however I'm just a little confused with python. I'm guessing this is because I'm thinking in the wrong mind set.
Take the following class as example:
class User():
"""The default user implementation"""
# define the variables
id = None
first_name = None
last_name = None
email = None
password = None
created = None
deleted = False
def __init__(self):
"""Creates a new instance of the User object."""
self.is_admin = False
From the documentation that I have read, all of the id, first_name, last_name etc. are class attribute which are shared between instances. These would be static within a C# mindset. Then the is_admin is an instance attribute, which is limited to a specific instance of the object. These would be fields or properties within C#.
However, my confusion comes when I do something like this:
new_user = User()
new_user.id = "blah"
new_user.last_name = "lasty"
new_user1 = User()
new_user1.id = "some_id"
new_user1.last_name = "firsty"
This sets the values as:
new_user.id = "blah"
new_user.last_name = "lasty"
new_user1.id = "some_id"
new_user1.last_name = "firsty"
Given that the id and last_name are defined as class attributes, I would have assumed that the calls to the new_user1 objects would have overwritten the "blah" and "lasty" values, however each instance has retained the values that were defined to it. Hence, my confusion.
If this is normal, could someone please shed some light on to why this is? Also, in that case, how does one define a static variable?
Cheers,
Justin
Python looks up attributes on the instance, then the instance's class, then any base classes and their parents. So id and last_name are instance attributes that hide the attributes of the same name on the class. If you access an attribute you did not set on the instance (such as first_name) then you get the class's attribute since it was not found on the instance.
Simplest idea that works and shows the difference between a class variable and an instance variable:
>>> import datetime
>>> class Example:
... my_name = 'example'
... def __init__(self):
... self.now = datetime.datetime.now()
...
>>> e = Example()
>>> e.my_name
'example'
>>> e.now
datetime.datetime(2015, 6, 1, 2, 2, 58, 211399)
>>> d = Example()
>>> d.my_name
'example'
>>> d.now
datetime.datetime(2015, 6, 1, 2, 4, 21, 165731)
>>>
my_name is a class variable -- it is a property of the class and any instance of the class has access to that property. now is an instance variable -- only object of type Example have access to datetime and datetime is different for each object.
To drive the point home, let's try to access each variable from the class itself:
>>> Example.now
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Example' has no attribute 'now'
>>> Example.my_name
'example'
>>>
An object CAN modify a class variable for that instance:
>>> d.my_name = "George"
>>> d.may_name
'George'
>>> Example.my_name
'example'
But not for the class.
Static is a keyword that references static linkage in C and C++ and is used in many modern OO languages to denote a piece of code that is shared by all objects of a class but is not a class method or variable per se. Python as a staticmethod decorator for methods. but there are no static variables, only class variables.
I hope that clarifies things.
Class variables are not really 'static' in the sense that C and Java uses the term. They are easily overwritten. They are better thought of as single copy default values associated with the class object.
Consider (in Python 3):
class Foo(object):
cv='cv'
def __setattr__(self, name, value):
if name in self.__class__.__dict__:
print('Overloading class var "{}" with instance attribute "{}"'.format(self.__class__.__dict__[name], value))
super(self.__class__, self).__setattr__(name, value)
def __getattribute__(*args):
self, name, *the_rest=args
if name in Foo.__dict__:
print('there is a class variable called "{}" with value of: "{}"'.format(name, Foo.__dict__[name]))
return object.__getattribute__(*args)
Now instantiate a copy of the class Foo and test the class variable and instance variables:
>>> foo=Foo()
>>> foo.cv
there is a class variable called "cv" with value of: "cv"
'cv'
>>> foo.cv='IV'
Overloading class var "cv" with instance attribute "IV"
>>> foo.cv
there is a class variable called "cv" with value of: "cv"
'IV'
>>> Foo.cv='NEW CV'
>>> bar=Foo()
>>> bar.cv
there is a class variable called "cv" with value of: "NEW CV"
'NEW CV'
Python does not have constants or static variables. For class attributes it is the same. The class is loaded with the value on import. If the user changes that value for import.
class MyClass(object):
id = 1
def main():
myclass = MyClass()
print("class1", myclass.id)
print()
myclass2 = MyClass()
myclass2.id = 2
print("class1", myclass.id)
print("class2", myclass2.id)
print()
MyClass.id = 3
myclass3 = MyClass()
print("class1", myclass.id)
print("class2", myclass2.id)
print("class3", myclass3.id)
print()
myclass4 = MyClass()
print("class1", myclass.id)
print("class2", myclass2.id)
print("class3", myclass3.id)
print("class4", myclass4.id)
print()
myclass5 = MyClass()
myclass5.id = 5
print("class1", myclass.id)
print("class2", myclass2.id)
print("class3", myclass3.id)
print("class4", myclass4.id)
print("class5", myclass5.id)
# end main
if __name__ == '__main__':
main()
The results are interesting.
class1 1
class1 1
class2 2
class1 3
class2 2
class3 3
class1 3
class2 2
class3 3
class4 3
class1 3
class2 2
class3 3
class4 3
class5 5
If you have not set the instance id it will default to the class id.
MyClass.id = 1
This will change the value of an instance if the instance did not set a value.