class DemoClass:
def __init__(self):
self.name = "Marko"
def some_method(self):
print(self.name)
print(self.name) # NameError: name 'self' is not defined ???
my_object = DemoClass()
Why does this happen? Didn't I initialize the self.name variable in the init method which I think it means that it should be accessable in the entire class?
class DemoClass:
def __init__(self):
self.name = "Marko"
def some_method(self):
print(self.name)
my_object = DemoClass()
my_object.some_method()
do like this bro then only you can print the name.
You call the print() function with a class attribute (name) as argument. Even though the attribute is defined when Python executes the print() line, the class attributes exist in the local scope of the class and are accessible only to the class members or through the class namespace (e.g. my_object.name in a different scope where my_object is defined).
Related
I have a question regarding accessing class variable from the class.
Which way is preferred? Why Version 1 works? name isn't instance variable, how it can be accessed using .self?
Version 1:
class Base:
def get_name(self): return self.name
class Child_1(Base):
name = 'Child 1 name'
child = Child_1()
print(child.get_name())
Version 2:
class Base:
#classmethod
def get_name(cls): return cls.name
class Child_1(Base):
name = 'Child 1 name'
child = Child_1()
print(child.get_name())
Motivation behind this, is defining name once for all instances to save space.
self.name by default refers to cls.name
if you set it it only sets it for that instance however
self.name = "bob"
now overrides the class level name
just the same for methods as well
class Foo:
#staticmethod
def hello():
print("Hi There From Foo!")
def __init__(self):
self.hello() #this works
Foo.hello() # this also works
Foo() # print from in the init
Is there a way for a class to run a portion of its code only if the class called as a base class or when it's called through subprocess()? The code would be ignored if it's called through a subclass extension or if it's called through super().
Using __name__ == '__main__' will not work because when it's called using subprocess() it will have the module's name as its __name__.
So for example:
module A
class A():
def __init__(self):
self.name = 'Alice'
This portion will only run if class A() is run as the base class or through subprocess().
It will NOT run if it's called using super() or if it's called as an inherited class.
self.city = 'Pittsburgh'
module B
import A
class B(A):
def __init__(self):
super(B, self).__init__()
#Inherits self.name = 'Alice' but does NOT inherit self.city = 'Pittsburgh'
So in the above scenario, when class A() is created by directly calling it in module A or by subprocess(), it will have self.city as 'Pittsburgh'. However, if class A() is called through super() in module B or as an inherited class, it will only have self.name as Alice and will not have self.city attribute attached.
You could check the current class when setting the property using self.__class__.__name__:
class A():
def __init__(self):
self.name = 'Alice'
if self.__class__.__name__ == 'A':
self.city = 'Pittsburgh'
class B(A):
def __init__(self):
super(B, self).__init__()
x = A()
y = B()
print(hasattr(x, 'name'), hasattr(x, 'city'))
print(hasattr(y, 'name'), hasattr(y, 'city'))
I have a method in a dictionary as a class attribute;
class parentClass(object):
pass
class childClass(parentClass):
a = {'meth': my_meth}
def my_meth(self, var):
print(var)
inp = input()
# User enters 'meth'
childClass.a[inp]('test')
When I run the program I get the error;
NameError: name 'my_meth' is not defined
I have read functions are first class citizens in python. How can I assign a method as a value in a dictionary so I can call it later with certain parameters?
class parentClass(object):
pass
class childClass(parentClass):
def __init__(self):
self.a = {'meth': self.my_meth}
def my_meth(self, var):
print(var)
c = childClass()
c.a['meth']('test')
You must define Instance Variables are in __init__.
The issue with your code is that you set the a as a static variable in the class, but the method in the class is not static and requires self parameter.
To solve this, you can make the a variable connected with the instances, by setting it in the __init__ method:
class parentClass(object):
pass
class childClass(parentClass):
def __init__(self):
self.a = {'meth': self.my_meth}
def my_meth(self , var):
print(var)
childClass().a['meth']('Helloworld')
Or the my_meth can be made static thus able to call it from the class itself, like:
class parentClass(object):
pass
class childClass(parentClass):
def my_meth(var):
print(var)
a = {'meth': my_meth}
x = childClass.a['meth']("Helloworld")
How to save code duplication in the following scenario ?
say Aand B are two classes having a common function(say) name
class A(object):
name = 'foo'
#property
def name(self): # the common function
return self.name
similarly B
class B(object):
name = 'bar'
#property
def name(self):
return self.name
One way would be to make a class from which both of them inherit from, and define name there.
Any good alternatives ?
If you're really determined to avoid inheritance, just define a function outside of either class:
def get_name(object):
return object.name
class A(object):
name = 'foo'
def get_name(self): # the common function
return self.name
class B(A):
pass
In this case B would inherit from A
Is there a reason you can't have B inherit from A?
class B(A):
name = 'bar'
Since you are decorating name with #property, I am assuming you want this to be an instance variable. If you want this to return a more private variable, let's call it _name, you have to do:
class A(object):
def __init__(self):
self._name = 'foo'
#property
def name(self):
return self._name
You can't have both a variable and a function have the same name, since the latter will simply override the former. If you want a base class that takes care of this, it would look like this:
class HasName(object):
def __init__(self, name):
self._name = name
#property
def name(self):
return self._name
class A(HasName):
def __init__(self):
self._name = 'foo'
class B(HasName):
def __init__(self):
self._name = 'bar'
You can also call the constructor in HasName.
Assuming self.name stands in for a more complex method, the easiest way to cut down on duplicated code is to move the function out to the module and have it take an arbitrary object as a parameter. Then, if you still want to tie the method directly to the class, you can add a short method that dispatches to the module function.
def _name(obj):
return obj.name
class A(object):
# ...
#property
def name(self):
return _name(self)
class B(object):
# ...
#property
def name(self):
return _name(self)
Note that this will not work well if A.name and B.name have completely different behaviors. If the _name function starts checking the type of the object given, reconsider whether you really want to abstract that functionality in the first place.
I got an unexpected closure when creating a nested class. I suspect that this is something related to metaclasses, super, or both. It is definitely related to how closures get created. I am using python2.7.
Here are five simplified examples that demonstrate the same problem that I am seeing (they all build off the first):
EXAMPLE 1:
class Metaclass(type):
def __init__(self, name, bases, dict):
self.CONST = 5
class Base(object):
__metaclass__=Metaclass
def __init__(self):
"Set things up."
class Subclass(Base):
def __init__(self, name):
super(Subclass, self).__init__(self)
self.name = name
def other(self, something): pass
class Test(object):
def setup(self):
class Subclass(Base):
def __init__(self, name):
super(Subclass, self).__init__(self)
self.name = name
def other(self, something): pass
self.subclass = Subclass
class Subclass2(Base):
def __init__(self, name):
super(Subclass, self).__init__(self)
self.subclass2 = Subclass2
"0x%x" % id(Metaclass)
# '0x8257f74'
"0x%x" % id(Base)
# '0x825814c'
t=Test()
t.setup()
"0x%x" % id(t.subclass)
# '0x8258e8c'
"0x%x" % id(t.subclass2)
# '0x825907c'
t.subclass.__init__.__func__.__closure__
# (<cell at 0xb7d33d4c: Metaclass object at 0x8258e8c>,)
t.subclass.other.__func__.__closure__
# None
t.subclass2.__init__.__func__.__closure__
# (<cell at 0xb7d33d4c: Metaclass object at 0x8258e8c>,)
Subclass.__init__.__func__.__closure__
# None
EXAMPLE 2:
class Test2(object):
def setup(self):
class Subclass(Base):
def __init__(self, name):
self.name = name
def other(self, something): pass
self.subclass = Subclass
t2=Test2()
t2.setup()
t2.subclass.__init__.__func__.__closure__
# None
EXAMPLE 3:
class Test3(object):
def setup(self):
class Other(object):
def __init__(self):
super(Other, self).__init__()
self.other = Other
class Other2(object):
def __init__(self): pass
self.other2 = Other2
t3=Test3()
t3.setup()
"0x%x" % id(t3.other)
# '0x8259734'
t3.other.__init__.__func__.__closure__
# (<cell at 0xb7d33e54: type object at 0x8259734>,)
t3.other2.__init__.__func__.__closure__
# None
EXAMPLE 4:
class Metaclass2(type): pass
class Base2(object):
__metaclass__=Metaclass2
def __init__(self):
"Set things up."
class Base3(object):
__metaclass__=Metaclass2
class Test4(object):
def setup(self):
class Subclass2(Base2):
def __init__(self, name):
super(Subclass2, self).__init__(self)
self.subclass2 = Subclass2
class Subclass3(Base3):
def __init__(self, name):
super(Subclass3, self).__init__(self)
self.subclass3 = Subclass3
class Subclass4(Base3):
def __init__(self, name):
super(Subclass4, self).__init__(self)
self.subclass4 = Subclass4
"0x%x" % id(Metaclass2)
# '0x8259d9c'
"0x%x" % id(Base2)
# '0x825ac9c'
"0x%x" % id(Base3)
# '0x825affc'
t4=Test4()
t4.setup()
"0x%x" % id(t4.subclass2)
# '0x825b964'
"0x%x" % id(t4.subclass3)
# '0x825bcac'
"0x%x" % id(t4.subclass4)
# '0x825bff4'
t4.subclass2.__init__.__func__.__closure__
# (<cell at 0xb7d33d04: Metaclass2 object at 0x825b964>,)
t4.subclass3.__init__.__func__.__closure__
# (<cell at 0xb7d33e9c: Metaclass2 object at 0x825bcac>,)
t4.subclass4.__init__.__func__.__closure__
# (<cell at 0xb7d33ddc: Metaclass2 object at 0x825bff4>,)
EXAMPLE 5:
class Test5(object):
def setup(self):
class Subclass(Base):
def __init__(self, name):
Base.__init__(self)
self.subclass = Subclass
t5=Test5()
t5.setup()
"0x%x" % id(t5.subclass)
# '0x8260374'
t5.subclass.__init__.__func__.__closure__
# None
Here is what I understand (referencing examples):
Metaclasses are inherited, so Subclass gets Base’s metaclass.
Only __init__ is affected, Subclass.other method is not (#1).
Removing Subclass.other does not make a difference (#1).
Removing self.name=name from Subclass.__init__ does not make a difference (#1).
The object in the closure cell is not a function.
The object is not Metaclass or Base, but some object of type Metaclass, just like Base is (#1).
The object is actually an object of the type of the nested Subclass (#1).
The closure cells for t1.subclass.__init__ and t1.subclass2.__init__ are the same, even though they are from two different classes (#1).
When I do not nest the creation of Subclass (#1) then there is no closure created.
When I do not call super(...).__init__ in Subclass.init__ no closure is created (#2).
If I assign no __metaclass__ and inherit from object then the same behavior shows up (#3).
The object in the closure cell for t3.other.__init__ is t3.other (#3).
The same behavior happens if the metaclass has no __init__ (#4).
The same behavior happens if the Base has no __init__ (#4).
The closure cells for the three subclasses in example 4 are all different and each matches the corresponding class (#4).
When super(...).__init__ is replaced with Base.__init__(self), the closure disappears (#5).
Here is what I do not understand:
Why does a closure get set for __init__?
Why doesn't the closure get set for other?
Why is the object in the closure cell set to the class to which __init__ belongs?
Why does this only happen when super(...).__init__ is called?
Why doesn't this happen when Base.__init__(self) is called?
Does this actually have anything at all to do with using metaclasses (probably, since the default metaclass is type)?
Thanks for the help!
-eric
(Update) Here is something that I found then (based on Jason's insight):
def something1():
print "0x%x" % id(something1)
def something2():
def something3():
print "0x%x" % id(something1)
print "0x%x" % id(something2)
print "0x%x" % id(something3)
return something3
return something2
something1.__closure__
# None
something1().__closure__
# 0xb7d4056c
# (<cell at 0xb7d33eb4: function object at 0xb7d40df4>,)
something1()().__closure__
# 0xb7d4056c
# (<cell at 0xb7d33fec: function object at 0xb7d40e64>, <cell at 0xb7d33efc: function object at 0xb7d40e2c>)
something1()()()
# 0xb7d4056c
# 0xb7d4056c
# 0xb7d40e9c
# 0xb7d40ed4
First, a function's name is in scope within its own body. Second, functions get closures for the functions in which they are defined if they reference those functions.
I hadn't realized that the function name was in scope like that. The same goes for classes. When a class is defined within a function's scope, any references to that class name inside the class's methods cause the class to bound in a closure on that method's function, like so:
def test():
class Test(object):
def something(self):
print Test
return Test
test()
# <class '__main__.Test'>
test().something.__func__.__closure__
# (<cell at 0xb7d33c2c: type object at 0x825e304>,)
However, since closures cannot be created on non-functions the following fails:
def test():
class Test(object):
SELF=Test
def something(self):
print Test
return Test
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# File "<stdin>", line 2, in test
# File "<stdin>", line 3, in Test
# NameError: free variable 'Test' referenced before assignment in enclosing scope
Good stuff!
Why does a closure get set for __init__?
It refers to a local variable (namely Subclass) in the enclosing function (namely setup).
Why doesn't the closure get set for other?
Because it doesn't refer to any local variables (or parameters) in any enclosing functions.
Why is the object in the closure cell set to the class to which __init__ belongs?
That is the value of the enclosing variable being referred to.
Why does this only happen when super(...).__init__ is called?
Why doesn't this happen when Base.__init__(self) is called?
Because Base is not a local variable in any enclosing function.
Does this actually have anything at all to do with using metaclasses?
No.