Python does not, in fact, treat getFullName
as an instance-level member differently from lastName
and firstName
in your example. All of these are defined at the class-level an can be accessed as such.
If I change your example slightly:
class Person:
lastName = ""
firstName = ""
def getFullName(self):
return("{} {}".format(self.firstName, self.lastName))
Note that you can access all of these via the class:
>>> Person.firstName
''
>>> Person.getFullName
<function Person.getFullName at 0x104168c80>
And you can access all of these via an instance:
>>> p = Person()
>>> p.firstName
''
>>> p.getFullName
<bound method Person.getFullName of <__main__.Person object at 0x104173240>>
That is, they are all class attributes, and you can access any class attribute via an instance.
Now, you can see here that how you access the method getFullName
does affect what you get, in that Person.getFullName
is a function (that takes self
as it's first argument) and p.getFullName
is a bound method (in which self is already bound, so it doesn't take that argument):
>>> p = Person()
>>> Person.getFullName(p)
' '
>>> p.getFullName()
' '
Similarly, Person.firstName = "Bob"
will set the class attribute firstName
, whereas p.firstName = "Bob"
will set the instance attribute firstName
, and the instance variable will shadow the class variable next time you access p.firstName
:
>>> Person.firstName = "Bob"
>>> p.firtName
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'firtName'
>>> Person.firstName = "Bob"
>>> p.firstName
'Bob'
>>> p.firstName = "Joe"
>>> p.firstName
'Joe'
>>> Person.firstName
'Bob'