1) You meant print polly.getAge() instead of print polly.getAge.
2) However you then have a second issue (getAge() requires aging to be mandatory, which it totally shouldn't). You can kludge that with print polly.getAge(0), or fix it properly, see below.
Back to 1) The former actually calls the function/method (well it tries to call it, except for the issue of 2))
The latter is wrong, it only prints information about the actual function/method, but doesn't actually call it.
You can explore more by seeing that type(polly.getAge()) (or type(polly.getAge(0))) is an int, different to type(polly.getAge), which will be some type for function/method.
2) Your second issue here is getAge(...) is pretending to be a getter function but it also has a mandatory parameter aging and is implementing the aging, this is considered "method abuse" and violates separation of concerns, or at least don't name it getX which is really reserved for getters. Your alternatives are a) give it a default getAge(self, aging=0) (or use @property decorator), now it behaves like a getter when called getAge(). Or b) refactor out the two separate pieces of functionality into separate methods ("separation of concerns"):
class Pet(object):
...
def getAge(self, aging):
return self.age
def doAging(self, aging):
self.age += aging
# Note that doAging() has no return value, and that is correct behavior (it's a method, not a getter)
In general that is a better and more maintainable design, we frown on "magical getters/setters" with side-effects, for tons of reasons (one of which is they f### up unit-testing). As you start adding more methods, you'll see why very quickly...
getAgeprobably should not be modifying anything.