associação pythonbrasil[11] django zope/plone planet Início Logado como (Entrar)

Diferenças para "IntroducaoOop"

Diferenças entre as versões de 10 e 11
Revisão 10e 2006-01-14 19:53:01
Tamanho: 20083
Editor: FabioCorrea
Comentário:
Revisão 11e 2006-01-14 20:11:32
Tamanho: 20406
Editor: FabioCorrea
Comentário:
Deleções são marcadas assim. Adições são marcadas assim.
Linha 78: Linha 78:

{{{original_string = ' some text '
{{{#!python
original_string = ' some text '
Linha 111: Linha 111:
{{{
{{{#!python
Linha 129: Linha 130:
Linha 142: Linha 144:
{{{
{{{#!python
Linha 158: Linha 161:
Linha 165: Linha 169:

{{{#!python
Linha 174: Linha 180:
}}}
Linha 180: Linha 187:

{{{#!python
Linha 204: Linha 213:
}}}
Linha 210: Linha 220:

{{{#!python
Linha 215: Linha 227:
}}}
Linha 226: Linha 239:

{{{#!python
Linha 238: Linha 253:
}}}
Linha 240: Linha 256:

{{{#!python
Linha 246: Linha 264:
}}}
Linha 261: Linha 280:

{{{#!python
Linha 266: Linha 287:
}}}
Linha 273: Linha 295:
{{{#!python
Linha 274: Linha 297:
}}}
Linha 281: Linha 305:
{{{#!python
Linha 282: Linha 307:
}}}
Linha 284: Linha 310:
{{{#!python
Linha 285: Linha 312:
}}}
Linha 301: Linha 329:
{{{#!python
Linha 303: Linha 332:
}}}
Linha 305: Linha 335:
{{{#!python
Linha 308: Linha 339:
}}}
Linha 315: Linha 347:
{{{#!python
Linha 316: Linha 349:
}}}
Linha 328: Linha 362:
{{{#!python
Linha 329: Linha 364:
}}}
Linha 364: Linha 401:

[[BR]]
Traduzido por '''FabioCorrea'''

Tradução do "Introduction to OOP with Python" do site www.voidspace.org.uk

Introdução

Eu tenho programado com Python por mais de 2 anos [1]. Antes, havia feito alguma programação procedural por cerca de 8 anos - mas eu não estava familiarizado com objetos ou OOP.

A filosofia usada no design da Python encoraja um estilo de programação limpo. Os seus tipos de dados básicos (datatypes) e o sistema de espaço de nomes (namespaces) facilitam a escrita de código elegante e modular [2].

Estes fatores, mais a peculiar regra de estruturação de bloco por indentação, tornam a Python uma linguagem ideal para iniciantes. Apesar disso, eu tive dificuldades em aprender sobre classes e objetos. Foi um grande obstáculo a ser vencido, assim como são todos os novos sistemas.

De fato os princípios básicos da programação orientada a objetos são relativamente fáceis de aprender. Assim como outros aspectos da Python, eles são bem concebidos e implementados. Este tutorial é uma introdução a programação orientada a objetos, que eu gostaria de ter tido quando precisei aprender tais princípios.

Este artigo assume um conhecimento básico da sintaxe da Python. Se você sabe como criar os tipos de dados básicos e chamar funções, mas quer saber mais sobre objetos e classes - então você achará esse artigo extremamente útil.

Objetos e OOP

Objetos e OOP estão no coração do modo como a Python funciona. Você não é forçado a usar o paradigma OOP em seus programas - mas entender os conceitos é essencial para se tornar algo mais que um iniciante. Mesmo porque, você precisará usar as classes e objetos fornecidos pela biblioteca padrão da linguagem.

OOP o Novo Paradigma

A programação de computadores é uma disciplina relativamente nova. Surpreendentemente, a programação orientada a objetos data da longínqua década de 60. Simula é considerada a primeira linguagem de programação orientada a objetos.

A OOP não é um paradigma incontroverso, de fato não é claro o que venha a ser uma definição exata de Programação Orientada a Objetos.

Some people think that OOP has nearly had it's day, and we need to find the Post OOP Paradigm. Algumas pessoas acham que a OOP já teve a sua chance, e nós já deveríamos procurar pelo paradigma pós-OOP.

Outros como Paul Graham acham que, em primeiro lugar, a OOP nunca foi necessária.

Então, o quê é um Objeto?

O quê é um Objeto? Bem, estamos falando de programação - portanto um objeto é um conceito. Chamar elementos de nossos programas de objetos é uma metáfora - um modo útil de pensar sobre eles.

Em Python os elementos básicos da programação são coisas como strings, dicionários, inteiros, funções, e assim por diante [3] ... Todos eles são objetos [4]. Isto significa que eles possuem certas coisas em comum.

Antes de olharmos mais de perto o que isto significa, nós iremos rapidamente cobrir alguns conceitos básicos de programação.

Programação Procedural

Se você já programou antes, você deve estar familiarizado com o estilo procedural de programação. Neste estilo, você divide o seu programa em 'pedaços' reutilizáveis chamados procedimentos (procedures) ou funções (functions) [5].

Sempre que possível você tenta manter o seu código nestes pedaços modulares - usando a lógica para decidir qual pedaço é chamado. Este estilo faz com que você não se esforce tanto ao visualizar o que o seu programa está fazendo. Ele também facilita a manutenção do seu código - você pode ver quais partes fazem o quê. Ao melhorar uma função (que é reutilizada) você pode, consequentemente, melhorar a performance em várias partes do seu programa.

Note

Para um visão interessante do desenvolvimento da programação procedural, leia uma mini história da programação

Separação de Dados

O estilo de programação procedural mantém uma estrita separação entre o seu código e seus dados.

Você tem variáveis, que contém os seus dados, e procedimentos. Você passa suas variáveis para os seus procedimentos - que ajem sobre elas e talvez até as modifiquem.

Se uma função quer modificar o conteúdo de uma variável ao passá-la para outra função, ela necessita acesso a ambas, variável e função chamanda. Se você realizar operações complexas isto pode compreender o uso de muitas variáveis e muitas funções.

Entra o Objeto

Elementos Básicos da OOP

Qualquer programador OOP experiente lhe dirá que os elementos essênciais da OOP são encapsulamento e passagem de mensagens.

Os equivalentes destes elementos na Python são namespaces e métodos.

A Python não adota o conceito de proteger (ocultar) o código do programador, [6] assim como a maioria das linguagens BSD. Ela encapsula os objetos em um namespace, mas através de um encapsulamento translúcido. :)

Isso leva a conclusão de que muitas operações são comuns a objetos do mesmo tipo. Por exemplo, a maioria das linguagens possuem modos nativos de criar uma versão somente em minúsculas (caixa baixa) de uma string.

There are lots of standard operations that are associated only with strings. These include making a lowercase version, making an uppercase version, splitting the string up, and so on. In an object oriented language we can build these in as properties of the string object. In Python we call these methods [7].

Existem várias operações padrão que estão associadas apenas a strings. Dentre elas, temos retornar uma versão em minúsculas, retornar uma versão em maiúsculas, particionar a string, e assim por diante. Em uma linguagem orientada a objetos nós podemos embutir essas operações como propriedades do objeto string. Em Python nós chamamos estas operações de métodos [7].

Todo objeto string possui um conjunto padrão de métodos - alguns dos quais você provavelmente já usou.

Por exemplo :

   1 original_string = ' some text '
   2 
   3 # remove espaços em branco no início e fim da string
   4 string1 = original_string.strip()
   5 
   6 # retorna uma versão em maiúsculas
   7 string2 = string1.upper()
   8 print string2
   9 SOME TEXT
  10 
  11 # retorna uma versão em minúsculas
  12 string2.lower() == string1
  13 True

A Python usa a sintaxe de ponto para acessar os atributos dos objetos. A instrução string2.lower() significa chamar o método lower do objeto string2. Este método retorna uma nova string - o resultado da chamada ao método.

Então toda string é atualmente um objeto string - e tem todos os métodos de um objeto string [8]. Na terminologia da Python nós dizemos que todas as strings são do tipo string.

No modelo de objetos as funções (métodos) e outros atributos que estão associados a um tipo particular de objeto, tornam-se parte do objeto. Os dados, e as funções que lidam com esses dados não estão mais separados - mas empacotados juntos no objeto.

Criando Novos Objetos

Let's look a bit more clearly at what's going on.

In Python there is a blueprint string object called the string type. It's actual name is str. It has all the methods and properties associated with the string.

Everytime a new string is created, the blueprint is used to create a new object with all the properties of the blueprint.

All the built in datatypes have their own 'blueprint' - the integer (int), the float (float), booleans (bool), lists (list), dictionaries (dict), and more.

For these built in datatypes, we can either use normal Python syntax to create them - or we can use the blueprint itself (the type).

   1 # create a dictionary the normal way
   2 a_dict = {
   3     'key' : 'value',
   4     'key2' : 'value2'
   5     }
   6 # use 'dict' to create one
   7 list_of_tuples = [('key', 'value'),
   8                  ('key2', 'value2')]
   9 a_dict_2 = dict(list_of_tuples)
  10 #
  11 print a_dict == a_dict_2
  12 True
  13 print type(a_dict)
  14 <type 'dict'>
  15 print type(a_dict_2)
  16 <type 'dict'>

See how we created a_dict_2 by passing a list of tuples to dict. All basic stuff, but it illustrates that new objects are created from blueprints. These objects have all the methods defined in the blueprint.

The new object is called an instance - and the process of creating it is called instantiation (meaning creating an instance). For the built in datatypes the blueprint is known as the type of the object. You can test the type of an object By using the built in function type [9].

That might seem like a lot to digest in one bite - but it probably doesn't involve anything you don't do already.

Python como uma Linguagem Orientada a Objeto

If you scour the internet you may find some unhelpful discussion as to whether Python is really object oriented or not. (For some value of object oriented). This debate is particularly beloved of Ruby programmers who like to claim thier language is more object oriented than Python.

This seems to come from the pre Python 2.2 days when there was a big difference between the built in types and user defined classes. Since 2.2 you can subclass the built in types. In Python 3.0 the unification will be complete.

We've already seen an example of using some string methods. We'll close off this section by using some dictionary methods.

   1 a_dict = {
   2     'key' : 'value',
   3     'key2' : 'value2'
   4     }
   5 a_dict_2 = a_dict.copy()
   6 print a_dict == a_dict_2
   7 True
   8 a_dict.clear()
   9 print a_dict
  10 {}
  11 print a_dict.clear
  12 <built-in method clear of dict object at 0x0012E540>
  13 print type(a_dict.clear)
  14 <type 'builtin_function_or_method'>

Above we used the clear method of a_dict by calling a_dict.clear(). When we printed clear, instead of calling it, we can see that it's just another object. It's a method object of the appropriate type.

Functions are Objects

Just to demonstrate that functions are objects, I'll show you a neat trick with them.

Have you ever written code that looks a bit like this ?

   1 if value == 'one':
   2     # do something
   3     function1()
   4 elif value == 'two':
   5     # do something else
   6     function2()
   7 elif value == 'three':
   8     # do something else
   9     function3()

Other languages have a construct called switch that makes writing code like that a bit easier.

In Python we can achieve the same thing (in less lines of code) using a dictionary of functions.

As an example, suppose we have three functions. You want to call one of the functions, depending on the value in a variable called choice.

   1 def function1():
   2     print 'You chose one.'
   3 def  function2():
   4     print 'You chose two.'
   5 def  function3():
   6     print 'You chose three.'
   7 #
   8 # switch is our dictionary of functions
   9 switch = {
  10     'one': function1,
  11     'two': function2,
  12     'three': function3,
  13     }
  14 #
  15 # choice can eithe be 'one', 'two', or 'three'
  16 choice = raw_input('Enter one, two, or three :')
  17 #
  18 # call one of the functions
  19 try:
  20     result = switch[choice]
  21 except KeyError:
  22     print 'I didn\'t understand your choice.'
  23 else:
  24     result()

The magic happens in the line result = switch[choice]. switch[choice] returns one of our function objects (or raises a KeyError). The we do result(), which calls it. Smile

Caution!

You could save a line or two of code by making the final block :

   1 # call one of the functions
   2 try:
   3     switch[choice]()
   4 except KeyError:
   5     print 'I didn\'t understand your choice.'

This directly calls the function returned by switch[choice]. However, if that function raises a KeyError (due to a bug) - it will get trapped by the try...except block. This error can be very hard to track down, because your error handling code is reporting the wrong error.

In general you should have your try...except blocks wrapping as little code as possible. User Defined Classes

The real trick is that we can create our own blueprints. These are called classes. We can define our own class of object - and from this create as many instances of this class as we want. All the instances will be different - depending on what data they are given when they are created. They will all have the methods (and other properties) from the blueprint - the class.

So lets look at a simple example. We define our own class using the class keyword.

Methods are defined like functions - using the def keyword. They are indented to show that they are inside the class.

   1 class OurClass(object):
   2     """Class docstring."""
   3 
   4     def __init__(self, arg1, arg2):
   5         """Method docstring."""
   6         self.arg1 = arg1
   7         self.arg2 = arg2
   8 
   9     def printargs(self):
  10         """Method docstring."""
  11         print self.arg1
  12         print self.arg2

I guess there are a few things that need explaining here. This will be easier if you see an example of it at work as well.

   1 instance = OurClass('arg1', 'arg2')
   2 print type(instance)
   3 <class 'OurClass'>
   4 instance.printargs()
   5 arg1
   6 arg2

In this example we create an instance of OurClass, and call it instance. When we create it, we pass in the arg1 and arg2 as arguments. When we call instance.printargs() these original arguments are printed. Mentioning Inheritance

The class definition starts with : class OurClass(object):

The class definition allows for something called inheritance. This means that your class can inherit properties from another class. I'm not going to explain this yet. Smile

All you need to know now is - if you're not inheriting from another class then you ought to inherit from object. Your class definitions should look like : class ClassName(object):

Old Style Classes

It has only been possible to inherit from object since Python 2.2. These are called new style classes. You might still see some old style class definitions floating around.

   1 class ClassName:
   2     """
   3     An old style class that
   4     isn't using inheritance.
   5     """

They still work - but they are deprecated and will probably stop working in Python 3. The init Method

The init method (init for initialise) is called when the object is instantiated. Instantiation is done by (effectively) calling the class.

From our example :

   1 instance = OurClass('arg1', 'arg2')

Here a new instance is created. Then it's init method is called and passed the arguments 'arg1' and 'arg2'.

To properly understand the init method you need to understand self. The self Parameter

The arguments accepted by the init method (known as the method signature) are :

   1 def __init__(self, arg1, arg2):

But we only actually pass it two arguments :

   1 instance = OurClass('arg1', 'arg2')

What's going on, where has the extra argument come from ?

When we access attributes of an object we do it by name (or by reference). Here instance is a reference to our new object. We access the printargs method of the instance object using instance.printargs.

In order to access object attributes from within the init method we need a reference to the object.

Whenever a method is called, a reference to the main object is passed as the first argument. By convention you always call this first argument to your methods self.

Is self a Wart ?

Some people regard it as a Python 'wart' that we have to include self. Java (?) includes it automatically and calls it this.

The main argument in favour of self is the Pythonic principle explicit is better than implicit [10]. This way we can see exactly where all our variable names come from.

This means in the init method we can do :

   1 self.arg1 = arg1
   2 self.arg2 = arg2

Here we are setting attributes on the object. You can verify this by doing the following :

   1 instance = OurClass('arg1', 'arg2')
   2 print instance.arg1
   3 arg1

values like this are known as object attributes. Here the init method sets the arg1 and arg2 attribute of the instance. printargs

We now know enough to understand what is happening in the printargs method.

This method doesn't take any arguments - so when we define it, we only need to specify the self parameter which is always passed to object methods.

   1 def printargs(self):

When this method is called it looks up (and prints) the original arguments which were saved as object attributes by init.

Hint

Let's get our terminology straight.

The 'functions' that are part of an object are called methods.

The values are called 'attributes'.

You can examine all the methods and attributes that are associated with an object using the dir command :

   1 print dir(some_obj)

The Power of Objects

As you can see objects combind data and the methods used to work with the data. This means it's possible to wrap complex processes - but present a simple interface to them. How these processes are done inside the object becomes a mere implementation detail. Anyone using the object only needs to know about the public methods and attributes. This is the real principle of encapsulation. Other parts of your application (or even other programmers) can use your classes and their public methods - but you can update the object without breaking the interface they use.

You can also pass around objects instead of just data. This is one of the most useful aspects of object oriented programming. Once you have a reference to the object you can access any of the attributes of the object. If you need to perform a complex group of operations as part of a program you could probably implement it with procedures and variables. You might either need to use several global variables for storing state (which are slower to access than local variables and not good if a module needs to be reusable within your application) - or your procedures might need to pass around a lot of variables.

If you implement a single class that has lots of attributes representing the state of your application, you only need to pass around a reference to that object. Any part of your code that has access to the object, can also access its attributes.

The main advantage of objects though is that it is a useful metaphor. It fits in with the way we think. In real life objects have certain properties and interact with each other. The more our programming language fits in with our way of thinking, the easier it is to use it to think creatively. Advanced Subjects

We've only covered the basics in this tutorial. Hopefully you now understand enough to create and use your own classes.

There is lots more still to learn. Some subjects I could expand this tutorial to cover include :

  • inheritance
  • class attributes
  • dict

  • subclassing built in types
  • new

  • getattr and setattr

  • private attributes (single and double underscore)
  • classmethods and staticmethods

Footnotes

[1]

It was two years in June 2005.... I started learning Python for a project called atlantibots.

[2]

It's system of modules and packages as well - these are related to namespaces, and are the envy of other languages.

[3]

These are called the basic datatypes - plus lots more things like classes, instances, and methods that we'll meet soon in this introduction.

[4]

Like smalltalk - which is sometimes spoken of as the archetypal object oriented language.

[5]

The technical difference used to be that a function returns a value but a procedure doesn't. Nowadays they tend to all get called functions. We don't call it functional programming though, that's something else altogether. Very Happy

[6]

Or is that to protect the programmer from the code ?

[7]

The 'old' object oriented name for this is 'message passing'. These days it's not a helpful metaphor.

[8]

You can see a list of string methods at string methods.

[9]

Actually type isn't a function - it's a type. It is the type of types (type(type) is type). Very Happy We can use it as a function though.

[10]

Try import this at an interactive interpreter prompt. This is called the Zen of Python.

BR Traduzido por FabioCorrea