Design of python--class

Source: Internet
Author: User

Design of the class

The design of the Python oop is discussed here, that is, how to use classes to model useful objects. The commonly used OOP design patterns in Python, such as inheritance, composition, delegation, and factory, will be written. It also introduces some concepts of class design, such as pseudo-private property, multi-inheritance, etc.

================================================================================

Python and OOP

Python's OOP implementations are similar to Java, and can be summarized as three concepts:

1. "Inheritance" inheritance is based on property lookups in Python (in x.name expressions)
2. "Polymorphic" in the X.method method, the meaning of methods depends on the type of X
3. "Encapsulation" method and operator implementation behavior, data hiding by default is a convention

================================================================================

OOP and Inheritance: "is a" relationship


For example: The pizzeria team can be defined by four classes in the file employees.py. The most common class employee provides common behavior, for example, raise (Giveraise) and print (__repr__). There are two types of employees, so employee has two subcategories: Chef and Server (chef and waiter). These two subclasses will overwrite the inherited work method to print more specific information. Finally, pizza bots are modeled by more specific classes: Pizzarobot is a chef and an employee. In OOP terms, these relationships are "a" (is-a) Link: The robot is a chef, and the chef is an employee. The code is written as follows:

#File employees.pyclass employee:def __init__ (self,name,salary = 0): Self.name = name self.salary = Sala Ry def giveraise (self,percent): Self.salary = self.salary + (Self.salary * percent) def work (self): PR Int (self.name, ' does stuff ') def __repr__ (self): return ' <employee:name =%s, salary =%s> '% (self.name,s        Elf.salary) class Chef (Employee): def __init__ (self,name): employee.__init__ (self,name,50000) def work (self): Print (Self.name, "Makes food") class Server (Employee): def __init__ (self,name): employee.__init__ (self,name , 40000) def work (self): print (Self.name, "interfaces with Customer") class Pizzarobot (Chef): Def __init__ (self,    Name): chef.__init__ (Self,name) def work (self): print (Self.name, ' makes pizza ') if __name__ = = ' __main__ ': Bob = Pizzarobot (' Bob ') print (Bob) bob.work () Bob.giveraise (. 2) print (Bob) print () for Klass in Emplo Yee,chef,server,pizzarobOt:obj = Klass (klass.__name__) obj.work () 
The results of the operation are as follows:

<employee:name = bob, salary = 50000>bob makes pizza<employee:name = bob, salary = 60000.0>employee does Stuffchef makes Foodserver interfaces with Customerpizzarobot makes pizza
As you can see, Bob is a pizzarobot, but when printing, still show is employee, from the results can not see what kind of staff he specifically belongs to, this time you may modify the __repr__ method in the employee class is as follows:

def __repr__ (self):        return ' <%s:name =%s, salary =%s> '% (self.__class__.__name__,self.name,self.salary)
Where, self.__class__.__name__, you can return the name of the class to which the instance belongs, and then execute the result as follows:
<pizzarobot:name = bob, salary = 50000>bob makes pizza<pizzarobot:name = bob, salary = 60000.0>employee Does Stuffchef makes Foodserver interfaces with Customerpizzarobot makes pizza
================================================================================

OOP and combination: "Have a" relationship

The combination involves embedding other objects inside the container object and using its container method. A combination reflects the relationship between the components, often referred to as a "one" (has-a) relationship.
Then the above example, since we already have employees, we put them in our pizza shop. The pizzeria is a combo object, with an oven and staff of waiters and chefs. When a customer comes to the store to place a order, the components in the store start to act: the waiter orders, the chef makes the pizza, and so on. Look at the example below pizzashop.py.

#File pizzashop.pyfrom Employees Import Pizzarobot,serverclass Customer:    def __init__ (self,name):        self.name = Name    def order (self,server):        print (Self.name, ' orders from ', server)    def pay (self,server):        print ( Self.name, ' pays for item to ', server) class Oven:    def Bake (self):        print (' Oven bakes ') class Pizzashop:    def __ Init__ (self):        self.server = Server (' Pat ') #组合其他对象        self.chef = Pizzarobot (' Bob ') #一个名叫Bob的机器人主厨        Self.oven = oven ()    def Order (self,name):        customer = Customer (name)        Customer.order (self.server)        Self.chef.work ()        self.oven.bake ()        Customer.pay (self.server) if __name__ = = ' __main__ ':    scene = Pizzashop ()    scene.order (' Homer ') #模拟Homer的订单    print (' ... ')    scene.order (' shaggy ') #模拟Shaggy的订单
Here, Pizzashop is the container and controller of the class. When this module was executed, our pizza shop processed two orders: one from Hommer and the other from Shaggy.
Homer orders from <server:name = Pat, salary = 40000>bob makes Pizzaoven bakeshomer pays for item to <server: Name = Pat, salary = 40000> ....  Shaggy orders from <server:name = Pat, salary = 40000>bob makes Pizzaoven bakesshaggy pays for item to <server : name = Pat, salary = 40000>
================================================================================
OOP and Delegates: Wrapper object

The so-called "delegate", usually refers to the controller object embedded in other objects, and the operation of the request to those objects.
In Python, a delegate is usually implemented with the __getattr__ hook method, because this method intercepts the read of a nonexistent property, and the wrapper class can use __getattr__ to forward any read to the wrapped object. The wrapper class package has the interface of the wrapped object, and it can add other operations.

For example, consider the following example:
>>> class Wrapper:def __init__ (self,object): self.wrapped = Objectdef __getattr__ (self,attrname):p rint (' Trace: ', attrname) return GetAttr (Self.wrapped,attrname)
__getattr__ Gets the property name string. This program uses the GetAttr built-in function to take the property out of the wrapped object with a variable name string: GetAttr (x,n) is like X.N, except that N is an expression that calculates a string at run time, not a variable. In fact, GetAttr (X,n) is similar to X.__dict__[n].

You can use this module to wrap classes and manage access to any object with attributes: Lists, dictionaries, and even classes and instances. Here, the wrapper class simply prints the trace message when each property is read and delegates the property request to the embedded object wrapped
>>> x = Wrapper ([2]) >>> X.append (4) trace:append>>> x.wrapped[1,, 3, 4]>>> >>> x = wrapper ({' A ': 1, ' B ': 2}) >>> X.keys () Trace:keysdict_keys ([' B ', ' a '])
The actual effect is to enhance the entire interface of the wrapped object with additional code in the wrapper class. We can use this approach to record method calls, transfer method calls to other or custom logic, and so on.
================================================================================
Pseudo-private property of class--variable name compression

Python supports the concept of variable name compression, allowing some variables within a class to be localized, but name compression does not prevent the class from being read by external code, primarily to avoid namespace collisions within instances, rather than restricting the reading of variable names. Therefore, a compressed variable name is best known as a "pseudo-private".

Of course, pseudo-private properties are advanced and completely optional, but because you might see this feature in other people's code, you have to pay attention even if you don't.

"Variable name compression works like this: There are two underscores at the beginning of a class statement, but no two underlined variable names at the end, which automatically expands to include the name of the class in which it is located. 】
For example, a variable name such as __x in the Spam class automatically becomes _spam__x: The original variable name is underlined in the header, and then the name of the class in which it is located. Because the modified variable name contains the name of the class in which it is located, it is equivalent to becoming unique. Does not conflict with similar variable names created by other classes in the same hierarchy.

Variable name compression occurs only within a class statement, and only for variable names with two underscores at the beginning.

Why use pseudo-private attributes, for example:
A programmer writes a class that he thinks attribute X is in this instance:

Class C1:def meth1 (self): self. X = 88def meth2 (self):p the rint (self). X
Another programmer works independently and writes such a class, and he has the same assumptions:
Class C2:def Metha (self): self. X = 99def METHB (self):p the rint (self). X
If these two classes are mixed in the same class tree, the problem arises:
Class C3 (C1,C2): ... I = C3 ()
Because the variable names in C1 and C2 are X, there can only be one x in I, depending on which class the last assignment is, so that one of the data is discarded for no reason.

To ensure that a property belongs to a class that uses it, you can use it anywhere in the class and precede the variable name with two underscores:
>>> class C1:def meth1 (self): self.__x = 88def meth2 (self):p rint (self.__x) >>> class C2:def Metha (self) : self.__x = 99def METHB (self):p rint (self.__x) >>> class C3 (C1,C2):p ass>>> I = C3 () >>> i.meth1 (); I.metha () >>> print (i.__dict__) {' _c1__x ': +, ' _c2__x ': 99}
As a result, the X property expands to include the name of its class before it is added to the instance. View its namespace dictionary to see the variables become _c1__x and _c2__x.

But this is not really private, you can still use the expanded variable name, for example, i._c1__x = 77
================================================================================

Multiple inheritance: "Hybrid" class

In the class statement, more than one superclass can be listed in the first line of parentheses. When you do this, you are using the so-called "multiple Inheritance".

When searching for properties, Python searches from left to right for the superclass in the first row until the match is found.

In general, multiple inheritance is a good way to model objects that belong to more than one collection. For example, a person can be an engineer, a writer, a musician, and so on, so that the attributes of these collections can be inherited.

================================================================================

Class is the object: The factory of the generic object

>>> def factory (Aclass,*args): Return AClass (*args) >>> class Spam:def doit (self,message):p rint ( Message) >>> class Person:def __init__ (self,name,job): Self.name = Nameself.job = job>>> Obj1 = Factory ( Spam) >>> obj2 = Factory (person, ' Guido ', ' Gurr ')
In this code, we define an object generator function called Factory. It expects the class object to be passed in, and one or more parameters of the class constructor.
Then two classes are defined and passed to the factory function to produce an instance of both. This is what you need to do to write factory functions in Python. It applies to any class and any constructor arguments.

Such factories can isolate the construction details of code and dynamic configuration objects, perhaps in the future.

Design of python--class

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.