0

Given this class:

class Person:
  lastName = ""
  firstName = ""

  def getFullName(self, lastName, firstName):
    self.instanceLevel_lastName = lastName
    self.instanceLevel_firstName = firstName

Why does Python choose to treat firstName and lastName as class-level attrs, and getFullName() as an instance-level member/method, although they are defined at the "same level"? I'd thought by default, the same-level attrs would be treated in the "same way" which should ALL be instance-level members.

I realize this is not a programming question, but it's more about the language design. I come from C++ background, so I'm a bit puzzled about this behavior in Python.

Laurel
  • 5,965
  • 14
  • 31
  • 57
Ltf4an
  • 787
  • 5
  • 18

3 Answers3

0
class Person:
  def __init__(self):
      self.firstName = ""
      self.lastName = ""

  def getFullName(self):
    ...

Will give you instance-level attributes.

Adam Acosta
  • 603
  • 3
  • 6
  • Sorry, I did not mean to ask "how to" define instance-level variables. I've edited my question. – Ltf4an Nov 15 '15 at 17:59
  • Oh sorry. Yeah, I guess it is a little counterintuitive that variables defined in a class are shared between all instances without the self modifer, without having to be marked with any particular modifier themselves, but I believe it follows from the way Python namespaces work, which seems to be driven by modules more than classes. It's very obvious from that perspective why a variable defined at module level is global to the module without further encapsulation. It's definitely different than most other languages where a source file name doesn't have much significance. – Adam Acosta Nov 15 '15 at 18:49
0

To get static methods you need to use the @staticmethod decorator.

class MyClass:
    classAttr = 4

    @staticmethod
    def static_foo():
        print("Static Shock!")

This is done most likely because there is seldom a need for static methods in python, as they can often be replaced by top-level functions in the module.

See this question for more info: Static methods in Python?

Community
  • 1
  • 1
Kory
  • 11
  • 2
  • I think by the same token, "static" variables are not of typical use either, and therefore, why are they not treated as instance-level member instead? – Ltf4an Nov 15 '15 at 18:06
  • @Ltf4an I don't know. I do know that one can define instance variables in places other than the __init__ function, though it's generally frowned upon. All instance variables have the self.varName convention, whereas the class variables are defined under the class name. I think it just comes down to readability at that point, from my experience new programmers find the self.varName a bit more readable. – Kory Nov 15 '15 at 22:45
0

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'