I have a Person class and a SubPerson sub-class:
class Person:
def setname(self, name):
self.name = name
def display(self):
print(self.name)
class SubPerson(Person):
def display(self):
print("Name: {0}".format(self.name))
if __name__ == "__main__":
p = SubPerson()
p.display()
But when I call the display method of p I have the following error:
File "./person.py", line 14, in display
print("Name: {0}".format(self.name))
AttributeError: SubPerson instance has no attribute 'name'
Why? How can I fix this?
class Person:
def __init__(self, name=""):
self.name=name
#def setname(self, name):
# self.name = name
#instead of display
def __str__(self):
return self.name
#def display(self):
# print(self.name)
if __name__=='__main__':
p=Person("YourName")
print p
You have to "initialize" your attribute of your Person object.. And i would implement the str method to print your objects its like in C++ std::operator<< ..
And your subclass looks like this:
class SubPerson(Person):
def __str__(self):
return "Name: {0}".format(self.name)
There are some other methods(len,get, and so on..), which you can overwrite for your own Class..
please set "name" first
p.setname("your_name")
or if you dont want to set name, then initialize name attribute in parent class
class Person:
name = "your_name"
Why?
You should read exception message: "AttributeError: SubPerson instance has no attribute 'name'", that clearly indicates that SubPerson's instance p that you have created in main using expression p = SubPerson() don't have attribute 'name' - that is why it throws AttributeError exception.
Lets try your code on active interpreter and see:
>>> class Person:
... def setname(self, name):
... self.name = name
... def display(self):
... print(self.name)
...
>>> class SubPerson(Person):
... def display(self):
... print("Name: {0}".format(self.name))
...
>>> p = SubPerson()
>>> p.name # Notice
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: SubPerson instance has no attribute 'name'
>>>
Notice line p.name - you are getting same exception! Indeed p has no attribute with name 'name' you can use introspection technique to list all attribute of p using __dict__ and inherited attributes using dir() function, see below
>>> p.__dict__
{} # p don't have it any it own attribute
>>> dir(p) # either don't inerited attribute 'name'
['__doc__', '__module__', 'display', 'setname']
>>>
Notice only the attributes that p inherits from Person class are 'display', 'setname' but not name.
How can I fix this?
You have few techniques to rectify your code as below:
Python is dynamic language you can explicitly add new name in object namespace as:
>>> p.name = "grijesh"
>>> p.__dict__ # Now `p` has 'name' attributes
{'name': 'grijesh'}
>>> p.display() # it is safe to call display
Name: grijesh
Use your setname function as #Tasawer Nawaz's answer suggestion.
Use __init__ function and implement object constructor as give in #T.C.'s answer.
Basically in all technique you are attaching 'name' attribute to SubPerson instance object before accessing it in display() function method.
call the setname befoure your print statement.
You should explicitly call
p.setname("name")
before accessing it
Related
How to change object printing preview into desirable name ?
class Person:
def __init___(self):
self.name = name
self.age = age
man1 = Person("Jhon",32)
print(man1)
>>> <__main__.Person object at 0x7f9780554b80>
I need to change the preview of object into specifice attribute .(e.g: obj.name , in this example i want the preview will be "Jhon_Person_obj" instead the adress of it)
This code describe the printing reasult i need.
print(Jhon_Person_obj)
print(Jhon_Person_obj.age)
>>> <__main__.Personobject at 0x7f9780554bb0>
>>> 32
Override the __repr__ method of your class:
# PEP8: Class names should normally use the CapWords convention.
class Pokemon():
def __init__(self, name):
self.name = name
def __repr__(self):
return f"Pokemon(name='{self.name}')"
Usage:
p = Pokemon('Pikachu')
print(p)
# Output
Pokemon(name='Pikachu')
For a project I'm working on, I want to be able to associate a name with an object. The way I would like to do it is to set the .name attribute of the object to the name I want. What I really need is a function that takes an instance of an object, and returns something that is identical in every way but with a .name attribute. The problem is that I don't know what type of data the object will be ahead of time, so I can't use subclassing for example
Every method I've tried has hit a problem. Trying to give it a .name attribute directly doesnt work, for example:
>>> cats = ['tabby', 'siamese']
>>> cats.name = 'cats'
Traceback (most recent call last):
File "<pyshell#197>", line 1, in <module>
cats.name = 'cats'
AttributeError: 'list' object has no attribute 'name'
Using setattr has the same problem.
I've tried creating a new class that on init copies all attributes from the instance and also has a .name attribute, but this doesn't work either. If I try:
class NamedThing:
def __init__(self, name, thing):
thing_dict = {#not all types have a .__dict__ method
name: getattr(thing, name) for name in dir(thing)
}
self.__dict__ = thing_dict
self.name = name
It copies over the dict without a problem, but for some reason unless I directly call the new methods, python fails to find them, so the object loses all of its functionality. For example:
>>> cats = ['tabby', 'siamese']
>>> named_thing_cats = NamedThing('cats', cats)
>>> named_thing_cats.__repr__()#directly calling .__repr__()
"['tabby', 'siamese']"
>>> repr(named_thing_cats)#for some reason python does not call the new repr method
'<__main__.NamedThing object at 0x0000022814C1A670>'
>>> hasattr(named_thing_cats, '__iter__')
True
>>> for cat in named_thing_cats:
print(cat)
Traceback (most recent call last):
File "<pyshell#215>", line 1, in <module>
for cat in named_thing_cats:
TypeError: 'NamedThing' object is not iterable
I've also tried setting the type and attributes by setting class directly:
class NamedThing:
def __init__(self, name, thing):
thing_dict = {#not all types have a .__dict__ method
name: getattr(thing, name) for name in dir(thing)
}
self.__class__ = type('NamedThing', (type(thing),), thing_dict)
self.name = name
But this runs into a problem depending on what type thing is:
>>> cats = ['tabby', 'siamese']
>>> named_thing_cats = NamedThing('cats', cats)
Traceback (most recent call last):
File "<pyshell#217>", line 1, in <module>
named_thing_cats = NamedThing('cats', cats)
File "C:/Users/61490/Documents/Python/HeirachicalDict/moduleanalyser.py", line 12, in __init__
self.__class__ = type('NamedThing', (type(thing),), thing_dict)
TypeError: __class__ assignment: 'NamedThing' object layout differs from 'NamedThing'
I'm really stuck, help would be great
What you want is called an object proxy. This is some pretty sophisticated stuff, as you're getting into the data model of python and manipulating some pretty fundamental dunder (double underscore) methods in interesting ways
class Proxy:
def __init__(self, proxied):
object.__setattr__(self, '_proxied', proxied)
def __getattribute__(self, name):
try:
return object.__getattribute__(self, name)
except AttributeError:
p = object.__getattribute__(self, '_proxied')
return getattr(p, name)
def __setattr__(self, name, value):
p = object.__getattribute__(self, '_proxied')
if hasattr(p, name):
setattr(p, name, value)
else:
setattr(self, name, value)
def __getitem__(self, key):
p = object.__getattribute__(self, '_proxied')
return p[key]
def __setitem__(self, key, value):
p = object.__getattribute__(self, '_proxied')
p[key] = value
def __delitem__(self, key):
p = object.__getattribute__(self, '_proxied')
del p[key]
The most obvious thing that's going on here is that internally this class has to use the object implementation of the dunders to avoid recursing infinitely. What this does is holds a reference to a proxied object, then if you try to get or set an attribute it will check the proxied object, if the proxied object has that attribute it uses it, otherwise it sets the attribute on itself. For indexing, like with a list, it just directly acts on the proxied object, since the Proxy itself doesn't allow indexing.
If you need to use this in production, there's a package called wrapt you should probably look at instead.
Why not just create a __iter__ magic method with yield from:
class NamedThing():
def __init__(self, name, thing):
self.thing = thing
self.name = name
def __iter__(self):
yield from self.thing
cats = ['tabby', 'siamese']
named_thing_cats = NamedThing('cats', cats)
for cat in named_thing_cats:
print(cat)
Output;
tabby
siamese
Does this work?
class Thingy(list):
def __init__(self, name, thing):
list.__init__(self, thing)
self.name = name
cats = Thingy('cats', ['tabby', 'siamese'])
print(cats.name) # shows 'cats'
for cat in cats:
print(cat) # shows tabby, siamese
Or you could do:
class Thingy:
def __init__(self, name, thing):
self.thing = thing
self.name = name
I was looking into the advantages of #classmethods and figured that we can directly call the constructor from any method, in that case, why do we need a class method. Are there some advantages which i have missed.
Why this code, what are the advantages?
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
#classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
and not this code :-
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
Because if you derive from Person, fromBirthYear will always return a Person object and not the derived class.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, year)
class Fred(Person):
pass
print(Fred.fromBirthYear('bob', 2019))
Output:
<__main__.Person object at 0x6ffffcd7c88>
You would want Fred.fromBirthYear to return a Fred object.
In the end the language will let you do a lot of things that you shouldn't do.
Given
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
your code works find, as long as you don't access fromBirthYear via an instance of Person:
>>> Person("bob", 2010)
Person('bob', 10)
However, invoking it from an instance of Person will not:
>>> Person("bob", 2010).fromBirthYear("bob again", 10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fromBirthYear() takes 2 positional arguments but 3 were given
This is due to how the function type implements the descriptor protocol: access through an instance calls its __get__ method (which returns the method object that "prepasses" the instance to the underlying function), while access through the class returns the function itself.
To make things more consistent, you can define fromBirthYear as a static method, which always gives access to the underlying function whether accessed from the class or an instance:
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
#staticmethod
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
>>> Person.fromBirthYear("bob", 2010)
Person('bob', 10)
>>> Person.fromBirthYear("bob", 2010).fromBirthYear("bob again", 2015)
Person('bob again', 5)
Finally, a class method behaves somewhat like a static method, being consistent in the arguments received whether invoked from the class or an instance of the class. But, like an instance method, it does receive one implicit argument: the class itself, rather than the instance of the class. The benefit here is that the instance returned by the class method can be determined at runtime. Say you have a subclass of Person
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
#classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
class DifferentPerson(Person):
pass
Both classes can be used to call fromBirthYear, but the return value now depends on the class which calls it.
>>> type(Person.fromBirthYear("bob", 2010))
<class '__main__.Person'>
>>> type(DifferentPerson.fromBirthYear("other bog", 2010))
<class '__main__.DifferentPerson'>
Using the #classmethod decorator has the following effects:
The method is neatly documented as being intended for use this way.
Calling the method from an instance works:
>>> p = Person('Jayna', 43)
>>> p.fromBirthYear('Scott', 2003)
<__main__.Person object at 0x7f1c44e6aa60>
Whereas the other version will break:
>>> p = Person('Jayna', 43)
>>> p.fromBirthYear('Scott', 2003)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fromBirthYear() takes 2 positional arguments but 3 were given
>>> p.fromBirthYear(2003) # Jayna herself became the `name` argument
<__main__.Person object at 0x7f1c44e6a3a0>
>>> p.fromBirthYear(2003).name # this should be a string!
<__main__.Person object at 0x7f1c44e6a610>
The class itself is passed as a parameter (this is the difference between #classmethod and #staticmethod). This allows for various polymorphism tricks:
>>> class Base:
... _count = 0
... #classmethod
... def factory(cls):
... cls._count += 1
... print(f'{cls._count} {cls.__name__} instance(s) created via factory so far')
... return cls()
...
>>> class Derived(Base):
... _count = 0 # if we shadow the count here, it will be found by the `+=`
... #classmethod
... def factory(cls):
... print('making a derived instance')
... # super() not available in a `#staticmethod`
... return super().factory()
...
>>> Base.factory()
1 Base instance(s) created via factory so far
<__main__.Base object at 0x7f1c44e6a4f0>
>>>
>>> Derived.factory()
making a derived instance
1 Derived instance(s) created via factory so far
<__main__.Derived object at 0x7f1c44e63e20>
>>>
>>> Base().factory()
2 Base instance(s) created via factory so far
<__main__.Base object at 0x7f1c44e6a520>
>>>
>>> Derived().factory()
making a derived instance
2 Derived instance(s) created via factory so far
<__main__.Derived object at 0x7f1c44e63e20>
Note that Derived.factory and Derived().factory would create Derived rather than Base instances even if it weren't overridden:
>>> class Derived(Base):
... _count = 0
... pass
...
>>> Derived.factory()
1 Derived instance(s) created via factory so far
<__main__.Derived object at 0x7f1c44e63e20>
This is only possible using #classmethod, since otherwise there is no variable cls to call and we are stuck with a hard-coded Base. We would have to override the method to return Derived explicitly, even if we didn't want to change any other logic.
I'm work with python and I need a function in class like
class asas(object):
def b(self):
self.name = "Berkhan"
a = asas()
a.b().name
and I check this module
Traceback (most recent call last):
File "C:\Users\Berkhan Berkdemir\Desktop\new 1.py", line 5, in <module>
a.b().name
AttributeError: 'NoneType' object has no attribute 'name'
What should I do?
NoneType means that instead of an instance of whatever Class or Object you think you're working with, you've actually got None. That usually means that an assignment or function call up above failed or returned an unexpected result. See reference.
So, you can do something like this.
class asas(object):
def b(self):
self.name = "Berkhan"
return self.name
a = asas()
print(a.b()) # prints 'Berkhan'
or
class asas(object):
def b(self):
self.name = "Berkhan"
return self
a = asas()
print(a.b().name) # prints 'Berkhan'
b() returns nothing. Therefore it returns None.
You probably want something like this:
class asas(object):
def b(self):
self.name = "Berkhan"
return self
a = asas()
a.b().name
So I don't come from a computer science background and I am having trouble googling/SO searching on the right terms to answer this question. If I have a Python class with a class variable objects like so:
class MyClass(object):
objects = None
pass
MyClass.objects = 'test'
print MyClass.objects # outputs 'test'
a = MyClass()
print a.objects # also outputs 'test'
both the class and instances of the class will have access to the objects variable. I understand that I can change the instance value like so:
a.objects = 'bar'
print a.objects # outputs 'bar'
print MyClass.objects # outputs 'test'
but is it possible to have a class variable in Python that is accessible to users of the class (i.e. not just from within the class) but not accessible to the instances of that class? I think this is called a private member or static member in other languages?
Python is designed to allow instances of a class to access that class's attributes through the instance.
This only goes one level deep, so you can use a metaclass:
class T(type):
x = 5
class A(object):
__metaclass__ = T
Note that the metaclass syntax is different in Python 3. This works:
>>> A.x
5
>>> A().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'x'
It doesn't prevent you setting the attribute on instances of the class, though; to prevent that you'd have to play with __setattr__ magic method:
class A(object):
x = 1
def __getattribute__(self, name):
if name == 'x':
raise AttributeError
return super(A, self).__getattribute__(name)
def __setattr__(self, name, value):
if name == 'x':
raise AttributeError
return super(A, self).__setattr__(name, value)
def __delattr__(self, name):
if name == 'x':
raise AttributeError
return super(A, self).__delattr__(name)
The simplest way of achieving it is to use a descriptor. Descriptors are the thing meant for giving a higher level of control over attribute access. For example:
class ClassOnly(object):
def __init__(self, name, value):
self.name = name
self.value = value
def __get__(self, inst, cls):
if inst is not None:
msg = 'Cannot access class attribute {} from an instance'.format(self.name)
raise AttributeError(msg)
return self.value
class A(object):
objects = ClassOnly('objects', [])
Used as:
In [11]: a = A()
In [12]: a.objects
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-12-24afc67fd0ba> in <module>()
----> 1 a.objects
<ipython-input-9-db6510cd313b> in __get__(self, inst, cls)
5 def __get__(self, inst, cls):
6 if inst is not None:
----> 7 raise AttributeError('Cannot access class attribute {} from an instance'.format(self.name))
8 return self.value
AttributeError: Cannot access class attribute objects from an instance
In [13]: A.objects
Out[13]: []
If you want there to be a "single source of truth" for objects, you could make it a mutable type:
class MyClass(object):
objects = []
With immutable types, the fact that each instance starts out with the same reference from MyClass is irrelevant, as the first time that attribute is changed for the instance, it becomes "disconnected" from the class's value.
However, if the attribute is mutable, changing it in an instance changes it for the class and all other instances of the class:
>>> MyClass.objects.append(1)
>>> MyClass.objects
[1]
>>> a = MyClass()
>>> a.objects
[1]
>>> a.objects.append(2)
>>> a.objects
[1, 2]
>>> MyClass.objects
[1, 2]
In Python, nothing is really "private", so you can't really prevent the instances from accessing or altering objects (in that case, is it an appropriate class attribute?), but it is conventional to prepend names with an underscore if you don't ordinarily want them to be accessed directly: _objects.
One way to actually protect objects from instance access would be to override __getattribute__:
def __getattribute__(self, name):
if name == "objects":
raise AttributeError("Do not access 'objects' though MyClass instances.")
return super(MyClass, self).__getattribute__(name)
>>> MyClass.objects
[1]
>>> a.objects
...
AttributeError: Do not access 'objects' though MyClass instances.
No, you can't (EDIT: you can't in a way that is completely unaccessible, like in Java or C++).
You can do this, if you like:
class MyClass(object):
objects = None
pass
MyClass_objects = 'test'
print MyClass_objects # outputs 'test'
a = MyClass()
print a.objects # outputs 'None'
or this:
in your_module.py:
objects = 'test'
class MyClass(object):
objects = None
pass
in yourapp.py:
import your_module
print your_module.objects # outputs 'test'
a = your_module.MyClass()
print a.objects # outputs 'None'
the reason is:
When you create an instance of some class there is nothing to prevent
you from poking around inside and using various internal, private
methods that are (a) necessary for the class to function, BUT (b) not
intended for direct use/access.
Nothing is really private in python. No class or class instance can
keep you away from all what's inside (this makes introspection
possible and powerful). Python trusts you. It says "hey, if you want
to go poking around in dark places, I'm gonna trust that you've got a
good reason and you're not making trouble."
Karl Fast