0

Being from OOPS background, It looks strange to see below code from link

def f():
    f.beencalled = True
    return 0

My question:

1) From the above code, Is f a reference variable pointing to an object f of class 'function'?

2) We add a new attribute beencalled to an object f, so now 'function' class does not have this attribute beencalled defined and we say that object f is an object of class 'function'? Does it make sense?

3 Answers 3

5

1) Yes:

>>> def f():
        print(type(f))

>>> f()
>>> <class 'function'>

2) The function class does not have a new attribute, but the object f does. Adding or removing attributes to/from an object does not affect which attributes other objects of that class will have:

>>> class A: pass
>>> a = A()
>>> a.var = 7
>>> b = A()
>>> b.var
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
    b.newvar
AttributeError: 'A' object has no attribute 'var'

Classes are much more flexible in python than in Java or C++. Objects can have attributes not defined in their class, or even lack attributes that were defined in their class! Look at this:

>>> class A:
def __init__(self, a):
    self.var = a


>>> obj = A(7)
>>> del obj.var #deletes the var attribute from obj, does not change the A class
>>> obj.var
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    obj.var
AttributeError: 'A' object has no attribute 'var'

>>> obj2 = A(6)
>>> obj2.var #obj2 is a new object, so the fact we deleted var from obj doesn't affect it
6 

EDIT: after a bit of searching I found an explanation for why this behavior was chosen (source):

To implement user-defined objects, I settled on the simplest possible design; a scheme where objects were represented by a new kind of built-in object that stored a class reference pointing to a "class object" shared by all instances of the same class, and a dictionary, dubbed the "instance dictionary", that contained the instance variables.

In this implementation, the instance dictionary would contain the instance variables of each individual object whereas the class object would contain stuff shared between all instances of the same class--in particular, methods. In implementing class objects, I again chose the simplest possible design; the set of methods of a class were stored in a dictionary whose keys are the method names. This, I dubbed the class dictionary. To support inheritance, class objects would additionally store a reference to the class objects corresponding to the base classes. At the time, I was fairly naïve about classes, but I knew about multiple inheritance, which had recently been added to C++. I decided that as long as I was going to support inheritance, I might as well support a simple-minded version of multiple inheritance. Thus, every class object could have one or more base classes.

In this implementation, the underlying mechanics of working with objects are actually very simple. Whenever changes are made to instance or class variables, those changes are simply reflected in the underlying dictionary object. For example, setting an instance variable on an instance updates its local instance dictionary. Likewise, when looking up the value of a instance variable of an object, one merely checks its instance dictionary for the existence of that variable. If the variable is not found there, things become a little more interesting. In that case, lookups are performed in the class dictionary and then in the class dictionaries of each of the base classes.

Sign up to request clarification or add additional context in comments.

18 Comments

valek so object can have proeprties that it's class does not contain in general? and for that matter, extra behaviour as well? which class does not have?
@Sham Yes. They can also lack attributes that their class has in general!
VALEK But we are tied with class and class instances kind of concept in java/c++, in what sense are these paradigms true? java does not allow doing this
@Sham Python classes conceptually follow OOP because there is a type hierarchy with method inheritance. It's true that the ability to change the set of attributes could break polymorphism (if a user of a superclass expects a certain attribute that was removed by a subclass), but keep in mind that enforcing attributes doesn't eliminate the problem either (see en.wikipedia.org/wiki/…). As always it's the programmer's responsibility to decide when and how to use language features to design the most practical and understandable systems.
@Sham Well, it isn't accurate to say the object doesn't comply with "class attributes", because the instance attributes aren't part of the class definition, they're only assigned within methods (mainly __init__). And as you know, methods can be overridden. If you think about it, the situation is not so different in statically typed languages, because the internal fields are usually hidden in favor of getter and setter methods -- and there is nothing stopping you from deciding that a certain property is not valid in a subclass, and overriding the getter and setter to throw an exception.
|
2

On a slightly different note, you can change this behavior for custom classes.

class FooBar(object):
    __slots__ = ["foo","bar","baz"]
    # if you don't define __slots__, you can add attr to the object as needed
    # if you do, the object can only contain those attributes.
    def __init__(self,foo=None,bar=None,baz=None):
        self.foo = foo
        self.bar = bar
        self.baz = baz
    def __str__(self):
        return "I'm a FooBar with id {0} with foo: {1.foo}, bar: {1.bar}, baz: {1.baz}".format(id(self),self)

>>> a = FooBar("a","B","CCC")
>>> print(a)
I'm a FooBar with id 47260256 with foo: a, bar: B, baz: CCC
>>> a.spam = "eggs"
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    a.spam = "eggs"
AttributeError: 'FooBar' object has no attribute 'spam'

Alternately, without defining __slots__:

class BooFar(object):
    def __str__(self):
        return "I'm a BooFar with the following attributes:\n{}".format(self.__dict__)

>>> b = BooFar()
>>> print(b)
I'm a BooFar with the following attributes:
{}
>>> b.spam = "eggs"
>>> print(b)
I'm a BooFar with the following attributes:
{'spam': 'eggs'}

2 Comments

@Sham I don't even remotely understand your question.... Mostly you use __slots__ to minimize a memory footprint. Implementing __slots__ makes your object MUCH smaller than the same object that implements a __dict__ instead (which is the default)
adam so we can add/delete attributes to objects of a class, but after adding/deleting attribute, will that object be still called as object of that class.
1

f() in just an instance of types.FunctionType, and instances can have their own attributes.

Adding an attribute to an instance won't affect its class unless you've overridden the __setattr__ method of that class and doing something evil there.

>>> import types
>>> def func(): pass
>>> isinstance(func, types.FunctionType)
True

3 Comments

>>> def f():pass >>> type(f) <class 'function'> >>> how do i understand this?
@Sham f is a function that takes no arguments, does nothing and returns None. The type of this function is <class 'function'>.
@Sham Understand what?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.