Like in java or C# where we can create an object like
Account obj = new SavingsAccount();
where Account is the parent class and SavingsAccount is the child class
How do I do the same thing with python?
basically I'm trying to do is this
https://repl.it/#MushfiqurRahma1/Polymorphic-Object
Python is dynamically typed: names refer to objects without any notion of type being involved. You just have
>>> class Account: pass
...
>>> class SavingsAccount(Account): pass
...
>>> obj = SavingsAccount()
Each object stores a reference to its own type
>>> type(obj)
<class '__main__.SavingsAccount'>
and each type has a referent to its method resolution order (MRO)
>>> type(obj).__mro__
(<class '__main__.SavingsAccount'>, <class '__main__.Account'>, <class 'object'>)
Instance attributes are not "compartmentalized" according to the class that "defines" them; each attribute simply exists on the instance itself, without reference to any particular class.
Methods exist solely in the classes themselves; when it comes time to call obj.foo(), the MRO is used to determine whose definition is used.
Python uses Duck typing, which means you shouldn’t really care about the class in the Left side of the assignment. Just instantiate the Child class and you should already be able to use it’s parent “interface” to do stuff like dynamic method calls.
Python is a loosely typed language. That means you don't have to specify your variable types. You could just do something like:
class Account():
def deposit():
pass
class SavingsAccount(Account):
pass
obj = SavingsAccount()
obj.deposit(20)
EDIT: As chepner pointed out: Python is strongly typed, but also dynamically typed: type is associated with an object, not the name referring to an object.
Related
I found there is object() which is a built-in function in Python. *You can find object() in Built-in Functions
And, the documentation says below:
Return a new featureless object. object is a base for all classes. It
has methods that are common to all instances of Python classes. This
function does not accept any arguments.
As the documentation says, object() can create an object but I don't know how to do it.
My questions:
How to create an object with object()?
When to use object()? or What are the use cases of object()?
To create an object with object, just call it: object(). However, it is never (as noted in the comments, it may be sometimes useful, when you need to have a something but you don't care what it is) used as is. object is just the (implicit in Python 3) base class of all classes. It provides basic features, such as allocation and magic methods, that you never directly manipulate in Python.
The naming follows one of Python's catchphrases "everything is an object".
You can create an object with only object() as shown below:
print(type(object()))
Then,the object of object class is created:
<class 'object'>
In addition, you can create and initialize the object of Person class with object() as shown below:
class Person:
def __init__(self, name):
self.name = name
obj = object().__new__(Person) # Creates the object of "Person" class
print(type(obj))
obj.__init__("John") # Initializes the object of "Person" class
print(obj.name)
Then, the object of Person class is created and initialized:
<class '__main__.Person'>
John
I define a python class in python interpreter
class A:
pass
I get base class of A using A.__bases__, it shows
(object,)
but when I enter dir(A), the output don't contain __bases__ attribute, then I try dir(object), __bases__ is not found either, where does the __bases__ come from?
The __bases__ attribute in a class is implemented by a descriptor in the metaclass, type. You have to be a little careful though, since type, as one of the building blocks of the Python object model, is an instance of itself, and so type.__bases__ doesn't do what you would want for introspection.
Try this:
descriptor = type.__dict__['__bases__']
print(descriptor, type(descriptor))
You can reproduce the same kind of thing with your own descriptors:
class MyMeta(type):
#property # a property is a descriptor
def foo(cls):
return "foo"
class MyClass(metaclass=MyMeta):
pass
Now if you access MyClass.foo you'll get the string foo. But you won't see foo in the variables defined in MyClass (if you check with vars or dir). Nor can you access it through an instance of MyClass (my_obj = MyClass(); my_obj.foo raises an AttributeError).
it is a special attribute akin to __name__ or __dict__. While the result of function dir actually depends on the implementation of __dir__ function.
You might want to look it on the doc here https://docs.python.org/3/reference/datamodel.html
What is the difference between class and instance variables in Python?
class Complex:
a = 1
and
class Complex:
def __init__(self):
self.a = 1
Using the call: x = Complex().a in both cases assigns x to 1.
A more in-depth answer about __init__() and self will be appreciated.
When you write a class block, you create class attributes (or class variables). All the names you assign in the class block, including methods you define with def become class attributes.
After a class instance is created, anything with a reference to the instance can create instance attributes on it. Inside methods, the "current" instance is almost always bound to the name self, which is why you are thinking of these as "self variables". Usually in object-oriented design, the code attached to a class is supposed to have control over the attributes of instances of that class, so almost all instance attribute assignment is done inside methods, using the reference to the instance received in the self parameter of the method.
Class attributes are often compared to static variables (or methods) as found in languages like Java, C#, or C++. However, if you want to aim for deeper understanding I would avoid thinking of class attributes as "the same" as static variables. While they are often used for the same purposes, the underlying concept is quite different. More on this in the "advanced" section below the line.
An example!
class SomeClass:
def __init__(self):
self.foo = 'I am an instance attribute called foo'
self.foo_list = []
bar = 'I am a class attribute called bar'
bar_list = []
After executing this block, there is a class SomeClass, with 3 class attributes: __init__, bar, and bar_list.
Then we'll create an instance:
instance = SomeClass()
When this happens, SomeClass's __init__ method is executed, receiving the new instance in its self parameter. This method creates two instance attributes: foo and foo_list. Then this instance is assigned into the instance variable, so it's bound to a thing with those two instance attributes: foo and foo_list.
But:
print instance.bar
gives:
I am a class attribute called bar
How did this happen? When we try to retrieve an attribute through the dot syntax, and the attribute doesn't exist, Python goes through a bunch of steps to try and fulfill your request anyway. The next thing it will try is to look at the class attributes of the class of your instance. In this case, it found an attribute bar in SomeClass, so it returned that.
That's also how method calls work by the way. When you call mylist.append(5), for example, mylist doesn't have an attribute named append. But the class of mylist does, and it's bound to a method object. That method object is returned by the mylist.append bit, and then the (5) bit calls the method with the argument 5.
The way this is useful is that all instances of SomeClass will have access to the same bar attribute. We could create a million instances, but we only need to store that one string in memory, because they can all find it.
But you have to be a bit careful. Have a look at the following operations:
sc1 = SomeClass()
sc1.foo_list.append(1)
sc1.bar_list.append(2)
sc2 = SomeClass()
sc2.foo_list.append(10)
sc2.bar_list.append(20)
print sc1.foo_list
print sc1.bar_list
print sc2.foo_list
print sc2.bar_list
What do you think this prints?
[1]
[2, 20]
[10]
[2, 20]
This is because each instance has its own copy of foo_list, so they were appended to separately. But all instances share access to the same bar_list. So when we did sc1.bar_list.append(2) it affected sc2, even though sc2 didn't exist yet! And likewise sc2.bar_list.append(20) affected the bar_list retrieved through sc1. This is often not what you want.
Advanced study follows. :)
To really grok Python, coming from traditional statically typed OO-languages like Java and C#, you have to learn to rethink classes a little bit.
In Java, a class isn't really a thing in its own right. When you write a class you're more declaring a bunch of things that all instances of that class have in common. At runtime, there's only instances (and static methods/variables, but those are really just global variables and functions in a namespace associated with a class, nothing to do with OO really). Classes are the way you write down in your source code what the instances will be like at runtime; they only "exist" in your source code, not in the running program.
In Python, a class is nothing special. It's an object just like anything else. So "class attributes" are in fact exactly the same thing as "instance attributes"; in reality there's just "attributes". The only reason for drawing a distinction is that we tend to use objects which are classes differently from objects which are not classes. The underlying machinery is all the same. This is why I say it would be a mistake to think of class attributes as static variables from other languages.
But the thing that really makes Python classes different from Java-style classes is that just like any other object each class is an instance of some class!
In Python, most classes are instances of a builtin class called type. It is this class that controls the common behaviour of classes, and makes all the OO stuff the way it does. The default OO way of having instances of classes that have their own attributes, and have common methods/attributes defined by their class, is just a protocol in Python. You can change most aspects of it if you want. If you've ever heard of using a metaclass, all that is is defining a class that is an instance of a different class than type.
The only really "special" thing about classes (aside from all the builtin machinery to make them work they way they do by default), is the class block syntax, to make it easier for you to create instances of type. This:
class Foo(BaseFoo):
def __init__(self, foo):
self.foo = foo
z = 28
is roughly equivalent to the following:
def __init__(self, foo):
self.foo = foo
classdict = {'__init__': __init__, 'z': 28 }
Foo = type('Foo', (BaseFoo,) classdict)
And it will arrange for all the contents of classdict to become attributes of the object that gets created.
So then it becomes almost trivial to see that you can access a class attribute by Class.attribute just as easily as i = Class(); i.attribute. Both i and Class are objects, and objects have attributes. This also makes it easy to understand how you can modify a class after it's been created; just assign its attributes the same way you would with any other object!
In fact, instances have no particular special relationship with the class used to create them. The way Python knows which class to search for attributes that aren't found in the instance is by the hidden __class__ attribute. Which you can read to find out what class this is an instance of, just as with any other attribute: c = some_instance.__class__. Now you have a variable c bound to a class, even though it probably doesn't have the same name as the class. You can use this to access class attributes, or even call it to create more instances of it (even though you don't know what class it is!).
And you can even assign to i.__class__ to change what class it is an instance of! If you do this, nothing in particular happens immediately. It's not earth-shattering. All that it means is that when you look up attributes that don't exist in the instance, Python will go look at the new contents of __class__. Since that includes most methods, and methods usually expect the instance they're operating on to be in certain states, this usually results in errors if you do it at random, and it's very confusing, but it can be done. If you're very careful, the thing you store in __class__ doesn't even have to be a class object; all Python's going to do with it is look up attributes under certain circumstances, so all you need is an object that has the right kind of attributes (some caveats aside where Python does get picky about things being classes or instances of a particular class).
That's probably enough for now. Hopefully (if you've even read this far) I haven't confused you too much. Python is neat when you learn how it works. :)
What you're calling an "instance" variable isn't actually an instance variable; it's a class variable. See the language reference about classes.
In your example, the a appears to be an instance variable because it is immutable. It's nature as a class variable can be seen in the case when you assign a mutable object:
>>> class Complex:
>>> a = []
>>>
>>> b = Complex()
>>> c = Complex()
>>>
>>> # What do they look like?
>>> b.a
[]
>>> c.a
[]
>>>
>>> # Change b...
>>> b.a.append('Hello')
>>> b.a
['Hello']
>>> # What does c look like?
>>> c.a
['Hello']
If you used self, then it would be a true instance variable, and thus each instance would have it's own unique a. An object's __init__ function is called when a new instance is created, and self is a reference to that instance.
I have a class with some attributes I want to use the methods. What is the most pythonic way to use it?. Is there documentation I can read about these styles issues?. I use pylint and pep8 to fix this kind of issues, but these program don't show any errors in this example with the attribute
class A(object):
BLOCK_SIZE = 8192
def func1(self):
print self.BLOCK_SIZE
def func2(self):
print A.BLOCK_SIZE
If I understand correctly this two case are the same, but I don't
know if is better to refer the class name or use the self reference.
Thanks
You should prefer self.
There are two types of fields - Class variables and Object variables.
Class variables are shared in the sense that they are accessed by all objects (instances) of that class. There is only copy of the class variable and when any one object makes a change to a class variable, the change is reflected in all the other instances as well.
Object variables are owned by each individual object/instance of the class. In this case, each object has its own copy of the field i.e. they are not shared and are not related in any way to the field by the same name in a different instance of the same class.
By using A.BLOCK_SIZE - you get class variable while by using self.BLOCK_SIZE you get an attribute of the specific object.
Check this to get a detailed example and explanations.
https://www.ibiblio.org/g2swap/byteofpython/read/class-and-object-vars.html
A class attribute can more or less be used as the default value for an instance attribute. The language allow a class attribute to be read either from the class itself or from any instance of the class, provided the instance has no attribute of same name.
But things go differently for write access: A.BLOCK_SIZE=16384 will change the global class attribute, while self.BLOCK_SIZE=16384 will create (or update) an instance attribute of same name.
Here is a little example with your class:
>>> a = A()
>>> a.func1() # access the class attribute
8192
>>> a.func2() # access the class attribute too
8192
>>> a.BLOCK_SIZE=4096 # create an instance attribute of same name
>>> a.func1() # access the INSTANCE attribute
4096
>>> a.func2() # still access the class attribute
8192
That's the reason why you should under common circonstances use the instance semantics (self.BLOCK_SIZE) because it does not rely on the class name and allows per instance override.
The class semantics A.BLOCK_SIZE should only be used if you want to change the class attribute, or need to use the class attribute even if an instance attribute exists.
I'm having headache trying to understand the cyclic relationship that exit between the metaclass type, the object class, and the class type.
I'm trying to understand how python makes everything an object.is it because everything is an instance of the metaclass type or is it because everything is a subclass of object class.
if its because of being subclass of object class, does that mean if the class object was named class pyobj. Would that mean that everything in Python starts with pyobj?
I know objects created by metaclass are types/classes, this types are then used to create other object.
From this:
>>> isinstance(type, object)
True
>>> isinstance(object,type)
True
>>> issubclass(object,type)
False
>>> issubclass(type,object)
True
Is it safe to say that python creates the class object first using the type metaclass (I'm simplifying the metaclass for brevity).
type('object',(),{})
which implies class object is a class of class type and it does not inherit any attributes other class.
Then it creates the class type:
type('type', (object,),{})
implying type class is class of class type and it inherits attributes from the object class.
Then creates the other classes by inheriting from the class object
type('dict', (object,), {})
type('Animal', (object), {})
which similar to creating an Animal class as :
class Animal:
pass
Does this mean the metaclass used to create the class object is still the one used to create this Animal class or is the metaclass type used by default ?
Which type is being used, is it the metaclass type or the type class that was created after object was created ?
Where does the class type created with the base class object come into play ?
I have also tried to understand what really is going on between the object and the class from all he responses above and in this article http://www.cafepy.com/article/python_types_and_objects/python_types_and_objects.html
I'm still getting confused. What is the relation between this two class in terms of object creation?
Will I ever get this or is it a chicken and egg situation?
Python's core types really do have a chicken and egg situation going on. type inherits from object, but object is an instance of type.
You can't really reason about which of object or type is defined first in Python, because in regular Python code you could not set up their relationship. The Python interpreter gets to do it by fiddling with the internals before the environment is set up, so it doesn't matter if the types are not completely defined up front.
In your example where you call type to create new object and type types, you're not actually getting objects that are equivalent to the real type and object, as your new object type is an instance of the builtin type metaclass, not the hand-made type metaclass you create later.
Here's an illustration of roughly how the interpreter goes about it. The code doesn't actually work, since you can't create a new-style class without inheriting from object, nor can you reassign a type object's __class__ attribute (to make object an instance of type). If you could, you could start up your own independent type system!
my_object = type('my_object', (), {}) # this doesn't work right, it inherits from object
my_type = type('my_type', (my_object,), {})
my_object.__class__ = my_type # this doesn't work at all (it will raise an exception)